Invoking arbitrary PowerShell commands with retries in PowerShell

1 minute read

Yesterday I blogged about a function I created to execute arbitrary shell (cmd) commands in PowerShell, with retries in face of failures. But what if the command I want to execute is actually another PowerShell script (or function, or cmdlet)? The rules change a bit:

  • We need to use splatting when making the call (otherwise named parameters won’t work, see the references below).
  • In addition to splatting the call itself, we also need to format the argument hash table for printing the command (otherwise it would just print something like Executing: Foo.ps1 System.Collections.Hashtable).
  • $LASTEXITCODE is no longer (necessarily) relevant, we need to work with PowerShell’s $? automatic variable.
  • Parsing the error stream makes less sense, but we need to handle exceptions.

Here’s how it looks:

Invokes a command with retries.

The Call-PSCommandWithRetries function invokes PowerShell scripts, functions, or Cmdlets using the provided parameters, with optional retries in configurable intervals upon failures.

The command to invoke. Can be any PowerShell script, function, or Cmdlet.

.PARAMETER Arguments
Arguments to pass when invoking the comand (using splatting). 

.PARAMETER RetrySleepSeconds
Time in seconds to sleep between retry attempts in case of command failure.

.PARAMETER MaxAttempts
Maximum number of retry attempts in case of command failure.

.PARAMETER PrintCommand
Determines whether or not to print the full command to the host before execution.

None. You cannot pipe objects to Call-PSCommandWithRetries.

The output of the last command execution.

$output = Call-PSCommandWithRetries "dir" @{"Path"='C:\'}

function Call-PSCommandWithRetries
    [int]$RetrySleepSeconds = 10,
    [int]$MaxAttempts = 10,
    [bool]$PrintCommand = $True

  $attempt = 0
  while ($true)
   $formattedArgs = $Arguments.Keys.ForEach({"-$($_):$($Arguments.$_)"}) -join ' '
   Write-Host $(if ($PrintCommand) {"Executing: $Command $formattedArgs"} else {"Executing PS command..."}) 
   $exceptionThrown = $false
    & $Command @Arguments 2>&1 | tee -Variable output | Write-Host
    Write-Host "PS command threw exception: $($_.Exception)" -ForegroundColor Yellow
    $exceptionThrown = $true
   if ($? -and !($exceptionThrown))
    Write-Host "PS Command executed successfully"
    return $output
   Write-Host "PS Command failed" -ForegroundColor Yellow
   if ($attempt -eq $MaxAttempts)
    $ex = new-object System.Management.Automation.CmdletInvocationException "All retry attempts exhausted"
    $category = [System.Management.Automation.ErrorCategory]::LimitsExceeded
    $errRecord = new-object System.Management.Automation.ErrorRecord $ex, "CommandFailed", $category, $Path
    return $output
   Write-Host "Retrying test execution [#$attempt/$MaxAttempts] in $RetrySleepSeconds seconds..."
   Start-Sleep -s $RetrySleepSeconds


Leave a Comment