PowerCLI: Shutdown your Virtual Infrastructure
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:
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.
Welcome to 2010 vSphere Quick Start Guide – PowerCLI and PDF











Great post! I’m amazed at how little this topic is addressed in posts and articles.
Improvements could come in a few forms.
1. It would be nice if there were a way to dry-run test it, so that you could do some validating without it kicking in.
2. In reality, there is a general order in which one would want vm’s to gracefully shut down. It’s no fun if your DC’s shut down first.
As for your comment about vcenter not being a VM in order for this to work, I think there is another way. One would have their cluster of ESX hosts. Then, you have a cheap old PC with a few extra NIC’s, with ESXi built up, connected to the SAN as well, but only running one VM; the server running vcenter. That way you have the flexibility of it being a VM on the SAN, but living outside the cluster.
Social comments and analytics for this post…
This post was mentioned on Twitter by alanrenouf: New blog post: PowerCLI: Shutdown your Virtual Infrastructure http://bit.ly/7a8FBa...
[...] PowerCLI: Shutdown your Virtual Infrastructure via Virtu-Al by Virtu-Al on 1/6/10 [...]
Nice script….I’m looking for a similar script to shutdown guest based on priority. I have a custom field called Priority attached to each guest with value 1,2 or 3. I would like to shutdown guest with low value 3 first followed by value 2 and last value 1
Cheers,
vishy
@vishy
Good Idea, I didnt think of using custom fields like that, mind if I write the script as a follow up post ?
Alan
Hi Alan,
That will be great, I’ll look forward for an update script.
Thanks and Regards,
Vishy
Hi,
I have been looking for something like this for a while, However I do not have vcentre and connect to my ESXi hosts directly. Unfortunately I have no PowerCLI experience. Can anyone offer any help as to how I would change this to talk to the ESXi hosts directly and not to Vcentre.
Many Thanks
Chris
Have a look at my article for free ESXi at http://www.techhead.co.uk/how-to-automatically-shut-down-vmware-esxi-gracefully-during-power-failure-using-an-apc-ups
Very cool post, I like it alot
[...] Update (08/04/2010): I have found the above vMA to be quite fiddly. And have had much better luck with the PowerCLI code found on this page : http://www.virtu-al.net/2010/01/06/powercli-shutdown-your-virtual-infrastructure/ [...]
Very cool! Only problem I came across is that we have lots of VM’s that are already shutdown or suspended. We also wanted to make the script suspend the VM’s instead of shutting them off. Pretty easy to implement both those changes:
# For each of the VMs on the ESX hosts
Foreach ($VM in ($ESXSRV | Get-VM | Where { $_.PowerState -eq “poweredOn” } )){
# Suspend the guests cleanly
$VM | Suspend-VM -Confirm:$false
In response #2 it was discused to have a priority setting of some kind to have some VM’s shutdown before others. How would one do this, we want to make sure out DC’s go down last.
I have tested your script and it works great other then this one item, thanks.
Jesse
Hello.
I am new to the vmware and powershell. I have just a small family server which is still very important for me. I am using Vmware esxi. It is now set so that when I manually shutdown the host, it waits till guests get shutdown. The order which system is starting first and shutting last is set in configuratin. As I understand the script, it shutdowns the guests first. Is there any possibility just to tell esxi to shutdown so that it uses it’s own configuration? It must be set from Windows machine and it needs to be set a reaction on some event. Scheduled task is running and when some conditions will occure I need the task to send shutdown. Is it even possible?
Thank you
Jan
Great script! There is indeed not that much information on automated full environment shutdowns out there. Has one of the priority-based scripts already found its way to the public somewhere?
Before using this script one might want to double-check for VMs with a missing VMware Tools installation. Just had a customer with mostly Linux VMs where many VMs simply didn’t have the Tools installed and thus the graceful guest shutdown wouldn’t work. Either use vCheck or something like following snippet:
$VMS_WITHOUT_TOOLS = ( get-view -viewtype virtualmachine `
-filter @{ “Guest.ToolsStatus” = “toolsNotInstalled”; “Runtime.PowerState” = “poweredOn” } `
-property Name )
if ($VMS_WITHOUT_TOOLS) {
write-host “These VMs are missing VMware Tools, Shutdown-VMGuest won’t work for them”
$TOOLS_MISSING_ON | %{ write-host “-” $_.Name }
}
Sebastian
P.S.: Perl SDK users might want to check out William’s ghettoUPSHostShutdown.pl too: http://communities.vmware.com/docs/DOC-11902
Have you had time/opportunity to figure out how this script could be adjusted to even partially work when the vCenter server is a VM??
That is, perhaps one can/should set this up to work only with the hosts that do not contain the vCenter Server, and let the UPS etc. manage the host containing vCenter Server?? It could be assumed the SAN will simply power on…
Or set things to shut down all VMs but vCenter and then go from there etc.??
I am new to PowerShell and HA so I cannot yet offer much in this regard…I know most of us VMware admins stand on the shoulders of giants like you.
Thank you, Tom
Hello,
my answer to how to shutdown all VM’s expect vCenter or DC’s – create folder for all DC’s Machines, vCenter and rest
and then first shutdown all machines “rest”
first:
Get-Folder -Name “rest” | Get-VM | Shutdown-VMGuest –Confirm:$false
when script confirms all i shutdown then
second:
Get-Folder -Name “DC’s” | Get-VM | Shutdown-VMGuest –Confirm:$false
and last
Get-Folder -Name “vcenter” | Get-VM | Shutdown-VMGuest –Confirm:$false
or if you want to shutdown all esx as well do not shutdown vcenter, – use powercli to shutdown all esx’s and set in esx’s poweroff option to shutdown all machines….
I am looking for a way to implement shutting down ESXi hosts using a VMA. I have tried ghetto shutdown script but it waits for each guest to shutdown before continuing to the next. Has anyone found a better solution for VMA and ESXi (paid)?
thanks
Thanks! Very handy script!
[...] PowerCLI: Shutdown your Virtual Infrastructure | Virtu-Al might have the answer you're looking for. Reply With Quote [...]
[...] Yesterday I decided to look into how to put formatted
code into my blogs. I had gone to this blog the other day and
noticed how the PowerShell code blocks were nicely formatted and it
got me to [...]
[...] quick search on a site that is becoming a favorite of mine found me a solution that I could run in powercli. Alan Renouf created this script. After the outage, I took another [...]
[...] quick search on a site that is becoming a favorite of
mine found me a solution that I could run in powercli. Alan Renouf
created this script. After the outage, I took another
[...]
[...] The following script is straight from http://www.virtu-al.net/2010/01/06/powercli-shutdown-your-virtual-infrastructure/ [...]
Looking for help on a script that will check all vms on a host and if only one VM is remaining running and that VM has a specific name, then that VM is shut down so that the DPM will suspend the host. Any ideas?
Thanks!
Yes this is achievable by powerCLI
i can run this script with double click the script file.but when i register it to taskschd.msc,it failed to get-vm:
the return value of get-vm is empty !although the get-vmhost work perfectly.
i register the script to taskschd.msc with checking “run whether user is logged on or not “.
could tell why the return value of get-vm is empty ?thank you.
try adding the following code to the top – it may be that you do not have the cmdlets loaded as part of the session:
if (!(get-pssnapin -name VMware.VimAutomation.Core -erroraction silentlycontinue)) { add-pssnapin VMware.VimAutomation.Core }Thanks for the script, it’s just what I was looking for.
Hi.
I’m looking at shutting down a ESXi host with running guests.
The guests should get automaticaly shutdown by the host if configured correctly.
So just need to shutdown the host cleanly.
Also need to shut down another FreeNAS box, but that’s another story.
Been playing with a few scripts, then saw one in the vSphere PowerCLI Administration Guide on pg 14:
Downloadable from here http://www.vmware.com/support/developer/PowerCLI/PowerCLI41U1/html/index.html
5 Shut down the myHost virtual machine host
$host = Get-VMHost myHost
$hv = Get-View $h.ID
$hv.ShutdownHost_Task($true)
Any one got any idea what the $h is?
Also when I run the first line in PowerGUI Script Editor I get:
Cannot overwrite variable Host because it is read-only or constant.
At C:\Users\user\AppData\Local\Temp\7aad3dc5-990e-4568-a06b-987092d00575.ps1:5 char:6
+ $host <<<< = Get-VMHost $vSphereServername
+ CategoryInfo : WriteError: (Host:String) [], SessionStateUnauthorizedAccessException
+ FullyQualifiedErrorId : VariableNotWritable
Then for the second line I get:
Get-View : Cannot validate argument on parameter 'VIObject'. The argument is null or empty. Supply an argument that is not null or empty and then try the
command again.
At C:\Users\user\AppData\Local\Temp\7aad3dc5-990e-4568-a06b-987092d00575.ps1:6 char:15
+ $hv = Get-View <<<< $h.ID
I've already established connection to the host by way of Connect-VIServer.
Anyone got any ideas?
@Virtu-Al
thank you for your advice.i added the flowing code to my script
if (!(get-pssnapin -name VMware.VimAutomation.Core -erroraction silentlycontinue)) {
Write-Host “add-pssnapin …”
add-pssnapin VMware.VimAutomation.Core
}else{
Write-Host “already exist.no need to add”
}
it shows “already exist.no need to add”.and no output from get-vm cmdlet.
Yeah, you shouldnt use $host as a variable as this is a reserved variable, type $host in PowerShell and you will get information about the current powershell session, I would change the $host in your script to $h as you are then calling $h on the next line.
I’m not using $host as a variable.
The PowerCLI admin manual on pg 14 is.
As shown above.
So obviously it’s another VMware error?
Also be aware that any shutdown will not work on ESXi.
As They have disabled write access to the host.
So I’m in the process of writing a shutdown application to get around this new limitation and will be posting on my blog when done if anyone interested.
This is how I got around the VCenter as a VM problem:
Start-Transcript -Path C:\CSS_Log.txt -Append
Add-PSSnapin VMware.VimAutomation.Core
Set-PowerCLIConfiguration -DefaultVIServerMode multiple -Confirm:$False
Connect-VIServer HOSTA,HOSTB,HOSTC -User ‘USER’ -Password ‘PASSWORD’
Get-VMHost | Get-VMHostStartPolicy | Set-VMHostStartPolicy -Enabled:$True -WaitForHeartBeat:$True
Get-VM | Get-VMStartPolicy | Set-VMStartPolicy -StartAction PowerOn -UnspecifiedStartOrder
Get-VM -Name SVR-SQL01 | Get-VMStartPolicy | Set-VMStartPolicy -StartAction PowerOn -StartOrder 3
Get-VM -Name SVR-VC01 | Get-VMStartPolicy | Set-VMStartPolicy -StartAction PowerOn -StartOrder 2
Get-VM -Name SVR-DC01 | Get-VMStartPolicy | Set-VMStartPolicy -StartAction PowerOn -StartOrder 1
Get-VM | Shutdown-VMGuest -Confirm:$False
DO {Get-VM | Get-VMGuest} WHILE (Get-VM | Get-VMGuest | where {$_.State -eq “Running”})
Get-VM | Stop-VM -Confirm:$False
DO {Get-VM} WHILE (Get-VM | where {$_.PowerState -eq “PoweredOn”})
Get-VMHost | Stop-VMHost -Force -Confirm:$False
Stop-Transcript
I’m going round in circles with this script. I just want to stop all VM’s in a RP and not get a warning if they are already powered off. Any help much appreciated.
# Stop all VM’s in a RP
do
{
# Get the name of the Resource Pool
$ResourcePool = read-host ” Insert the Name of the Resource Pool to Stop”
# Get the members of that RP
$VMName = (get-resourcepool $ResourcePool | get-vm)
# For each of the VMs in the RP
{
Foreach ($VMName in ($ResourcePool | get-vm | Where-object {$_.PowerState -eq “poweredOn” }))
}
# Shutdown the guest cleanly
{$VMName | Stop-VM -Confirm:$false}
}
until ($script:response -eq “quit”);
Thanks for very useful script. The only problem i had is VCENTER is VM. I did see post above about creating folders but this is what i did to exclude VCENTER until all VM’s down
# For each of the VMs on the ESX hosts
Foreach ($VM in ($ESXSRV | Get-VM | Where { $_.PowerState -eq “poweredOn” } | Where { $_.Name -ne “VCENTER” })){
Hi, for those VMs that do not have MVtools, they will cause the script to wait, and not shut down the host. I’m setting up this script to trigger on heat or water in server room, so want things off, how would I set it so that it does a hard shut down of any VMs that have hung?
[...] telepíthetünk. APC és Powerware termékek esetén ez megoldott. Illetve létezik egy PowesShell script is. Ez is hasznos tud [...]
Nevermind — I had changed the wait time, and it was looping at 65 secs, I changed it again and all is well. Thank you for a great script!
BTW, some may find it useful to use the VMWare credential store, as opposed to storing their credentials in a script, here’s the connection string I have based on this:
http://communities.vmware.com/thread/199583
C:\WINDOWS\system32\windowspowershell\v1.0\powershell.exe -PSConsoleFile “C:\Program Files\VMware\Infrastructure\VSphere PowerCLI\vim.psc1” -NoExit –Command
$creds = Get-VICredentialStoreItem -Host ‘yourhost’
Connect-VIServer -Server yourserver -User $creds.User -Password $creds.Password
# Connect to the VC server credential store