2017-08-02 28 views
1

我有与执行各种操作很多(20+)功能的一个相当大的PowerShell脚本。PowerShell中的try/catch和重试

现在所有的代码并没有真正的错误处理或重试功能。如果一个特定的任务/功能失败,它只会失败并继续。

我想改进错误处理并实施重试以使其更加健壮。

我想类似这样的东西:

$tries = 0 
while ($tries -lt 5) { 
    try{  

     # Do Something 

     # No retries necessary 
     $tries = 5; 
    } catch { 
     # Report the error 
     # Other error handling 
    } 
} 

的问题是,我有很多很多的步骤,我需要做到这一点。

我不认为这是有意义的实施上述代码20次。这似乎是多余的。

我在想用一个包含我想调用的函数的参数编写一个“TryCatch”函数?

虽然我不确定这是正确的方法。我最终不会得到一个类似如下的脚本:

TryCatch "Function1 Parameter1 Parameter2" 
TryCatch "Function2 Parameter1 Parameter2" 
TryCatch "Function3 Parameter1 Parameter2" 

有没有更好的方法来做到这一点?

回答

3

如果您经常需要一个重试动作的次数,你可以换码的循环在功能try..catch,并在脚本块传递命令:

function Retry-Command { 
    [CmdletBinding()] 
    Param(
     [Parameter(Position=0, Mandatory=$true)] 
     [scriptblock]$ScriptBlock, 

     [Parameter(Position=1, Mandatory=$false)] 
     [int]$Maximum = 5 
    ) 

    Begin { 
     $cnt = 0 
    } 

    Process { 
     do { 
      $cnt++ 
      try { 
       $ScriptBlock.Invoke() 
       return 
      } catch { 
       Write-Error $_.Exception.InnerException.Message -ErrorAction Continue 
      } 
     } while ($cnt -lt $Maximum) 

     # Throw an error after $Maximum unsuccessful invocations. Doesn't need 
     # a condition, since the function returns upon successful invocation. 
     throw 'Execution failed.' 
    } 
} 

调用该函数是这样的(默认值是5重试):

Retry-Command -ScriptBlock { 
    # do something 
} 

或像这样(如果你需要在某些情况下,不同量的重试):

Retry-Command -ScriptBlock { 
    # do something 
} -Maximum 10 

的功能可以进一步例如改善的通过使脚本终止后$Maximum失败的尝试配置另一个参数,这样就可以有有将导致脚本停止时,他们失败的行动,以及它的失败可以忽略不计的动作。

+0

经过测试,看起来好像有$ ScriptBlock.Invoke(),如果有一个错误没有被捕获。使用写主机语句,我确认了正在调用retry-command,使其进入do循环,使其进入try循环,但我故意将数据输入到我的scriptblock中,这会导致错误,但没有发现错误 – Brad

+0

我的脚本块如下所示:Invoke-Sqlcmd -Query“DELETE FROM This_Table_Does_NOT_Exist”-ServerInstance mydbserver -Database TestDB。如果我从脚本外部运行该命令,则会发生错误:Invoke-Sqlcmd:无效的对象名称'This_Table_Does_NOT_Exist'。 – Brad

+0

该错误似乎是[非终止错误](https://blogs.technet.microsoft.com/heyscriptingguy/2015/09/16/understanding-non-terminating-errors-in-powershell/)。尝试在'Invoke-Sqlcmd'语句中添加'-ErrorAction Stop'。 –

0

错误处理总是会添加更多的脚本,因为它通常必须处理许多不同的事情。如果您想让每个函数都有多次尝试,Try Catch函数可能对您上面描述的内容最有效。自定义功能将允许你甚至在值每次路过设置之类的尝试之间的睡眠定时器,或改变功能多少会尝试尝试。

+0

您可能还需要弄清楚为什么你需要重试步骤5倍。无论如何,有trycatch功能也将创建日志输出的好地方,也许那种了... – brendan62269

+0

它主要是一个预防措施。所以我们试图覆盖一些错误场景: 1)这是一个终端错误(我们应该退出) 2)这是一个非终端错误,我们应该继续但警告错误 3)这是一个临时错误(将重试帮助?)。一个例子可能是我们试图针对尚未完全启动的VM或云实例运行操作。在这种情况下,等待和重试是一个很好的选择。尽管最终它应该放弃。 – Brad

0

解决方案与通过一个委托到一个函数,而不是脚本块:

function Retry([Action]$action) 
{ 
    $attempts=3  
    $sleepInSeconds=5 
    do 
    { 
     try 
     { 
      $action.Invoke(); 
      break; 
     } 
     catch [Exception] 
     { 
      Write-Host $_.Exception.Message 
     }    
     $attempts-- 
     if ($attempts -gt 0) { sleep $sleepInSeconds } 
    } while ($attempts -gt 0)  
} 

function MyFunction($inputArg) 
{ 
    Throw $inputArg 
} 

#Example of a call: 
Retry({MyFunction "Oh no! It happend again!"})