3

I tried this code but only file1.txt gets created. File2.txt does not. I'm looking for the built-in way to use timeouts. So not by creating custom loops.

Out-File "file1.txt"                  #this file is created

$Job = Start-Job -ScriptBlock {            
        Out-File "file2.txt"          #this file is not created
}
$Job | Wait-Job -Timeout 5
$Job | Stop-Job
Ferro
  • 1,863
  • 2
  • 14
  • 20

2 Answers2

7

I have finally found the solution. The Start-Job script starts in a default home folder, different from the script location. So it works if I use an absolute path. I like this code much better than custom made loops:

Start-Job {                
    Out-File "C:\file2.txt"
} | Wait-Job -Timeout 3

Ferro
  • 1,863
  • 2
  • 14
  • 20
0

Using a function called Wait-Action that incorporates all of this functionality into a PowerShell function, download it from the PowerShell Gallery:

Install-Script -Name Wait-Action

To add a timeout feature to a PowerShell script requires a few different tasks:

Start a timer Invoke some piece of code Check the code's status every so often If timeout is exceeded, have PowerShell do something If timeout is not exceeded, continue with the script Stop the timer

The first thing we need to do is define a timeout. Most often, a timeout in seconds will work. I want to ensure my code doesn't last for more than 10 seconds, so I'll set a variable for that.

$Timeout = 10 ## seconds

Next, I'll need to take whatever code I want to wait on and add it to a scriptblock. For this example, imagine I've created a few background jobs further up the script. I'd like to wait until all of these jobs are completed before continuing.

$jobs = Get-Job
 $Condition = {param($jobs) 'Running' -not in $jobs.State }
 $ConditionArgs = $jobs

Next, I need to define how long in between checks my script should perform the task.

$RetryInterval = 5 ## seconds

Now I'll start the timer.

## Start the timer
 $timer = [Diagnostics.Stopwatch]::StartNew()

Now that the timer is started, I can now invoke that piece of code I need to be done.

## Start checking the condition scriptblock. Do this as long as the action hasn't exceeded
 ## the timeout or the condition scriptblock returns something other than $false or $null.
 while (($timer.Elapsed.TotalSeconds -lt $Timeout) -and (& $Condition $ConditionArgs)) {

     ## Wait a specific interval
     Start-Sleep -Seconds $RetryInterval

     ## Check the time
     $totalSecs = [math]::Round($timer.Elapsed.TotalSeconds,0)
     Write-Verbose -Message "Still waiting for action to complete after [$totalSecs] seconds..."
 }

Once the timeout has been exceeded, or the task has completed, I'll then need to stop the timer.

## The action either completed or timed out. Stop the timer.
 $timer.Stop()

Now I can check to see if the timeout was exceeded or if the task completed on its own. Here, I'm throwing in an exception indicating that the action did not complete if the timeout stopped it. Otherwise, I'm just writing out a verbose statement that any code can follow after that.

## Return status of what happened
 if ($timer.Elapsed.TotalSeconds -gt $Timeout) {
     throw 'Action did not complete before timeout period.'
 } else {
     Write-Verbose -Message 'Action completed before the timeout period.'
 }
S.Abishek
  • 23
  • 3