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?
$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.
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
$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
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?
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
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?
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
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
$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
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
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
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
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
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
}
You seem to be missing a curly brace at the of the if-block and before the else-block.
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
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
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