################################################################################# # 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 http://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