Over that past few months I've been getting quite a few emails and comments as it pertains to the scripts I have shared to shutdown and power on VMs in the event of power loss. I assume since the storm weather is kicking in people are realizing that they need to have some kind of protection in regards to gracefully getting the VMs down. Now I've had the (privilege?) of watching my script run multiple times in a production environment and it has gotten to the point where it is working flawlessly. One caveat to the script though – whichever Windows box is executing the PowerShell must stay powered on longer than your vCenter Server.
That being said the script would be pretty useless if you had a virtualized vCenter Server running on the same cluster as your production VMs that your are shutting down – this is what all of the emails and comments that I've been getting have been based around. So, without further ado I've added a few updates to the script to better support those with a virtualized vCenter. A few explanations below…
So first off (Line 50) I've added a variable called $vCenterVMName and assigned this a default value of NA. This variable should hold the VM Name of your vCenter Server. I've tried to keep just one version of the script supporting both virtualized and non-virtualized vCenter's thus is why the default to "NA". So if you don't have a virtualized vCenter just leave the variable set to NA and the script will run as it always had, otherwise if you do, put its' VM name in here.
Secondly down on Lines 107 to 1118 I do a few things. First, check to see if you have changed that default value and if you have we need to figure out which ESXi host vCenter is running on in order to shut it down last. This is what's done here.
Then, in each of the shutdown loops (Line 125 and Line 162) I've added an if statement. Basically it just checks to see if the VM it is processing is the vCenter Server. If so, it doesn't process the shutdown.
Lastly I've done a couple more things. On Line 186 I've added a check while shutting down the hosts. If the host that is being processed is the host that vCenter is running on I want to leave it till the end, so it is skipped during this loop. Then, the finally the block of code starting on Line 196, if needed, will send the shutdown command to the host that is running vCenter Server.
As you may of noticed I've added a some logging as well, nothing bit, just a record of what happened in a txt file rather than relying on Write-Host. The script in its' entirety is below or you can download it here. Watch for updates to the power on script to support the vritualized vCenter as well. Just not sure how I'm going to tackle that one yet 🙂
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 |
################################################################################# # Power off VMs (poweroffvms.ps1) # # This is a complete update to my previous shutdown script. No longer do we # loop through the esx hosts and shut down VMs per host. We now just shut them # all down up front. Also, no more $vmstoleaveon variable. I'm assuming here # that your vCenter is not virtual. If it is you can most likely grab version # 1 of this script and take the code to leave the vCenter host till last. Maybe # someday I'll get around to updating it to merge the two...but for now, this is # it! # # This script does have a 'partner' script that powers the VMs back on, you can # grab that script at https://blog.mwpreston.net/shares/ # # Created By: Mike Preston, 2012 - With a whole lot of help from Eric Wright # (@discoposse) # # Variables: $mysecret - a secret word to actually make the script run, stops # the script from running when double click DISASTER # $vcenter - The IP/DNS of your vCenter Server # $username/password - credentials for your vCenter Server # $filename - path to csv file to store powered on vms used for the poweronvms.ps1 script. # $cluster - Name of specific cluster to target within vCenter # $datacenter - Name of specific datacenter to target within vCenter # # # Usage: ./poweroffvms.ps1 "keyword" # Intended to be ran in the command section of the APC Powerchute Network # Shutdown program before the shutdown sequence has started. # ################################################################################# param($keyword) Add-PSSnapin VMware.VimAutomation.Core #some variables $vcenter = "vcenterServer" $username = "user" $password = "password" $cluster = "clusterName" $datacenter = "datacenterName" $filename = "c:\path\to\poweredonvms.csv" $mysecret = "kerfuffle" $date = ( get-date ).ToString('yyyyMMdd') $logfile = New-Item -type file "C:\ShutdownLog-$date.txt" #for use with a virtualized vCenter - bring it down last :) - if you don't need this functionality #simply leave the variable set to NA and the script will work as it always had $vCenterVMName = "NA" Write-Host "A Powerchute network shutdown command has been sent to the vCenter Server." -Foregroundcolor yellow Write-Host "This script will shutdown all of the VMs and hosts located in $datacenter" -Foregroundcolor yellow Write-Host "Upon completion, this server ($vcenter) will also be shutdown gracefully" -Foregroundcolor yellow Write-Host "" Write-Host "This script has also has a counterpart (powervmsbackon.ps1) which should" -Foregroundcolor yellow Write-Host "be setup to run during the startup of this machine ($vcenter). " -Foregroundcolor yellow Write-Host "This will ensure that your VMs are powered back on once power is restored!" -Foregroundcolor yellow Sleep 5 Add-Content $logfile "mwpreston.net PowerOff Script Engaged" Add-Content $logfile "" if ($keyword -ne $mysecret) { Write-Host "You haven't passed the proper detonation sequence...ABORTING THE SCRIPT" -ForegroundColor red Add-Content $logfile "You haven't passed the proper detonation sequence...ABORTING THE SCRIPT" exit } #connect to vcenter Write-Host "Connecting to vCenter - $vcenter ...." -nonewline Add-Content $logfile "Connecting to vCenter - $vcenter" $success = Connect-VIServer $vcenter -username $username -Password $password if ($success) { Write-Host "Connected!" -Foregroundcolor Green } else { Write-Host "Something is wrong, Aborting script" -Foregroundcolor Red Add-Content $logfile "Something is wrong, Aborting script" exit } Write-Host "" Add-Content $logfile "" #Get a list of all powered on VMs - used for powering back on.... Get-VM -Location $cluster | where-object {$_.PowerState -eq "PoweredOn" } | Select Name | Export-CSV $filename #change DRS Automation level to partially automated... Write-Host "Changing cluster DRS Automation Level to Partially Automated" -Foregroundcolor green Get-Cluster $cluster | Set-Cluster -DrsAutomation PartiallyAutomated -confirm:$false #change the HA Level Write-Host "" Write-Host "Disabling HA on the cluster..." -Foregroundcolor green Write-Host "" Add-Content $logfile "Disabling HA on the cluster..." Add-Content $logfile "" Get-Cluster $cluster | Set-Cluster -HAEnabled:$false -confirm:$false #get VMs again (we will do this again instead of parsing the file in case a VM was powered in the nanosecond that it took to get here.... :) Write-Host "" Write-Host "Retrieving a list of powered on guests...." -Foregroundcolor Green Write-Host "" Add-Content $logfile "Retrieving a list of powered on guests...." Add-Content $logfile "" $poweredonguests = Get-VM -Location $cluster | where-object {$_.PowerState -eq "PoweredOn" } Add-Content $logfile "Checking to see if vCenter is virtualized" #retrieve host info for vCenter if ($vcenterVMName -ne "NA") { Add-Content $logfile "vCenter is indeed virtualized, getting ESXi host hosting vCenter Server" $vCenterHost = (Get-VM $vCenterVMName).Host.Name Add-Content $logfile "$vCenterVMName currently running on $vCenterHost - will process this last" } else { Add-Content $logfile "vCenter is not virtualized" } Add-Content $logfile "Proceeding with VM PowerOff" Add-Content $logfile "" #and now, let's start powering off some guests.... ForEach ( $guest in $poweredonguests ) { if ($guest.Name -ne $vCenterVMName) { Write-Host "Processing $guest ...." -ForegroundColor Green Write-Host "Checking for VMware tools install" -Foregroundcolor Green $guestinfo = get-view -Id $guest.ID if ($guestinfo.config.Tools.ToolsVersion -eq 0) { Write-Host "No VMware tools detected in $guest , hard power this one" -ForegroundColor Yellow Add-Content $logfile "$guest.Name - no VMware tools, hard power off" Stop-VM $guest -confirm:$false } else { write-host "VMware tools detected. I will attempt to gracefully shutdown $guest" Add-Content $logfile "$guest.Name - VMware tools installed, gracefull shutdown" $vmshutdown = $guest | shutdown-VMGuest -Confirm:$false } } } #Lets wait a minute or so for shutdowns to complete Write-Host "" Write-Host "Giving VMs 2 minutes before resulting in hard poweroff" Write-Host "" Add-Content $logfile "" Add-Content $logfile "Waiting a couple minutes then hard powering off all remaining VMs" Add-Content $logfile "" Sleep 120 #Now, let's go back through again to see if anything is still powered on and shut it down if it is Write-Host "Beginning Phase 2 - anything left on....night night..." -ForegroundColor red Write-Host "" #get our list of guests still powered on... $poweredonguests = Get-VM -Location $cluster | where-object {$_.PowerState -eq "PoweredOn" } ForEach ( $guest in $poweredonguests ) { if ($guest.Name -ne $vCenterVMName) { Write-Host "Processing $guest ...." -ForegroundColor Green #no checking for toosl, we just need to blast it down... write-host "Shutting down $guest - I don't care, it just needs to be off..." -ForegroundColor Yellow Add-Content $logfile "$guest.Name - Hard Power Off" Stop-VM $guest -confirm:$false } } #wait 30 seconds Write-Host "Waiting 30 seconds and then proceding with host power off" Write-Host "" Add-Content $logfile "" Add-Content $logfile "Processing power off of all hosts now" Sleep 30 #and now its time to slam down the hosts - I've chosen to go by datacenter here but you could put the cluster # There are some standalone hosts in the datacenter that I would also like to shutdown, those vms are set to # start and stop with the host, so i can just shut those hosts down and they will take care of the vm shutdown ;) $esxhosts = Get-VMHost -Location $cluster foreach ($esxhost in $esxhosts) { if ($esxhost.Name -ne $vCenterHost) { #Shutem all down Write-Host "Shutting down $esxhost" -ForegroundColor Green Add-Content $logfile "Shutting down $esxhost" $esxhost | Foreach {Get-View $_.ID} | Foreach {$_.ShutdownHost_Task($TRUE)} } } #finally shut down the host which vCenter resides on if using that functionality if ($vcenterVMName -ne "NA") { Add-Content $logfile "" Add-Content $logfile "Processing $vcenterHost - shutting down " Get-VMhost $vCenterHost | Foreach {Get-View $_.ID} | Foreach {$_.ShutdownHost_Task($TRUE)} } Add-Content $logfile "" Add-Content $logfile "All done!" #that's a wrap |
So there you have it! Hopefully this will help some of you out with your shutdown endeavors. Feel free to make any changes you need in order to make it work for your environment and let me know how it goes – keep those comments, concerns, thoughts and emails coming in!
Thanks for the updated script. I need to get this updated because I now have an SSO server, Inventory server, and vcenter server. Any ideas the easiest way to exclude all of my vcenter servers from shutting down until the end?
Hi,
i found your script to be really great, do you mind if i post it on my blog with some changes i made?
I added the following:
– support for vApps
– removed annoying error messages when variables are = null
– added support for encrypted password dumped on a file (don’t like password in clear text)
– added date-time in the log file for each event
– minor cosmetic in the output
– tested with vsphere 5.5 U1
I actually have two clusters in my lab. How do I get the script to interact with both?
You could technically pass your Datacenter object name into the cluster variable, then it would grab all the VMs located in that virtual datacenter! Probably the easiest way! You will have to ensure that you perform the HA/DRS enable/disable on both clusters though if you want to do that!
Hi, this is really great! I wonder – is there a way to store the result? for example – if a VM can’t be shut down for whatever reason, is there some kind of output that can be stored in the log?
I’m sure there is! I’ve been through a few iterations of this script and have a lot of notes and changes I’d like to make upon my next! I’ll be sure to keep that in mind! Thanks!