AntonVZhbankov
Immortal
Immortal

Shutdown infrastructure on power outage

Let's suppose we have dedicated Windows host with UPS monitoring hardware and we can run PowerCLI script on UPS event.

For physical vCenter I wrote some script:

 Get-VMHost | ForEach-Object {
  $myOnVMs = (Get-VM | Where-Object {$_.PowerState -eq "PoweredOn"})
  $myOnVMs | Shutdown-VMGuest
  Start-Sleep -Seconds 300
  $myOnVMs = (Get-VM | Where-Object {$_.PowerState -eq "PoweredOn"})
  $myOnVMs | Stop-VM -RunAsync
  Start-Sleep -Seconds 60
  Set-VMHost -vmhost $_ -state maintenance
  Stop-VMHost -vmhost $_ -RunAsync
}

Any thoughts, comments, additions?


---

MCSA, MCTS Hyper-V, VCP 3/4, VMware vExpert

http://blog.vadmin.ru

EMCCAe, MCITP: SA+VA, VCP 3/4/5, VMware vExpert http://blog.vadmin.ru
0 Kudos
7 Replies
LucD
Leadership
Leadership

Could be a bit shorter by dropping the variables.

Perhaps you could include in the first Where-Object a condition to check if VMware Tools are installed.

Get-VMHost | ForEach-Object {
	Get-VM | Where-Object {$_.PowerState -eq "PoweredOn" -and $_.Guest.State -eq "Running"} | Shutdown-VMGuest
	Start-Sleep -Seconds 300
	Get-VM | Where-Object {$_.PowerState -eq "PoweredOn"} | Stop-VM -RunAsync
	Start-Sleep -Seconds 60
	Set-VMHost -vmhost $_ -state maintenance
	Stop-VMHost -vmhost $_ -RunAsync
}

____________

Blog: LucD notes

Twitter: lucd22


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

RvdNieuwendijk
Leadership
Leadership

I would do it like this:

Get-VM | Where-Object {$_.PowerState -eq "PoweredOn"} | Shutdown-VMGuest
Start-Sleep -Seconds 300
Get-VM | Where-Object {$_.PowerState -eq "PoweredOn"} | Stop-VM -RunAsync
Start-Sleep -Seconds 60
Get-VMHost | ForEach-Object {
  Set-VMHost -vmhost $_ -state maintenance
  Stop-VMHost -vmhost $_ -RunAsync
}

The main change is that I removed the stopping of the VM's from the VMHost loop. As you have to stop the VM's only once and not for every host.

Regards, Robert

Blog: https://rvdnieuwendijk.com/ | Twitter: @rvdnieuwendijk | Author of: https://www.packtpub.com/virtualization-and-cloud/learning-powercli-second-edition
AntonVZhbankov
Immortal
Immortal

>The main change is that I removed the stopping of the VM's from the VMHost loop

Thanks, it makes sense. And helps to avoid problems if DRS migrate new VMs to host with powered off VMs.


---

MCSA, MCTS Hyper-V, VCP 3/4, VMware vExpert

http://blog.vadmin.ru

EMCCAe, MCITP: SA+VA, VCP 3/4/5, VMware vExpert http://blog.vadmin.ru
0 Kudos
RvdNieuwendijk
Leadership
Leadership

And it makes the script at least (number of hosts -1) * 360 seconds faster. Smiley Wink

Blog: https://rvdnieuwendijk.com/ | Twitter: @rvdnieuwendijk | Author of: https://www.packtpub.com/virtualization-and-cloud/learning-powercli-second-edition
0 Kudos
AntonVZhbankov
Immortal
Immortal

Robert, you're absolutely right.

But what would you suggest for vCenter in VM?


---

MCSA, MCTS Hyper-V, VCP 3/4, VMware vExpert

http://blog.vadmin.ru

EMCCAe, MCITP: SA+VA, VCP 3/4/5, VMware vExpert http://blog.vadmin.ru
0 Kudos
LucD
Leadership
Leadership

If your vCenter runs in a VM, you would probably be better of to connect to the ESX(i) servers one-by-one.

If you need to keep your vCenter running till last, you can look at my Counter the self-aware VUM post to see how you can find the vCenter.

____________

Blog: LucD notes

Twitter: lucd22


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

0 Kudos
RvdNieuwendijk
Leadership
Leadership

You are right. I didn't think about the vCenter Server running as a VM. But while thinking about that, it is also possible that you are running the database server used by the vCenter server as a VM. And we have the need to sometimes shutdown only one cluster, so I wanted to be able to specify a cluster name. It is possible that the vCenter Server or the database server or both are running on that cluster. So I made a new script that handles this all. I have tested this script in my test environment. But it has only one cluster and one ESX 3.5 server in that cluster. It has five VM's, the vCenter Server and the vCenter database server included. So I was not able to test all scenario's. But I have a good confidence that it will work in other scenario's as well.

