invoke-JobWithRetry.ps1

<#PSScriptInfo
 
.VERSION 1.0
 
.GUID 07e4f49b-0836-47c7-9096-dcdf5e44004b
 
.AUTHOR Jeffrey Snover
 
.COMPANYNAME Microsoft
 
.COPYRIGHT
 
.TAGS
 
.LICENSEURI
 
.PROJECTURI
 
.ICONURI
 
.EXTERNALMODULEDEPENDENCIES
 
.REQUIREDSCRIPTS
 
.EXTERNALSCRIPTDEPENDENCIES
 
.RELEASENOTES
 
 
#>


<#
 
.DESCRIPTION
 Invoke a scriptblock that may hang and need to be stopped and retried a number of times
 
#>
 
[CmdletBinding()]
param
(
    [Parameter(Mandatory=$true)]
    [scriptblock]
    $ScriptBlock,

    # How long a single scriptblock is allowed to run before being stopped/retried
    [Parameter()]
    $TimeoutPerTry = 30,

    # How long the function can run, in seconds, trying the ScriptBlock in a loop before returning.
    [Parameter()]
    $TotalTryTime = 120,

    # Number of seconds time to sleep between retries
    [Parameter()]
    $PauseBetweenRetries = 0
)

$trycount = 1
$stopwatch = [System.Diagnostics.Stopwatch]::StartNew()
do
{
    $job = Start-Job -ScriptBlock $ScriptBlock
    $completedJob = Wait-Job -Job $job -Timeout $TimeoutPerTry
    if ($completedJob.State -eq 'Completed')
    {
        $output = Receive-Job -Job $completedJob
        Remove-Job -Job $completedJob
        return $output
    }
    else
    {
        Stop-Job -Job $job
        Remove-Job -Job $job
        Write-Verbose "Invoke-JobWithRetry: Try $tryCount did not complete"
        $tryCount++
        Start-Sleep -Seconds $PauseBetweenRetries
    }
}
until ($stopwatch.Elapsed.TotalSeconds -ge $TotalTryTime)

if ($completedJob.State -eq 'Failed')
{
    Trace-Error -Message $completedJob.ChildJobs[0].JobStateInfo.Reason
}
elseif (-not $completedJob)
{
    Write-Error -Message "Job failed, reason: the task did not complete within $TotalTryTime seconds."
}