Как перехватить исключение, возникающее в блоке скриптов start-job? - PullRequest
20 голосов
/ 06 января 2012

У меня есть следующий скрипт,

$createZip = {
    Param ([String]$source, [String]$zipfile)
    Process { 
        echo "zip: $source`n     --> $zipfile"
        throw "test"
    }
}

try {
    Start-Job -ScriptBlock $createZip -ArgumentList "abd", "acd"  
    echo "**Don't reach here if error**"
    LogThezippedFile
}
catch {
    echo "Captured: "
    $_ | fl * -force
}
Get-Job | Wait-Job 
Get-Job | receive-job 
Get-Job | Remove-Job 

Однако исключение, возникшее в другом экземпляре powershell, не может быть перехвачено.Какой лучший способ запечатлеть исключение?

Id              Name            State      HasMoreData     Location             Command                  
--              ----            -----      -----------     --------             -------                  
343             Job343          Running    True            localhost            ...                      
**Don't reach here if error**
343             Job343          Failed     True            localhost            ...                      
zip: abd
     --> acd
Receive-Job : test
At line:18 char:22
+ Get-Job | receive-job <<<<  
    + CategoryInfo          : OperationStopped: (test:String) [Receive-Job], RuntimeException
    + FullyQualifiedErrorId : test

Ответы [ 3 ]

25 голосов
/ 06 января 2012

Использование throw изменит свойство State объекта задания на "Failed".Ключ должен использовать объект задания, возвращенный из Start-Job или Get-Job, и проверить свойство State.Затем вы можете получить доступ к сообщению об исключении из самого объекта задания.

По вашему запросу я обновил пример, добавив в него также параллелизм.

$createZip = {
    Param ( [String] $source, [String] $zipfile )

    if ($source -eq "b") {
        throw "Failed to create $zipfile"
    } else {
        return "Successfully created $zipfile"
    }
}

$jobs = @()
$sources = "a", "b", "c"

foreach ($source in $sources) {
    $jobs += Start-Job -ScriptBlock $createZip -ArgumentList $source, "${source}.zip"
}

Wait-Job -Job $jobs | Out-Null

foreach ($job in $jobs) {
    if ($job.State -eq 'Failed') {
        Write-Host ($job.ChildJobs[0].JobStateInfo.Reason.Message) -ForegroundColor Red
    } else {
        Write-Host (Receive-Job $job) -ForegroundColor Green 
    }
}
8 голосов
/ 06 марта 2015

Это действительно должен быть комментарий, но у меня нет репутации оставлять комментарии.

Мой ответ таков: вы должны использовать ответ Энди Арисменди, но также вывести $job.ChildJobs[0].Error

Поскольку $job.ChildJobs[0].JobStateInfo.Reason.Message не всегда полезно.

3 голосов
/ 01 марта 2016

Мне удалось «перебросить» исключение в главном потоке, используя:

Receive-Job $job -ErrorAction Stop

В качестве примера я приведу свой вариант использования.Его можно легко применить к OP.

$code = {
    $Searcher = New-Object -ComObject Microsoft.Update.Searcher
    #Errors from Search are not terminating, but will be present in the output none the less.
    $Results = $Searcher.Search('IsInstalled=0  and IsHidden=0')
    $Results.Updates
};
$job = Start-Job -ScriptBlock $code;
$consume = Wait-Job $job -Timeout 600;

if ($job.state -eq 'Running') {
    Stop-Job $job
    throw 'Windows update searcher took more than 10 minutes. Aborting' 
};

#Captures and throws any exception in the job output
Receive-Job $job -ErrorAction Stop;
Write-Host "Finished with no errors"; #this will not print if there was an error

Работает в версии 2.0.

Обратите внимание, что если ошибка в задании не прекращается, последующие строки продолжат выполняться,Но это не будет очевидно в выводе, возвращаемом из Receive-Job, так как Receive-Job «завершает работу на полпути» - он выбрасывает сам при обнаружении объекта ошибки.

Один из способов избежатьто есть обернуть весь блок в try {} catch {throw;}

Кроме того, состояние задания не будет «Failed», если исключение не завершается

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...