<#
.SYNOPSIS
  This PowerCLI script stops all virtual machines and ESX servers.
.DESCRIPTION
  If you specify the ClusterName parameter only this cluster will be stopped.
  You might run the vCenter Server or it's database server or both as a VM.
  In that case you have to specify their virtual machine names if they are running in the
  environment that has to be stopped.
.PARAMETER VIServerName
  Specify the name of the vCenter Server if this is running as a virtual machine
  on the environment that will be stopped.
.PARAMETER DBServerName
  Specify the name of the vCenter Server it's database server
  if this is running as a VM on the environment that will be stopped.
.PARAMETER ClusterName
  Specify a cluster name if only this cluster has to be stopped.
.NOTES
  This script requires PowerShell v2 and PowerCLI.
.EXAMPLE
  ./Stop-vSphere -VIServerName vCenter -DBServername SQLserver -Cluster MyCluster
  
  Stops all VM's and all ESX servers of the MyCluster cluster.
#>

param ([string] $VIServerName,
       [string] $DBServerName,
	   [string] $ClusterName)

Set-StrictMode -Version 2.0

function Get-VMHostName {
<#
.SYNOPSIS
  Returns the host name of a virtual machine.
.DESCRIPTION
  Returns the host name of a virtual machine.
.PARAMETER Name
  Specify the name of a virtual machine.
.EXAMPLE
  Get-VMHostName -Name MyVM
  
  Returns the host name of the MyVM virtual machine.
#>

  param ([parameter(Mandatory=$true)][string] $Name)
	  
  $VM = Get-VM -Name $Name
  if ($VM) {
    $VM.Host.Name
  }
}

