Windows 如何在powershell中不断尝试,直到成功?

Windows 如何在powershell中不断尝试,直到成功?,windows,powershell,scripting,powershell-3.0,powershell-4.0,Windows,Powershell,Scripting,Powershell 3.0,Powershell 4.0,使用基本构造: try { Do-Something } catch { Write-Output "Something threw an exception" } 是否有可能继续尝试,直到成功?也许使用这样的while loopp: $Timeout = 60 $timer = [Diagnostics.Stopwatch]::StartNew() $t = 0 while (($timer.Elapsed.TotalSeconds -lt $Timeout) -and ($

使用基本构造:

try
{
    Do-Something
}
catch
{
    Write-Output "Something threw an exception"
}
是否有可能继续尝试,直到成功?也许使用这样的while loopp:

$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
您的
执行某些操作
应使用开关
-ErrorAction Stop
调用,以便发出可被
try
捕获的终止异常

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

function DoSomething {
    [CmdLetBinding()]
    Param(
    )

    # Your code

}

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

try {
    Do-Something -ErrorAction Stop
}

如果您的
DoSomething
不是函数,而是现有的powershell CmdLet,则。。。你猜对了,只要用
-ErrorAction Stop


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

您可以使用
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
    }
}

假设您的函数在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
调用。

调用
$t
的目的是什么?它会立即退出,因为您的条件失败,您需要计时器小于60并且
$t
不等于
1
,但在第一次迭代时,您将
$t
设置为
1
,因此循环退出。@arco444我认为当
执行某件事失败时,循环将失败,并且在
执行某件事成功之前,循环将无法执行
$t=1
-ErrorAction Stop
可用于cmdlet,如果
执行某件事
是一个函数,错误处理功能必须明确完成。谢谢!您的建议与我的补充澄清(见问题)也起到了作用!我所做的唯一一件事就是将第一行更改为:
$ErrorActionPreferenceBak=1