2

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.

codersl
  • 2,222
  • 4
  • 30
  • 33
TheDemonLord
  • 327
  • 1
  • 2
  • 15

3 Answers3

1

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.

SomeShinyObject
  • 7,581
  • 6
  • 39
  • 59
1

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
}
user3520245
  • 1,016
  • 1
  • 8
  • 18
  • I didn't realise that existed! For this issue - I've implemented your solution as it's much more elegant and graceful. However I've marked the other answer as correct as it addressed the syntax/logical error in my original script (which I feel is more helpful for others struggling with timeout loops) – TheDemonLord Mar 07 '17 at 20:38
  • Your search for VM is quite slow. Sorry it looks poor. Try these Measure-Command {Get-VM | where{$_.name -eq "yourvmname"}} TotalSeconds : 18.5221952 Measure-Command {Get-VM -name yourvmname} TotalSeconds : 6.229672 Measure-Command {Get-view -viewtype VirtualMachine -filter @{"name" = "yourvmname"}} TotalSeconds : 1.2584678 Measure-Command {Get-view -viewtype VirtualMachine -property name -filter @{"name" = "yourvmname"}} TotalSeconds : 1.2559065 – user3520245 Mar 08 '17 at 08:46
0

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
codersl
  • 2,222
  • 4
  • 30
  • 33