function Stop-VMOnVMHost {
<#
.SYNOPSIS
  Stops a virtual machine while connected to the ESX server where the virtual machine is running.
.DESCRIPTION
  Stops a virtual machine while connected to the ESX server where the virtual machine is running.
.PARAMETER Name
  Specify the name of a virtual machine.
.PARAMETER VMHostName
  Specify the name of the ESX server on which the virtual machine is running.
.PARAMETER Credential
  Specify a PSCredential object that contains credentials for authenticating with the server.
.EXAMPLE
  Stop-VMOnVMHost -Name MyVM -VMHostName ESX1 -Credential (Get-Credential)
  
  Stops the virtual machine MyVM while connected to ESX1.
#>

  param ([parameter(Mandatory=$true)][string] $Name,
         [parameter(Mandatory=$true)][string] $VMHostName,
		 [parameter(Mandatory=$true)][http://System.Management.Automation.PSCredential|http://System.Management.Automation.PSCredential] $Credential)

  Write-Debug "Connecting to $VMHostName"
  Connect-VIServer -Server $VMHostName -Credential $Credential

  # Stop the VM
  $VM = Get-VM -Name $Name | Where-Object {$_.PowerState -eq "PoweredOn" -and $_.Guest.State -eq "Running"}
  if ($VM) {
    Write-Debug "Shutting down the $Name server"
    $VM | Shutdown-VMGuest -Confirm:$False
    Write-Debug "Waiting 300 Seconds"
    Start-Sleep -Seconds 300
  }
  $VM = Get-VM -Name $Name | Where-Object {$_.PowerState -eq "PoweredOn"}
  if ($VM) {
    Write-Debug "Stopping the $Name VM"
    $VM | Stop-VM -Confirm:$False
    Write-Debug "Waiting 60 Seconds"
    Start-Sleep -Seconds 60
  }
}

function Stop-VMHostOnVMHost {
<#
.SYNOPSIS
  Stops an ESX server while connected to that ESX server.
.DESCRIPTION
  Stops an ESX server while connected to that ESX server.
.PARAMETER Name
  Specify the name of an ESX server.
.PARAMETER Credential
  Specify a PSCredential object that contains credentials for authenticating with the server.
.EXAMPLE
  Stop-VMHostOnVMHost -Name ESX1 -Credential (Get-Credential)
  
  Stops ESX server ESX1 while connected to ESX1.
#>

  param ([parameter(Mandatory=$true)][string] $Name,
         [parameter(Mandatory=$true)][http://System.Management.Automation.PSCredential|http://System.Management.Automation.PSCredential] $Credential)
	
  Write-Debug  "Connecting to host $Name"
  Connect-VIServer -Server $Name -Credential $HostCredential

  Write-Debug "Setting host $Name in maintenance mode"
  Set-VMHost -VMHost $Name -State Maintenance -Confirm:$False

  Write-Debug "Stopping the host $Name"
  Stop-VMHost -VMHost $Name -Confirm:$False -RunAsync
}

# Disable debugging
# $DebugPreference = "SilentlyContinue"

# Enable debugging
$DebugPreference = "Continue"

# Get the cluster
if ($ClusterName) {
  $Cluster = Get-Cluster -Name $ClusterName
}

# Get the host credential
"Type username and password for a host in the credentials box"
$HostCredential = Get-Credential

# Find the vCenter server it's host name
if ($VIServerName) {
  $vcHostName = Get-VMHostName -Name $VIServerName
}

# Find the vCenter database server it's host name
if ($DBServerName) {
  $dbHostname = Get-VMHostName -Name $DBServerName
}

# Shutdown all guests except the vCenter Server and the database server
if ($Cluster) {
  $myOnVMs = $Cluster | Get-VM | Where-Object {$_.Name -ne $VIServerName -and $_.Name -ne $DBServerName -and $_.PowerState -eq "PoweredOn" -and $_.Guest.State -eq "Running"}
}
else {
  $myOnVMs = Get-VM | Where-Object {$_.Name -ne $VIServerName -and $_.Name -ne $DBServerName -and $_.PowerState -eq "PoweredOn" -and $_.Guest.State -eq "Running"}
  
}
if ($myOnVMs) {
  Write-Debug "Shutting down guests"
  $myOnVMs | Shutdown-VMGuest -Confirm:$False
  Write-Debug "Waiting 300 Seconds"
  Start-Sleep -Seconds 300
}

# Stop all VM's except the vCenter Server and the database server
if ($Cluster) {
  $myOnVMs = $Cluster | Get-VM | Where-Object {$_.Name -ne $VIServerName -and $_.Name -ne $DBServerName -and $_.PowerState -eq "PoweredOn"}
}
else {
  $myOnVMs = Get-VM | Where-Object {$_.Name -ne $VIServerName -and $_.Name -ne $DBServerName -and $_.PowerState -eq "PoweredOn"}
}
if ($myOnVMs) {
  Write-Debug "Stopping VM's"
  $myOnVMs | Stop-VM -Confirm:$False -RunAsync
  Write-Debug "Waiting 60 Seconds"
  Start-Sleep -Seconds 60
}
  
# Stop all hosts except the ones running the vCenter Server and the database server
if ($Cluster) {
  $MyHosts = $Cluster | Get-VMHost | Where-Object {$_.Name -ne $vcHostName -and $_.Name -ne $dbHostName}
}
else {
  $MyHosts = Get-VMHost | Where-Object {$_.Name -ne $vcHostName -and $_.Name -ne $dbHostName}
}
If ($MyHosts) {
  $MyHosts | ForEach-Object {
    Write-Debug "Setting host $_ in maintenance mode"
    Set-VMHost -VMHost $_ -State Maintenance -Confirm:$False
    Write-Debug "Stopping host $_"
    Stop-VMHost -VMHost $_ -Confirm:$False -RunAsync
  }
}

Disconnect-VIServer * -Confirm:$false

if ($vcHostName) {
  # Check if the vCenter Server it's host is in the cluster
  if ($Cluster) {
    $vcHost = $Cluster | Get-VMHost -Name $vcHostName
  }
  else {
    $vcHost = Get-VMHost -Name $vcHostName
  }
}

if ($dbHostName) {
  # Check if the database server it's host is in the cluster
  if ($Cluster) {
    $dbHost = $Cluster | Get-VMHost -Name $dbHostName
  }
  else {
    $dbHost = Get-VMHost -Name $dbHostName
  }
}

if ($vcHost) {
  # Stop the vCenter Server on it's host
  Stop-VMOnVMHost -Name $VIServerName -VMHostName $vcHostName -Credential $HostCredential
}

if ($dbHost) {
  # Stop the database server on it's host
  Stop-VMOnVMHost -Name $DBServerName -VMHostName $dbHostName -Credential $HostCredential
}

if ($vcHost) {
  # Stop the host running the vCenter Server
  Stop-VMHostOnVMHost -Name $vcHostName -Credential $HostCredential
}

if ($dbHost -and ($vcHostName -ne $dbHostName)) {
  # Stop the host running the database server
  Stop-VMHostOnVMHost -Name $dbHostName -Credential $HostCredential 
}

As the script uses square brackets and the forum software has problems with them, I also attach the script so you can download it.

Message was edited by: RvdNieuwendijk

Blog: https://rvdnieuwendijk.com/ | Twitter: @rvdnieuwendijk | Author of: https://www.packtpub.com/virtualization-and-cloud/learning-powercli-second-edition
0 Kudos