Imagine your Power intake to your rack has failed, imagine your UPS has kicked in but is about to run out of power, you need to quickly shut down all of your virtual infrastructure…. quick run !

Or, you could let PowerCLI do the work for you and help you safely shutdown your entire virtual infrastructure, you could even tell your UPS software that when it gets to a certain amount of battery life left that it needs to run this script to safely shut things down.

When I first wrote this script it didn’t work quite as expected, we can easily tell all our guests to shut down nicely through the guest shutdown feature but as I found, this doesn’t always work, for example, what happens if one of your machines is sat there on the following screen:

image

If that happens then the guests never actually shut down and we are left in limbo waiting for the guests to “safely” be shut down, As you will see from the below script, I have added not only a check to see if the VMs are powered off but also a fail safe time where it just goes for it and shuts down the hosts anyway.

Connect-VIServer MyVIServer

# Get All the ESX Hosts
$ESXSRV = Get-VMHost

# For each of the VMs on the ESX hosts
Foreach ($VM in ($ESXSRV | Get-VM)){
    # Shutdown the guest cleanly
    $VM | Shutdown-VMGuest -Confirm:$false
}

# Set the amount of time to wait before assuming the remaining powered on guests are stuck
$waittime = 200 #Seconds

$Time = (Get-Date).TimeofDay
do {
    # Wait for the VMs to be Shutdown cleanly
    sleep 1.0
    $timeleft = $waittime - ($Newtime.seconds)
    $numvms = ($ESXSRV | Get-VM | Where { $_.PowerState -eq "poweredOn" }).Count
    Write "Waiting for shutdown of $numvms VMs or until $timeleft seconds"
    $Newtime = (Get-Date).TimeofDay - $Time
    } until ((@($ESXSRV | Get-VM | Where { $_.PowerState -eq "poweredOn" }).Count) -eq 0 -or ($Newtime).Seconds -ge $waittime)

# Shutdown the ESX Hosts
$ESXSRV | Foreach {Get-View $_.ID} | Foreach {$_.ShutdownHost_Task($TRUE)}

Write-Host "Shutdown Complete"

This can be changed to only shutdown all vms and hosts in a certain datacenter of cluster by amending line 04 to the following:

For a specific datacenter, mine is called DC1…

$ESXSRV = Get-DataCenter “DC1” | Get-VMHost

For a specific cluster, mine is called Production…

$ESXSRV = Get-Cluster “Production” | Get-VMHost

I’m sure I don’t need to tell you that you need to be extremely careful when testing this script as one false move could shut down everything ! – Please test this to make sure it works first !

* Just to mention, this will obviously not work if your virtual center is a VM, for that you will need to do some funky connecting to each host etc, let me know if you desperately need that.