Как постоянно пробовать что-то в PowerShell, пока это не удастся? - PullRequest
0 голосов
/ 19 сентября 2018

Используя базовую конструкцию:

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

Можно ли продолжать пробовать что-нибудь до тех пор, пока это не удастся?Возможно, используя цикл 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 секунды.Пожалуйста, помогите.

В частности, Do-Something:

(Get-Process -Name FineReader).MainWindowHandle

Я бы хотел, чтобы код продолжал попытки до тех пор, пока не существует FineReader, и он может получить MainWindowHandle.

Ответы [ 3 ]

0 голосов
/ 19 сентября 2018

Вы можете использовать ключевое слово 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
    }
}
0 голосов
/ 19 сентября 2018

Предположим, что у вас происходит сбой функции в 9 из 10 вызовов:

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 вызова.

0 голосов
/ 19 сентября 2018

Ваш Do-Something должен вызываться с коммутатором -ErrorAction Stop, чтобы выдать завершающее исключение, которое может быть перехвачено try

. Для этого вам также необходимо связать свою функцию как CmdLet,Например:

function DoSomething {
    [CmdLetBinding()]
    Param(
    )

    # Your code

}

И затем вызвать вашу функцию с помощью переключателя -ErrorAction Stop:

try {
    Do-Something -ErrorAction Stop
}

Если ваш DoSomething не функция, а скорее существующий PowerShell CmdLet, тогда... как вы уже догадались, просто позвоните с помощью -ErrorAction Stop

Вы можете узнать больше о try / catch / finally в powershell здесь

...