VMware Cloud Community
tdubb123
Expert
Expert

shutdown VMs and patch esxi host

I got a standalone esxi host to patch and need to manually shutdown the VMs, patch the host via update manager, wait for the host to patch, reboot then power on the vms back on

$vms = get-datacenter xxx | get-vm

foreach ($vm in $vms) {

   if($vm.PowerState -eq 'PoweredOn'){

  Shutdown-VMGuest -VM $vm -Confirm:$false

   while($vm.PowerState -eq 'PoweredOn'){

  sleep 5

   $vm = Get-VM -Name $vm.Name

   }

   }

   }

set-vmhost -VMHost $vmhost -State Maintenance -Confirm:$false

$baseline | Attach-Baseline -entity $vmhost -Confirm:$false

Scan-Inventory -Entity $vmhost

$baseline | Remediate-Inventory -Entity $vmhost -Confirm:$false -ErrorAction SilentlyContinue

get-vmhost -name $vmhost | set-vmhost -state Connected -Confirm:$false

$vm | start-vm -confirm:$false

Will this work. I also have a problem where a vm can get stuck in a shutdown state for a long time. I want to stop the VM if it does not shutdown in say 3 mins. How do i do this?

0 Kudos
15 Replies
Grzesiekk
Expert
Expert

$vms = get-datacenter xxx | get-vm

foreach ($vm in $vms) {

   if($vm.PowerState -eq 'PoweredOn'){

  Shutdown-VMGuest -VM $vm -Confirm:$false

$counter = 0

   while($vm.PowerState -eq 'PoweredOn'){

if ($counter -gt 180) {

$vm = Get-VM -Name $vm.Name

stop-vm -vm $vm -confirm:$false

} else { 

sleep 5

   $vm = Get-VM -Name $vm.Name

$counter+=5

}

   }

   }

   }

set-vmhost -VMHost $vmhost -State Maintenance -Confirm:$false

$baseline | Attach-Baseline -entity $vmhost -Confirm:$false

Scan-Inventory -Entity $vmhost

$baseline | Remediate-Inventory -Entity $vmhost -Confirm:$false -ErrorAction SilentlyContinue

get-vmhost -name $vmhost | set-vmhost -state Connected -Confirm:$false

$vm | start-vm -confirm:$false

Counter for 180sec, if triggered, then you stop the vm, using your script.

--- @blog https://grzegorzkulikowski.info
0 Kudos
LucD
Leadership
Leadership

That should work as far as I can tell.

To limit the time to wait to lets say 5 mins, you can use a timer.

Something like this for example

$vm = Get-VM -Name MyVM

$stopwatch = [system.diagnostics.stopwatch]::StartNew()

while ($timer.Elapsed.TotalSeconds -lt 300 -or $vm.PowerState -eq 'Running')

{

  sleep 5

   $vm = Get-VM -Name $vm.Name

}

$stopwatch.Stop()

if ($stopwatch.Elapsed.TotalSeconds -ge 300 -and $vm.PowerState -eq 'Running')

{

   Stop-VM -VM $vm -Confirm:$false

}


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

0 Kudos
tdubb123
Expert
Expert

Hi Thanks

I am having to wait for each vm to shutdown one by one. How can i change it to do a shutdown-vmguest all at same time?

0 Kudos
LucD
Leadership
Leadership

Since there is no RunAsync option for the Stop-VMGuest cmdlet, you could go for parallelism.

Stop 1 or more VMs in a background job, and launch multiple of those background jobs.


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

0 Kudos
tdubb123
Expert
Expert

Hi Lucd,

I am trying something like this without the for loop

$DC = read-host "Enter the Datacenter to patch"

$vmhost = get-vmhost -Location (Get-Datacenter $dc)

$vms = get-datacenter $dc | get-vm | ?{$_.powerstate -eq "Poweredon"}

$baseline = get-baseline -server vc -Name *Critical*

