Te recomendamos que pruebes esta respuesta en un ambiente controlado antes de enviarlo a producción, saludos.
Solución:
Si con frecuencia necesita un código que vuelva a intentar una acción varias veces, puede envolver su bucle try..catch
en una función y pase el comando en un 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
$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.'
Invoque la función de esta manera (el valor predeterminado es 5 reintentos):
Retry-Command -ScriptBlock
# do something
o así (si necesita una cantidad diferente de reintentos en algunos casos):
Retry-Command -ScriptBlock
# do something
-Maximum 10
La función podría mejorarse aún más, por ejemplo, haciendo la terminación del script después de $Maximum
intentos fallidos configurables con otro parámetro, de modo que puede tener acciones que harán que el script se detenga cuando fallan, así como acciones cuyas fallas pueden ignorarse.
Adapté la respuesta de @Victor y agregué:
- parámetro para reintentos
- ErrorAction establecido y restaurado (o de lo contrario, las excepciones no quedan atrapadas)
- retraso de retroceso exponencial (sé que el OP no pidió esto, pero lo uso)
- se deshizo de las advertencias de VSCode (es decir, reemplazó
sleep
conStart-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
Solución con pasar un delegado a una función en lugar de un bloque de script:
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!")
Te mostramos reseñas y calificaciones
Si para ti ha sido de ayuda nuestro post, agradeceríamos que lo compartas con más seniors así contrubuyes a difundir esta información.