In the previous tip we implemented a timeout using PowerShell background jobs so you could set a maximum time some code was allowed to run before it raised an exception.

Here is a more lightweight alternative that uses in-process threads rather than out-of-process executables:

function Invoke-CodeWithTimeout
{
    param
    (
        [Parameter(Mandatory)]
        [ScriptBlock]
        $Code,

        [int]
        $Timeout = 5

    )

    $ps = [PowerShell]::Create()
    $null = $ps.AddScript($Code)
    $handle = $ps.BeginInvoke()
    $start = Get-Date
    do
    {
        $timeConsumed = (Get-Date) - $start
        if ($timeConsumed.TotalSeconds -ge $Timeout) {
            $ps.Stop()
            $ps.Dispose()
            throw "Job timed out."    
        }
        Start-Sleep -Milliseconds 300
    } until ($handle.isCompleted)
    
    $ps.EndInvoke($handle)
    $ps.Runspace.Close()
    $ps.Dispose()
}

And here is how to use the new timeout:

 
PS> Invoke-CodeWithTimeout -Code { Start-Sleep -Seconds 6; Get-Date } -Timeout 5
Job timed out.
At line:24 char:13
+       throw "Job timed out."
+       ~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : OperationStopped: (Job timed out.:String) [], RuntimeException
    + FullyQualifiedErrorId : Job timed out.
 

PS> Invoke-CodeWithTimeout -Code { Start-Sleep -Seconds 3; Get-Date } -Timeout 5

Thursday November 1, 2018 14:53:26
 

Twitter This Tip! ReTweet this Tip!

Anonymous