Use PowerCli to shutdown VM’s and Hosts when running on battery.

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”

 

  • Ian Blackwood

    Hi mwpreston !
    This is the best script I have found to perform this (one would think) very common requirement.
    In my case I will be having a local WinXP VMGuest shutdown the ESXi 4.1 Host it is running on. Whilst we have a VCS that is in our Data Centre – not out on the sites – so if the power goes off I have to assume it is likely the comms links will be affected as well…
    Whilst I happy with batch and bash scripts, the Powershell / powercli is all new to me so forgive my ignorance….
    So I have questions:
    1. What happens if a guest hangs on shutdown (e.g. stays at Windows power off screen). Some scripts do a second run through and force off these machines (whether this is required is a different matter).
    2. Is your method of triggering the Host shutdown the equivalent of using the -force parameter ?
    3. How are you making the PowerCLI connections to the vcs/hosts  ? I am trying to figure out a way to connect without having credentials in clear text in a file.
    Hope to hear from you soon but I'll keep digging in the meantime….
     
    Thanks
    Ian
     
     

    • mwpreston

      Hi Ian, great questions and I’ve updated the script to facilitate some of the items that you pointed out.

      I’m running under an account that has administrative priveledges on the vCenter Server, also, the connections are going through the vCenter Server as well…

  • Thomas Dietrich

    Thanks for the script.  This provides a complete solution for shutting down / suspending VM’s, putting hosts in maintenence mode, and then shutting down the hosts.  Very much appreciated!  I especially like the ability to bypass certain VM’s and leave them running until the end.I’ve made some modifications to allow the user to enter the parameter for the vCenter server as part of calling the script, or for the script to prompt the user for the name of the vCenter to which the script should establish a connection, and then to actually establish that connection.My only problem is with the function of putting the host in maintenence mode.  When done through the GUI it prompts whether to vMotion suspended and powered off VM’s to another host.  Since this script is intended to shut down the infrastructure I don’t want to vMotion any of my VMs when I enter maintenence mode.  Is there an argument that can be included in the command “Set-VMhost -VMhost $currentesxHost -State Maintenance” to prevent any of the VM’s from being vMotioned?

    I might play with the ability to have the script query the names of the hosts and then shut them down without having to include the host names in the script itself, or potentially allow for user input of host names.

    Thanks!

    • mwpreston

      Hi Thomas, thanks for the comment.
      Yes, I had the ability to bypass certain VMs just incase this script was actually running a VM itself, or if vCenter was virtualized. I had put the hosts in maintenance mode due to the fact that when I was doing some production level testing with this I found that HA was responding sometimes if VMs were not quite registered as being powered off. This led to VMs being restarted again on remaining hosts, then the script would move to the next host and do the same thing until either admission control went crazy or until everything was almost running on one host. Feel free to modify at will, if you get any great ideas post them back and we can update it. Thanks again

  • Pingback: How to use a CyberPower UPS solution for proper automated shutdown of your VMware ESXi lab during power outages, including all VMs | Tinkertry