VMware Cloud Community
Tchaney
Contributor
Contributor
Jump to solution

Shutting down VMs with and without VMware tools installed

So after a major power failure where I work occured where the UPS's batteries only ran about 10 minutes and the backup generator didn't kick in, I've been put in charge of writing a script that kicks off to shut down VMs and servers within a given cluster. Now as I'm fairly new to the enviroment here so I'm not sure if all vms have the tools installed. I want to cover all the bases and cover vms that don't have tools installed. What my script currently does is it initiates the guest shutdown on all vms and checks every 10 seconds up to 120 seconds for the VMs to go offline If after 120 seconds there are still vms online it issues a power off command on all servers that haven't shut down. Now this will catch all the VMs but I don't want the machine have to wait the full 2 minutes if it can be avoided (remember this script will be ran when the datacenter goes to UPS power so every watt counts to keep the critical systems online). the script does throw an error when it can't shutdown because no tools are installed so I was thinking I could use a try/catch block to catch the error and send just a strait power off command to those vms. I've attempted to do so, but no success.

Is there a way that I can either catch the error, or shutdown all VMs that don't have tools installed?

Attached is my code maybe you can spot what I can do to shutdown the VMs without tools within the do/while loop when the errors first occur.

Add-PSSnapin VMware.VimAutomation.Core
$server = $args[0]
$cluster = $args[1]
Connect-VIServer -Server $server
$counter = 0
do {
if (Get-Cluster -Name $cluster | get-vm | where {$_.powerstate -eq "poweredon"}){
  if ($counter -eq 0) {
   Get-Cluster -Name $cluster |get-vm | where {$_.powerstate -eq "poweredon"} | shutdown-VMGuest -Confirm:$false
  }
  Write-Host "VMs are powered on waiting "(120-$counter)" Seconds"
  $counter = $counter + 10
  Sleep 10
  }
}
while ($counter -le 110) -or ((Get-VMHost | Get-VM | where {$_.powerstate -eq "poweredon"}).count) -ne 0
if ($counter = 120) {
Write-Host "Some VMs failed to shut down gracefully, powering down now"
Get-Cluster -name $cluster |get-vm | where {$_.powerstate -eq "poweredon"} | Stop-VM -Confirm:$false
}
Write-Host "Putting servers into maintenance mode."
Get-cluster -name $cluster | get-vmhost | where {$_.state -eq "connected"} | Set-VMHost -State "Maintenance"
sleep 10
Write-Host "Shutting down servers."
Get-cluster -name $cluster | get-vmhost | where {$_.state -eq "Maintenance"} | Stop-VMHost -Confirm:$false
Disconnect-VIServer -Confirm:$false
0 Kudos
1 Solution

Accepted Solutions
LucD
Leadership
Leadership
Jump to solution

Try something like this

$vm = Get-VM
$vm | where {$_.Guest.State -eq "Running"} | Shutdown-VMGuest -Confirm:$false 
$vm | where {$_.Guest.State -eq "NotRunning"} | Stop-VM -Confirm:$false

The VMs where the VMware Tools are running will get a Guest shutdown, while the VMs that not have the VMware Tools running, will get a poweroff.


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

View solution in original post

0 Kudos
8 Replies
RParker
Immortal
Immortal
Jump to solution

Question)

Why aren't tools installed, not only are they recommended and useful, they are critical to VM functionality.  They aren't any different from using OEM drivers on stand alone servers, and even more compatible because they are tailor made for VM guest OS they support.

You can do OS level shutdown using a script from the AD to directly communicate with the OS by name also.

0 Kudos
Tchaney
Contributor
Contributor
Jump to solution

I agree that the tools should be installed, but that doesn't mean that they always are. With a large enviroment there's a good possibility that a server or two have been missed. I was just hoping that if I ran into a VM like that, I could bring it down quicker than waiting the full 120 seconds.

0 Kudos
LucD
Leadership
Leadership
Jump to solution

Try something like this

$vm = Get-VM
$vm | where {$_.Guest.State -eq "Running"} | Shutdown-VMGuest -Confirm:$false 
$vm | where {$_.Guest.State -eq "NotRunning"} | Stop-VM -Confirm:$false

