Skip to content

Instantly share code, notes, and snippets.

@Jaykul
Created January 20, 2021 17:55
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Jaykul/54a213dd2db42406a8a69c9666394d44 to your computer and use it in GitHub Desktop.
Save Jaykul/54a213dd2db42406a8a69c9666394d44 to your computer and use it in GitHub Desktop.
There are so many ways to write this...
function Invoke-WithRetry {
<#
.SYNOPSIS
Invoke a ScriptBlock until it returns a value (or until a certain ammount of time elapses)
.DESCRIPTION
Invokes the given ScriptBlock on $RetryEvery interval until it returns a value.
If the $Limit time passes without a value, returns nothing.
.EXAMPLE
$Time = (Get-Date).AddMinutes(0.5)
Invoke-WithRetry { if($Time -lt (Get-Date)) { return $Time } }
Runs a simple ScriptBlock until it returns a value
.EXAMPLE
$Time = (Get-Date).AddMinutes(0.5)
Invoke-WithRetry { if($Time -lt (Get-Date)) { return $Time } } -Activity "Wait for $Time" -Limit "0:0:15"
Runs the script with progress output and a shorter time limit (which will expire without returning a value)
#>
[CmdletBinding()]
param(
# The code you want to run in a retry loop
# This script block MUST have output on success, and no output otherwise.
# You can Write to streams, but not Output unless you have success.
[Parameter(Mandatory)]
[ScriptBlock]
$ScriptBlock,
# A label for progress messages. If set, Invoke-WithRetry will Write-Progress after each failed attempt.
[string]
$Activity,
# The maximum amount of time to wait. Default is 10 minutes: "0:10"
[timespan]
$Limit = "0:10",
# The minimum amount of time between tries. Default is 5 seconds: "0:0:5"
[timespan]
$RetryEvery = "0:0:5"
)
$ShowProgress = $PSBoundParameters.ContainsKey("Activity")
$Stopwatch = [System.Diagnostics.Stopwatch]::new()
$Stopwatch.Start()
$Result = $null
$Count = 0
try {
do {
$Result = & $ScriptBlock
if (!$Result ) {
$Count++
if ($ShowProgress) {
Write-Progress -Activity $Activity -Status "Attempted $Count time(s). Waiting $RetryEvery to try again." -SecondsRemaining ($Limit - $Stopwatch.Elapsed).TotalSeconds
}
Start-Sleep -Milliseconds $RetryEvery.TotalMilliseconds
}
} while (!$Result -and $Stopwatch.Elapsed -lt $Limit)
$Result
} finally {
$Stopwatch.Stop()
if ($ShowProgress) {
Write-Progress -Activity $Activity -Completed
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment