问题
Here is the scenario - I'm remotely starting a VM via Powershell/PowerCLI (VMwares Powershell module) and once the VM is started I will be running a series of cmdlets against the VM.
Currently I have this bit of code:
Start-VM "my VM Name" -runAsync
$vm = Get-VM | where { $_.name -eq "my VM Name" }
start-sleep -seconds 20
do {
start-sleep -seconds 5
$toolsStatus = ($VM | Get-View).Guest.ToolsStatus
} until ($toolsStatus -eq 'toolsOK')
Which works - the VM starts and the loop will check until VMware Tools is reporting in to VMware (which means the VM has fully booted into the OS).
However this will run indefinitely and so in a scenario where the VM fails to boot successfully - the script hangs. So I've tried to add in a timer to exit the script if it runs passed by 5 Minutes:
Start-VM "My VM Name" -runAsync
$VM = Get-VM | where { $_.name -eq "My VM Name" }
$timeout = new-timespan -minutes 5
start-sleep -seconds 5
$toolsStatus = ($VM | Get-View).Guest.ToolsStatus
$sw = [diagnostics.stopwatch]::StartNew()
while ($sw.elapsed -lt $timeout) {
if ($toolsStatus -eq 'toolsOK') {
return
}
start-sleep -seconds 5
}
Exit
Which successfully exits the script after 5 minutes. The issue is whilst I'm testing this - the VM has booted and I'm getting a response indicating that VMtools has responded, but the loop isn't stopping. It's continuing till it has timed-out then exiting as opposed to proceeding to the next step.
I've not worked with this type of loop before so would appreciate some input as I'm sure I'm close - but I've missed something.
回答1:
You're not updating $toolsStatus
in your loop, hence it never exits even though the VM has booted. Just move the check inside your loop.
Start-VM "My VM Name" -runAsync
$VM = Get-VM | where { $_.name -eq "My VM Name" }
$timeout = new-timespan -minutes 5
start-sleep -seconds 5
$sw = [diagnostics.stopwatch]::StartNew()
while ($sw.elapsed -lt $timeout) {
$toolsStatus = ($VM | Get-View).Guest.ToolsStatus
if ($toolsStatus -eq 'toolsOK') {
return
}
start-sleep -seconds 5
}
Exit
回答2:
Should be just a simple logical fix. In your final while
loop, add both expressions with an -and
and negate the $toolStatus
while ($sw.elapsed -lt $timeout -and $toolsStatus -ne 'toolsOK'){
start-sleep -seconds 5
}
When one becomes false, the loop will end.
回答3:
VMWare already has a command for wait.
Start-VM "My VM Name" -runAsync
$VM = Get-VM | where { $_.name -eq "My VM Name" } | Wait-Tools -TimeoutSeconds 180
https://www.vmware.com/support/developer/PowerCLI/PowerCLI41U1/html/Wait-Tools.html
I've read about VMTools running and the OS not being started problems. As soon as the Windows logo appears VMTools seems to report as running, this can cause issues. I prefer to use a Powershell command to ping the machine until I get a response.
$thisisaddress = (Get-NetIPAddress | where {$_.AddressFamily -eq "IPv4" -and $_.InterfaceAlias -eq "Ethernet"}).ipaddress
$pingMachine = New-Object System.Net.NetworkInformation.Ping
$timeout = new-timespan -Minutes 1
$sw = [diagnostics.stopwatch]::StartNew()
while ($sw.elapsed -lt $timeout -and $pingStatus.Status -ne 'Success'){
$pingStatus = $pingMachine.Send($thisisaddress)
$pingStatus
}
来源:https://stackoverflow.com/questions/42640113/powershell-powercli-loop-timeouts-and-exits