Script: Emergency – Shutdown

Recently I had a vSphere 4.0 U1 environment experience a major outage. I had to bring down our entire environment consisting of 242 guests and 6 hosts. I knew that I had a bash script that I wrote for a 3.5 environment for this scenario, but due to logistical reasons it was unavailable. I had to come up with a quick solution as everyone was waiting on me.


A 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. (Thank you Alan.) After the outage, I took another look at his script and wanted to add a few other touches to it – specifically a warning screen with a way to safely stop the script before starting to shutdown VMs. Since I will be sharing this script with co-workers, I needed a way for them to stop the script if they accidentally started running it by mistake.

I am running the following revised script in PowerCLi version 4.1.

@"
===============================================================================
Title: 			SHUTDOWN v2.7
Created:		Alan Renouf
Modified by:	J. Sam Aaron 	12/24/2010
Description: 	Shutsdown all VMs and then the ESX Server
Requirements: 	Windows Powershell and the VI Toolkit
Usage:			.\shutdown.ps1
===============================================================================
"@

# Add the VI-Snapin if it isn't loaded already
if ( (Get-PSSnapin -Name "VMware.VimAutomation.Core" -ErrorAction SilentlyContinue) -eq $null )
	{
	Add-PSSnapin -Name "VMware.VimAutomation.Core"
	}

# Variables
Write-Host
$vc = Read-Host "Enter the ESX IP Address"
$VIServer = Connect-VIServer -Server $vc

# vc had some timeouts so retry...
if ($null -eq $VIServer) {
    write-host "Retrying Connect to "$vc
	$VIServer = Connect-VIServer -Server $vc
	}

# Warning Notice
$input = ""
clear
Write-Host "Connected to" $vc
Write-Host
Write-Host "==============================================================================="
Write-Host "===                                                                         ==="
Write-Host "===       WARNING!     WARNING!     WARNING!     WARNING!     WARNING!      ==="
(New-Object -ComObject sapi.spvoice).speak("WARNING! WARNING! WARNING!") | Out-Null
Write-Host "===                                                                         ==="
Write-Host "==============================================================================="
Write-Host
Write-Host "  This script is designed to power off all virtual machines and the ESX host."
Write-Host
Write-Host
$input = Read-Host "  TYPE 'NO' TO STOP THIS SCRIPT AND EXIT NOW."
if ($input -eq "no") {
	 Write-Host
	 Write-Host "==============================================================================="
	 Write-Host "===               THE SHUTDOWN PROCESS HAS BEEN CANCELLED.                  ==="
	 Write-Host "==============================================================================="
	 exit
	}
Write-Host
Write-Host "==============================================================================="
Write-Host "===                    THE SHUTDOWN PROCESS WILL RESUME.                    ==="
Write-Host "==============================================================================="

#Get All the ESX Hosts
$ESXSRV = Get-VMHost
#$ESXSRV = Get-Cluster "Cluster Name" | Get-VMHost
#$ESXSRV = Get-DataCenter “DC1” | Get-VMHost

# For each of the VMs on the ESX hosts
Foreach ($VM in ($ESXSRV | Get-VM | Where { $_.PowerState -eq “poweredOn” } )){
     # Shutdown the guest cleanly
     $VM | Shutdown-VMGuest -Confirm:$false | Out-Null
	 Write-Host
	 Write-Host $VM "is Powering Down"
	}

# Set the amount of time to wait before assuming the remaining powered on guests are stuck
$waittime = 60 #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-host
	 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 $timeleft -eq 0) 

# Force VMs off
Foreach ($VM in ($ESXSRV | Get-VM | Where { $_.PowerState -eq “poweredOn” } )){
	 $VM | Stop-VM -Confirm:$false | Out-Null
	 Write-Host
	 Write-Host $VM "has been Powered Off"
	}

# Timer to delay Maintenance Mode
$waittime = 20 #Seconds
$Time = (Get-Date).TimeofDay
 do {
	 sleep 1.0
	 $timeleft = $waittime - ($Newtime.seconds)
	 $Newtime = (Get-Date).TimeofDay - $Time
	} until (($Newtime).Seconds -ge $waittime)

# Place ESX in Maintenance Mode
$ESXSRV | Set-VMHost -State Maintenance | Out-Null
Write-Host
Write-Host   $vc "is in Maintenance Mode"

# Shutdown the ESX Hosts
$ESXSRV | Foreach {Get-View $_.ID} | Foreach {$_.ShutdownHost_Task($TRUE)} | Out-Null
Write-Host
Write-Host "==============================================================================="
Write-Host "===                  THE SHUTDOWN PROCESS HAS COMPLETED.                    ==="
Write-Host "==============================================================================="

# Disconnect from the ESX Server
Write-Host
Disconnect-VIServer -Server $vc -Confirm:$False
Write-Host "  Disconnected from" $vc

#######################################################################
# Changes:
# Version 2.7 - Added the ability to stop the shutdown during the warning
# Version 2.6 - Added Delay for Maintenance Mode
# Version 2.5 - Added Warning Notice
# Version 2.4 - Added Force stop
# Version 2.3 - Fixed Bug in Time: Adjusted waittime to 60 seconds
# Version 2.2 - Added Maintenance Mode
# Version 2.1 - Added a line to print that the VM was powered off
# Version 2.0 - Cleaned up Script
# Version 1.9 - Added Prompt for Host
# Version 1.8 - Added Sanity Check for PSSnapin
# Version 1.7 - Added Countdown timer
# Version 1.6 - Added Sanity Check on VM State
# Version 1.5 - Added VC Disconnection
# Version 1.4 - Added VC Connection
# Version 1.3 - Added VM Shutdown
# Version 1.2 - Added Title Sequence
# Version 1.1 - Added PSSnapin
# Version 1.0 - Initial Creation

The script is available for download here (Right-Click and “Save As”).

A few words of caution: Run this script in a fresh powercli or powershell window. If connecting to vCenter, this script will contact EVERY ESX host and start shutting down ALL VMs. If you need to shut down specific VMs on an ESX server, then connect to that server individually. Or comment out LINE 58 and uncomment LINE 59 or 60 for the specific Cluster or Datacenter that you need powered off.