The VMs where the VMware Tools are running will get a Guest shutdown, while the VMs that not have the VMware Tools running, will get a poweroff.


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

0 Kudos
Tchaney
Contributor
Contributor
Jump to solution

Thanks for the commands. Do I need any other snapin installed besides the VMware.VimAutomation.Core? I ask because when I attempt to run the command, I get the "is not recognized as as the name of a cmdlet, function, script file or operable program."

additionally while debugging my script, I noticed that my while section that is checking the time or for running vms, it doesn't detect that there aren't any running vms.

More specifically, I tested the commands (Get-VM | where {$_.powerstate -eq "poweredon"}).count and (Get-VM |where {&_.powerstate -eq "poweredoff"}).count and noticed that from the commandline it'll respond with counts 0-"number of VMs" but from a script it returns nothing for 0 or 1 VM. Anyone have experience with this?

**EDIT**

nevermind about the whole count issue, it's because I'm not explicitly declairing the variable as an array...

Funny how you get deeper into it, the easier it is to miss the little things.

0 Kudos
LucD
Leadership
Leadership
Jump to solution

You did load the snapin with Add-PSSnapin I assume ?

Did you do a Connect-VIServer to a vCenter or an ESXi host ?


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

0 Kudos
Tchaney
Contributor
Contributor
Jump to solution

Well don't I feel silly, for some reason I wasn't bright enough to reboot my connections after a weekend of inactivity. the commands work beautifully.

Now correct me if I'm wrong, but would it be a fair statement to say that machines returned by the command "notrunning" are those that are both running without tools installed and vms that are currently powered off? From my tests it seems like it.

0 Kudos
LucD
Leadership
Leadership
Jump to solution

Not exactly, when the tools are not running you might also see "toolsNotRunning".

The possible values can be found in the VirtualMachineToolsStatus enumeration.

When in doubt always consult the SDK Reference :smileygrin:


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

Tchaney
Contributor
Contributor
Jump to solution

Thanks for all the information. I need to wait for a test cluster to free up to test my script against some physical hardware and integration testing (with our UPS and stuff like that). Here's my code in case anyone has a need similar to what I do.

#Written by Travis C
#
#This script is designed to as gracefully as possible shut down all vms in a cluster and power the hardware down.
#
#Requirements to run: PowerCLI installed, Credentials cached on the server and account the script will be ran from.
#Command: New-VICredentialStoreItem -host {hostname} -User {Username} -Password {Password}
#
Add-PSSnapin VMware.VimAutomation.Core
$server = $args[0]
$cluster = $args[1]
Connect-VIServer -Server $server
$counter = 0
do {
if (Get-Cluster -Name $cluster | get-vm | where {$_.powerstate -eq "poweredon"}){
  if ($counter -eq 0) {
   Get-Cluster -Name $cluster | Get-VM | where {$_.guest.state -eq "notrunning"} | Where {$_.powerstate -eq "poweredon"} | Stop-VM -Confirm:$false
   Get-Cluster -Name $cluster | Get-vm | where {$_.powerstate -eq "poweredon"} | shutdown-VMGuest -Confirm:$false
  }
  Write-Host "VMs are powered on waiting "(120-$counter)" Seconds"
  $counter = $counter + 10
  Sleep 10
  }
}
until ((@(Get-VMHost | Get-VM | where {$_.powerstate -eq "poweredon"}).count -eq 0 ) -or ($counter -ge 120))
if ($counter -eq 120) {
Write-Host "Some VMs failed to shut down gracefully, powering down now"
get-cluster -name $ cluster | get-vm | where {$_.powerstate -eq "poweredon"} | Stop-VM -Confirm:$false
}
Write-Host "Putting servers into maintenance mode."
Get-cluster -name $cluster | get-vmhost | where {$_.state -eq "connected"} | Set-VMHost -State "Maintenance"
sleep 10
Write-Host "Shutting down servers."
Get-cluster -name $cluster | get-vmhost | where {$_.state -eq "Maintenance"} | Stop-VMHost -Confirm:$false
Disconnect-VIServer -Confirm:$false
0 Kudos