Home > OS >  Adding Time out section in powershell script
Adding Time out section in powershell script

Time:05-03

I am trying to test Time out after 30 seconds.

Sample code:

$a = "y"
$b = "n"
$timeout = New-TimeSpan -Seconds 30
$stopwatch = [System.Diagnostics.Stopwatch]::StartNew()
$stopwatch.Start()
$timeout.Seconds
$stopwatch.elapsed.Seconds
do{

    if($a -eq "n"){
        Write-Host "This block will never run"
        break
    }

    if($stopwatch.elapsed.Seconds -lt $timeout.Seconds){
        Write-Host "Testing this block: Time OUT!!"
        break
    }

}while($a -eq $b)

$stopwatch.Stop()

But the if block if($stopwatch.elapsed.Seconds -lt $timeout.Seconds) is true even $stopwatch.elapsed.Seconds value is 0 and $timeout.Seconds value is 30 in the loop and complete the code in few milliseconds and not taking 30 seconds to print the Time out statement.

Could anyone please give me pointer to resolve this issue.

CodePudding user response:

A couple of things:

  • You don't need these two lines: $timeout.Seconds and $stopwatch.elapsed.Seconds above the loop
  • Your while condition should be while($a -ne $b)
  • The test inside the loop should read if($stopwatch.elapsed.Seconds -ge $timeout.Seconds)

Try

$a = "y"
$b = "n"
$timeout = New-TimeSpan -Seconds 30
$stopwatch = [System.Diagnostics.Stopwatch]::new()
$stopwatch.Start()
do {
    if($stopwatch.Elapsed.Seconds -ge $timeout.Seconds){
        Write-Host "Testing this block: Time OUT!!"
        break
    }
    # no timeout, so proceed with what needs to be done here
    # . . .
} while($a -ne $b)  # loop forever unless you set $a equal to $b in the loop somewhere

$stopwatch.Stop()

CodePudding user response:

Theo's helpful answer addresses incidental logic problems with your approach and offers a solution that probably will work, but isn't fully robust: If the activity in your loop exceeds 1 minute before the timeout condition is tested, the test won't work as intended (even with the logic problems fixed).

You have two options:

  • Use .TotalSeconds instead of .Seconds, for the reasons explained below.

  • More simply, taking advantage of the fact that [timespan] instances are directly comparable (see below), you can use:

    if ($stopwatch.elapsed -gt $timeout) { # ... 
    

As zett42 points out, [timespan] instances are directly comparable, due to implementing the .NET System.IComparable interface (as well as its generic counterpart); e.g.:

   # -> $true - a timespan representing a 61-second duration 
   #            is greater than one representing a 60-second (1-minute) duration.
   [timespan]::FromSeconds(61) -gt [timespan] '00:01:00'

Therefore, as shown in the top section, you can simply directly compare $stopwatch.elapsed and $timeout - both of which are [timespan] instances.

The .Seconds property of a [timespan] instance is only the seconds component, potentially alongside larger units, such as minutes (.Minutes) and hours (.Hours)

You need the .TotalSeconds property to get the total amount of seconds (analogously, there are also .TotalDays, .TotalHours, and .TotalMinutes properties).

Also note that .Seconds is always a whole number ([int]), whereas .TotalSeconds can be a fractional value ([double]).

To illustrate the difference:

PS> [timespan] '00:01:05' | # 1 minute and 5 seconds 
      Select-Object Seconds, TotalSeconds

Seconds TotalSeconds
------- ------------
      5           65

CodePudding user response:

@sivam The issue is-

  • You're not applying the proper properties of the timespan command if it goes beyond 59 seconds then at 60 seconds it will consider it 1 minute.
  • Update the condition inside the loop if($stopwatch.elapsed.Seconds -lt $timeout.Seconds)

Try

$a = "y"
$b = "n"
$timeout = New-TimeSpan -Minutes 1
$stopwatch = [System.Diagnostics.Stopwatch]::StartNew()
$stopwatch.Start()
$timeout.Minutes
$stopwatch.elapsed.Minutes
do{
    if($a -eq "n"){
        Write-Host "This block will never run"
        break
    }
    if($stopwatch.elapsed.Minutes -ge $timeout.Minutes){
        Write-Host "Time OUT!!"
        break
    }
}while($a -ne $b)
$stopwatch.Stop()
  • Related