UPDATE – I’ve had the unfortunate chance of testing this script a few times and have found that its not as efficient as it could be.   If I were you I would check out my updated post Practise makes perfect! More PowerCLI APC Powerchute Network Shutdown Goodness (Now with Power On!) as it completes much faster and has a function to turn the VMs back on once power is restored.  Thanks!

A few months ago, in order to prepare for the release of ESXi and vSphere 5 I went through the motions of migrating all of our ESX hosts to ESXi. I thought I had all my ducks in a row concerning all of our third party solutions that connect to our environment (Veeam, VCops, etc) but one that completely slipped my mind was our APC and vGhetto shutdown scripts that were running inside our vMA. Since our then current solution relied on the ability to ssh into the hosts and ESXi by default doesn’t have an ssh server running, the scripts proved to be somewhat, how shall I say this….useless (and yes, I found out the hard way!!). When looking for alternatives I first went to APC and was delighted to see that they finally had a version of their powerchute network shutdown available for the vMA appliance. What I found out though was that it basically peeled through your list of servers that you have connected to the vMA and shut them down accordingly, which in my case is not the answer. I have multiple ESX(i) instances connected to the vMA which reside in many different locations, so if the power failed at our main datacentre, essentially our vMA would receive the shutdown command and initiate a shutdown sequence on ESX hosts in an offsite location. So, back to the drawing board as that was definitely not the answer. I liked the way that lam??? Ghetto scripts worked originally being that you could specify which hosts and even which vMA to shut down So i decided to recreate, or at least get close too that same functionality in powershell. Below is what I came up with, and the script is very much in its infancy so if you can see some spots for improvement please let me know! Also, I don’t claim to be a powershell expert in any sort of sense so definitely don’t take this directly not production, test it in a lab first or even in comment the shutdown lines and have a look at the output. I placed the script on a windows box outside of our virtual infrastructure, so essentially the physical machine receives the shutdown command, but before shutting itself down it runs the powershell script to gracefully shutdown the virtual infrastructure (vms and hosts) first.

Anyways, here it is and if you have any suggestions , comments or questions don’t hesitate to ask. We can muddle through this together 🙂

#################################################################################
# Shutdown VMs and Hosts
#
# This script will loop through a list of ESXi hosts and initiate shutdown
# commands to the vm’s residing on them. If VMware Tools is installed, the
# script will attempt to do a graceful shutdown. If VMware tools is not
# installed a hard power off will be issued. One note, if you have any VMs that
# you would like to remain on until the end of the process be sure to put their
# names in the $vmstoleaveon variable and also be sure they reside on the last
# host listed in the $hoststoprocess variable.
#
# i.e If I wanted to have VM1 and VM2 stay on till the end I would have to be
# sure that they reside on esxi-03 and my variables would be setup as follows
#
# $vmstoleaveon = “VM1 VM2”
# $listofhosts = “esxi-01 esxi-02 esxi-03”
#
# Created By: Mike Preston, 2011
# Updates: MWP – March 2012 – how not looks to see if any VMs are still on after
#                doing initial shutdown, then runs a hard stop, and enters
#                maintenance mode before shutting down.

 

#
#################################################################################
# list of hosts to process
$listofhosts = “esxi-01”, “esxi-02”, “esxi-03”
#list of vm’s to ‘go down with the ship’ – vms must reside on last host in above list.
$vmstoleave = “VM1”, “VM2”
#loop through each host
Foreach ($esxhost in $listofhosts)
{
$currentesxhost = get-vmhost $esxhost
Write-Host “Processing $currentesxhost”
#loop through each vm on host
Foreach ($VM in ($currentesxhost | Get-VM | where { $_.PowerState -eq “PoweredOn” }))
{
Write-Host “====================================================================”
Write-Host “Processing $vm”
# if this is a vm that is supposed to go down with the ship.
if ($vmstoleave -contains $vm)
{
Write-Host “I am $vm – I will go down with the ship”
}
else
{
Write-Host “Checking VMware Tools….”
$vminfo = get-view -Id $vm.ID
# If we have VMware tools installed
if ($vminfo.config.Tools.ToolsVersion -eq 0)
{
Write-Host “$vm doesn’t have vmware tools installed, hard power this one”
# Hard Power Off
Stop-VM $vm -confirm:$false
}
else
{
write-host “I will attempt to shutdown $vm”
# Power off gracefully
$vmshutdown = $vm | shutdown-VMGuest -Confirm:$false
}
}
Write-Host “====================================================================”
}
    Write-Host “Initiating host shutdown in 40 seconds”
    sleep 40
    #look for other vm’s still powered on.
    Foreach ($VM in ($currentesxhost | Get-VM | where { $_.PowerState -eq “PoweredOn” }))
    {
        Write-Host “====================================================================”
        Write-Host “Processing $vm”
        Stop-VM $vm -confirm:$false
        Write-Host “====================================================================”
    }
    #Shut down the host
    Sleep 20
    Set-VMhost -VMhost $currentesxHost -State Maintenance
    Sleep 15
    $currentesxhost | Foreach {Get-View $_.ID} | Foreach {$_.ShutdownHost_Task($TRUE)}
}
Write-Host “Shutdown Complete”