我有一个相当大的powershell脚本,它有许多(20+)函数,它们执行各种操作。
现在,所有的代码都没有任何错误处理或重试功能。如果一个特定的任务/函数失败了,它就会失败并继续运行。
我想改进错误处理和实现重试,以使它更加健壮。
我在想一些类似的事情:
$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"有更好的方法吗?
发布于 2017-08-02 23:06:04
如果经常需要多次重试操作的代码,则可以将循环的try..catch封装在函数中,并在scriptblock中传递命令:
function Retry-Command {
[CmdletBinding()]
Param(
[Parameter(Position=0, Mandatory=$true)]
[scriptblock]$ScriptBlock,
[Parameter(Position=1, Mandatory=$false)]
[int]$Maximum = 5,
[Parameter(Position=2, Mandatory=$false)]
[int]$Delay = 100
)
Begin {
$cnt = 0
}
Process {
do {
$cnt++
try {
# If you want messages from the ScriptBlock
# Invoke-Command -Command $ScriptBlock
# Otherwise use this command which won't display underlying script messages
$ScriptBlock.Invoke()
return
} catch {
Write-Error $_.Exception.InnerException.Message -ErrorAction Continue
Start-Sleep -Milliseconds $Delay
}
} 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失败尝试之后使用另一个参数进行可配置的脚本终止,这样您就可以拥有将导致脚本在失败时停止的操作,以及可以忽略其失败的操作。
发布于 2019-08-14 23:30:41
我改写了维克多的回答,并补充道:
sleep替换为Start-Sleep)# [Solution with passing a delegate into a function instead of script block](https://stackoverflow.com/a/47712807/)
function Retry()
{
param(
[Parameter(Mandatory=$true)][Action]$action,
[Parameter(Mandatory=$false)][int]$maxAttempts = 3
)
$attempts=1
$ErrorActionPreferenceToRestore = $ErrorActionPreference
$ErrorActionPreference = "Stop"
do
{
try
{
$action.Invoke();
break;
}
catch [Exception]
{
Write-Host $_.Exception.Message
}
# exponential backoff delay
$attempts++
if ($attempts -le $maxAttempts) {
$retryDelaySeconds = [math]::Pow(2, $attempts)
$retryDelaySeconds = $retryDelaySeconds - 1 # Exponential Backoff Max == (2^n)-1
Write-Host("Action failed. Waiting " + $retryDelaySeconds + " seconds before attempt " + $attempts + " of " + $maxAttempts + ".")
Start-Sleep $retryDelaySeconds
}
else {
$ErrorActionPreference = $ErrorActionPreferenceToRestore
Write-Error $_.Exception.Message
}
} while ($attempts -le $maxAttempts)
$ErrorActionPreference = $ErrorActionPreferenceToRestore
}
# function MyFunction($inputArg)
# {
# Throw $inputArg
# }
# #Example of a call:
# Retry({MyFunction "Oh no! It happened again!"})
# Retry {MyFunction "Oh no! It happened again!"} -maxAttempts 10发布于 2017-12-08 10:50:06
将委托传递给函数而不是脚本块的解决方案:
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!"})https://stackoverflow.com/questions/45470999
复制相似问题