【问题标题】:How to continuously try something in powershell until it succeeds?如何在PowerShell中不断尝试某些东西直到成功?
【发布时间】:2019-02-23 11:56:27
【问题描述】:

使用基本构造:

try
{
    Do-Something
}
catch
{
    Write-Output "Something threw an exception"
}

是否可以继续尝试 Do-Something 直到成功?也许使用这样的while循环:

$Timeout = 60
$timer = [Diagnostics.Stopwatch]::StartNew()
$t = 0
while (($timer.Elapsed.TotalSeconds -lt $Timeout) -and ($t -ne 1))) {
    Start-Sleep -Seconds 1
    try
    {
        Do-Something
        $t = 1
    }
    catch
    {
        Write-Output "Something threw an exception"
    }
}
$timer.Stop()

这里我使用了一个计时器来确保 PowerShell 不会无限期地运行。 它应该继续尝试直到try 成功并且$t = 1 被执行。但是,它在大约 2 秒内失败。请帮忙。

更具体地说,做某事是:

(Get-Process -Name FineReader).MainWindowHandle

我希望代码继续尝试,直到FineReader 存在并且它可以获得MainWindowHandle

【问题讨论】:

  • $t 的目的是什么?它立即退出,因为您的条件失败,您需要计时器小于 60 并且 $t 不等于 1,但在第一次迭代中您将 $t 设置为 1 ,所以循环退出。
  • @arco444 我认为当Do-Something 失败时循环会失败,并且在Do-Something 成功之前它不会执行$t = 1

标签: windows powershell scripting powershell-3.0 powershell-4.0


【解决方案1】:

你可以使用break关键字。

# Set the erroracton preference to stop when an error occurs,
$ErrorActionPreferenceBak = $ErrorActionPreference
$ErrorActionPreference    = 'Stop'

While($True){
    try{
        Do-Something
        break
    }
    catch{
        Write-Output "Something failed"
        Start-Sleep -Seconds 1 # wait for a seconds before next attempt.
    }
    finally{
        #Reset the erroracton preference
        $ErrorActionPreference = $ErrorActionPreferenceBak
    }
}

【讨论】:

  • 谢谢!您的建议也适用于我的补充说明(请参阅问题)!
  • 我唯一做的就是把第一行改成:$ErrorActionPreferenceBak = 1
【解决方案2】:

您的Do-Something 应使用开关-ErrorAction Stop 调用,以发出可被try 捕获的终止异常

为此,您还需要将函数绑定为 CmdLet。例如:

function DoSomething {
    [CmdLetBinding()]
    Param(
    )

    # Your code

}

然后使用-ErrorAction Stop 开关调用您的函数:

try {
    Do-Something -ErrorAction Stop
}

如果您的 DoSomething 不是函数而是现有的 powershell CmdLet,那么...您猜对了,只需使用 -ErrorAction Stop 调用它

您可以在 powershell here 中了解有关 try/catch/finally 的更多信息

【讨论】:

  • -ErrorAction Stop 可用于 cmdlet,如果 Do-SomeThing 是一个函数,则必须明确完成错误处理功能。
【解决方案3】:

假设您的函数在 10 次调用中有 9 次失败:

function Get-RandomFail{
    $value = [Random]::new().Next(10);
    if ($value -ne 5) { throw }
    return $value
}

你想限制时间窗口,你可以使用以下:

function Try-Invoke{
    [CmdletBinding()]
    param(
        $Action,
        $MaxSeconds,
        $Delay=1
    )
    $timeout = [timespan]::FromSeconds($MaxSeconds)
    $start = [DateTime]::Now
    do {
        try {
            return &$Action
        } catch {
            Write-Verbose "Error"
        }
        Start-Sleep -Seconds $Delay
    } until (([DateTime]::Now - $start) -gt $timeout)
    throw
}

$result = Try-Invoke {Get-RandomFail} -MaxSeconds 5 -Verbose

Get-RandomFail 将被调用,直到没有错误发生或直到时间结束。您还可以使用Delay 参数在每次不成功的Get-RandomFail 调用后修改睡眠时间。

【讨论】:

    猜你喜欢
    • 2021-02-12
    • 2016-09-27
    • 2010-12-07
    • 2013-09-08
    • 2015-10-20
    • 2022-01-17
    • 1970-01-01
    • 2012-12-18
    • 2016-10-08
    相关资源
    最近更新 更多