如果失败并显示特定错误消息,请重试 PowerShell 脚本 (.ps1)

Retry PowerShell script (.ps1) if failing with specific error message

我们有一个 PowerShell 构建脚本(Cake 引导程序)偶尔无法 download/restore nuget 包。我将如何创建一个通用的 .ps1 脚本,该脚本可用于调用另一个 .ps1 脚本,如果失败则重试并且输出包含特定字符串(我不想重试如果这是一个构建错误)?

可能的用法示例:

.\ExecuteWithRetry.ps1 -Script "Build.ps1 -target Restore" -OutputTrigger "RemoteException"

创建了一个可以解决问题的脚本。

用法示例:

./Execute-With-Retry.ps1 -RetryDelay 1 -MaxRetries 2 { & ./Build.ps1 -target Restore } -RetryFilter RemoteException

基于this gist from Alex Bevilacqua.

<#
This script can be used to pass a ScriptBlock (closure) to be executed and returned.

The operation retried a few times on failure, and if the maximum threshold is surpassed, the operation fails completely.

Params:
    Command         - The ScriptBlock to be executed
    RetryDelay      - Number (in seconds) to wait between retries
                      (default: 5)
    MaxRetries      - Number of times to retry before accepting failure
                      (default: 5)
    VerboseOutput   - More info about internal processing
                      (default: false)

    RetyFilter      - Only retry if retry filter value is contained in the command output

Examples:

./Execute-With-Retry.ps1 -RetryDelay 1 -MaxRetries 2 { & ./Build.ps1 -target Restore } -RetryFilter RemoteException

#>
param(    
  [Parameter(ValueFromPipeline, Mandatory)]
  $Command,    
  $RetryDelay = 5,
  $MaxRetries = 5,
  $VerboseOutput = $false,
  $RetryFilter
)

$currentRetry = 0
$success = $false
$cmd = $Command.ToString()

do {
  try {
    $result = & $Command
    $success = $true
    if ($VerboseOutput -eq $true) {
      $Host.UI.WriteDebugLine("Successfully executed [$cmd]")
    }

    return $result
  }
  catch [System.Exception] {
    $currentRetry = $currentRetry + 1

    $exMessage = $_.Exception.Message;
    if ($RetryFilter -AND !$exMessage.Contains($RetryFilter)) {
      throw $exMessage
    }

    if ($VerboseOutput -eq $true) {
      $Host.UI.WriteErrorLine("Failed to execute [$cmd]: " + $_.Exception.Message)
    }

    if ($currentRetry -gt $MaxRetries) {                
      throw "Could not execute [$cmd]. The error: " + $_.Exception.ToString()
    }
    else {
      if ($VerboseOutput -eq $true) {
        $Host.UI.WriteDebugLine("Waiting $RetryDelay second(s) before attempt #$currentRetry of [$cmd]")
      }
      Start-Sleep -s $RetryDelay
    }
  }
} while (!$success);