if($vms.PowerState -eq 'PoweredOn'){

$vms | Shutdown-VMGuest -Confirm:$false

while($vms.PowerState -eq 'PoweredOn'){

sleep 5

$vms = get-datacenter $dc | get-vm

}

it seems to work but how would i check if vmware tools is running befor i do a stop-vm?

0 Kudos
tdubb123
Expert
Expert

the script is not getting out of the while loop

$vm is empty when all the vms are shutdown

Shutdown-VMGuest : 4/6/2019 7:08:36 PM Stop-VMGuest Operation "Shutdown VM guest." failed for VM "lxxxxxxxx" for the following reason: A general

system error occurred: Invalid fault

At line:12 char:8

+ $vms | Shutdown-VMGuest -Confirm:$false

+        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    + CategoryInfo          : NotSpecified: (:) [Stop-VMGuest], VimException

    + FullyQualifiedErrorId : Client20_VmGuestServiceImpl_ShutdownVmGuest_ViError,VMware.VimAutomation.ViCore.Cmdlets.Commands.StopVmGuest

Shutdown-VMGuest : 4/6/2019 7:08:36 PM Stop-VMGuest Operation "Shutdown VM guest." failed for VM "lxxxxxx" for the following reason: Cannot

complete operation because VMware Tools is not running in this virtual machine.

At line:12 char:8

+ $vms | Shutdown-VMGuest -Confirm:$false

+        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    + CategoryInfo          : NotSpecified: (:) [Stop-VMGuest], VimException

    + FullyQualifiedErrorId : Client20_VmGuestServiceImpl_ShutdownVmGuest_ViError,VMware.VimAutomation.ViCore.Cmdlets.Commands.StopVmGuest

Shutdown-VMGuest : 4/6/2019 7:08:36 PM Stop-VMGuest Operation "Shutdown VM guest." failed for VM "lxxxxxxxxx" for the following reason: Cannot

complete operation because VMware Tools is not running in this virtual machine.

At line:12 char:8

+ $vms | Shutdown-VMGuest -Confirm:$false

+        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    + CategoryInfo          : NotSpecified: (:) [Stop-VMGuest], VimException

    + FullyQualifiedErrorId : Client20_VmGuestServiceImpl_ShutdownVmGuest_ViError,VMware.VimAutomation.ViCore.Cmdlets.Commands.StopVmGuest

Shutdown-VMGuest : 4/6/2019 7:08:36 PM Stop-VMGuest Operation "Shutdown VM guest." failed for VM "xxxxxxxxx" for the following reason: Cannot

complete operation because VMware Tools is not running in this virtual machine.

At line:12 char:8

+ $vms | Shutdown-VMGuest -Confirm:$false

+        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    + CategoryInfo          : NotSpecified: (:) [Stop-VMGuest], VimException

    + FullyQualifiedErrorId : Client20_VmGuestServiceImpl_ShutdownVmGuest_ViError,VMware.VimAutomation.ViCore.Cmdlets.Commands.StopVmGuest

0 Kudos
LucD
Leadership
Leadership

The $vms variable will be an array when more than 1 VM is still powered on, so you can't use the -eq operator.

With the -contains operator you should be able to check if there is still a VM that is powered on.

Something like this

$DC = Read-Host "Enter the Datacenter to patch"

$vmhost = Get-VMHost -Location (Get-Datacenter $dc)

$vms = Get-Datacenter $dc | Get-VM | Where-Object { $_.powerstate -eq "Poweredon" }

$baseline = Get-Baseline -Server vc -Name *Critical*


if ($vms.PowerState -contains 'PoweredOn')

{

   $vms | Shutdown-VMGuest -Confirm:$false

   while ($vms.PowerState -contains 'PoweredOn')

   {

     Start-Sleep 5

     $vms = Get-VM -Name $vms.Name | Where-Object { $_.powerstate -eq "Poweredon" }

   }

}


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

0 Kudos
tdubb123
Expert
Expert

how do I check if a vm has vmware tools installed.

if not shut it down hard? does this look right?

$DC = Read-Host "Enter the Datacenter to patch"

$vmhost = Get-VMHost -Location (Get-Datacenter $dc)

$vms = Get-Datacenter $dc | Get-VM | Where-Object { $_.powerstate -eq "Poweredon" }

$baseline = Get-Baseline -Server vc -Name *Critical*

if ($vms.PowerState -contains 'PoweredOn' -and $vms.extensiondata.guest.toolsruningstatus -contains "guesttoolsRunning"){

$vms | Shutdown-VMGuest -Confirm:$false

while ($vms.PowerState -contains 'PoweredOn')

{

    Start-Sleep 5

    $vms = Get-VM -Name $vms.Name | Where-Object { $_.powerstate -eq "Poweredon" }

}

else

stop-vm -vm $vms -Confirm:$false -RunAsync

}

set-vmhost -VMHost $vmhost -State Maintenance -Confirm:$false

sleep 5

$baseline | Attach-Baseline -entity $vmhost -Confirm:$false

Scan-Inventory -Entity $vmhost

$baseline | Remediate-Inventory -Entity $vmhost -Confirm:$false -ErrorAction SilentlyContinue -RunAsync

0 Kudos
LucD
Leadership
Leadership

That will work in 99% of the cases, but I have come to learn that the guestOperationsReady property in the GuestInfo object is even better.
Especially if you are going to send anything to the guest OS through the VMware Tools (Stop-VMGuest, Invoke-VMScript...).


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

0 Kudos
tdubb123
Expert
Expert

I am trying to do this

$vms = get-vm -name ans*

if ($vms.PowerState -contains 'PoweredOn' -and $vms.extensiondata.guest.guestoperationsready ){

$vms | Shutdown-VMGuest -Confirm:$false

while ($vms.PowerState -contains 'PoweredOn')

{

Start-Sleep 5

$vms = Get-VM -Name $vms.Name | Where-Object { $_.powerstate -eq "Poweredon" }

}

else

stop-vm -vm $vms -Confirm:$false -RunAsync

}

2 of my vms with vmware tools got shutdown fine. but one of them dont have vmtools and is not getting shutdown

shouldnt the

stop-vm -vm $vms -Confirm:$false -RunAsync

stop the vm hard?

the script is hung

0 Kudos
LucD
Leadership
Leadership

It should, but try adding the Kill switch.

That helps when the VM is not responding.


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

0 Kudos
tdubb123
Expert
Expert

still not working

$vms = get-vm -name ans*

if ($vms.PowerState -contains 'PoweredOn' -and $vms.extensiondata.guest.guestoperationsready -eq "True" ){

$vms | Shutdown-VMGuest -Confirm:$false -WarningAction SilentlyContinue

while ($vms.PowerState -contains 'PoweredOn')

{

Start-Sleep 5

$vms = Get-VM -Name $vms.Name | Where-Object { $_.powerstate -eq "Poweredon" }

}

else

stop-vm -vm $vms -Confirm:$false -RunAsync -Kill

Capture.PNG}

0 Kudos
LucD
Leadership
Leadership

You seem to be missing a curly brace at the of the if-block and before the else-block.

$vms = get-vm -name ans*

if ($vms.PowerState -contains 'PoweredOn' -and $vms.extensiondata.guest.guestoperationsready -eq "True" )

{

   $vms | Shutdown-VMGuest -Confirm:$false -WarningAction SilentlyContinue

   while ($vms.PowerState -contains 'PoweredOn')

   {

   Start-Sleep 5

   $vms = Get-VM -Name $vms.Name | Where-Object { $_.powerstate -eq "Poweredon" }

   }

}

else

{

   Stop-VM -vm $vms -Confirm:$false -RunAsync -Kill

}


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

0 Kudos
tdubb123
Expert
Expert

I seem to be having a problem here

the host is patched and stays in maintenance mode but does not exit the loop and does not set the host back in connected state

do {

set-vmhost -VMHost $vmhost -State Maintenance -Confirm:$false

$State = (get-vmhost $vmhost).ConnectionState

$baseline | Attach-Baseline -entity $vmhost -Confirm:$false

Scan-Inventory -Entity $vmhost

$baseline | Remediate-Inventory -Entity $vmhost -Confirm:$false -ErrorAction SilentlyContinu

sleep 300

}

while ($State -eq "Maintenance")

#Write-Host "$vmhost is in Maintenance mode"

write-host "PAtching $vmhost"

set-vmhost -VMHost $vmhost -State Connected

0 Kudos
LucD
Leadership
Leadership

It depends what you have in $vmhost.
Is that a name or a VMHost object?
After the reboot, you will in any case need to get the VMHost object again.


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

0 Kudos