programing

시작 작업의 스크립트 블록에 제기된 예외를 캡처하는 방법은?

jooyons 2023. 10. 27. 21:54
반응형

시작 작업의 스크립트 블록에 제기된 예외를 캡처하는 방법은?

나는 다음과 같은 대본을 가지고 있습니다.

$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 

그러나 다른 파워셸 인스턴스에서 제기된 예외는 캡처할 수 없습니다.예외를 포착하는 가장 좋은 방법은 무엇입니까?

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

사용.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 
    }
}

이건 정말 댓글이어야 하는데, 저는 댓글을 달 수 있는 평판이 없습니다.

내 대답은 Andy Arismendi의 답변을 사용하되 출력도 사용해야 한다는 것입니다.$job.ChildJobs[0].Error

~하듯이$job.ChildJobs[0].JobStateInfo.Reason.Message항상 유용한 것은 아닙니다.

다음을 사용하여 메인 스레드에서 예외를 "되돌릴" 수 있었습니다.

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

v2.0에서 작동합니다.

작업 내의 오류가 종료되지 않은 경우 다음 행이 계속 실행됩니다.그러나 수신 작업에서 반환되는 출력에서는 명확하지 않습니다. 수신 작업은 오류 개체가 발생하면 자체적으로 폐기되기 때문입니다.

이를 방지하는 한 가지 방법은 전체 블록을 시도 {}개의 캐치{throw;}에 래핑하는 것입니다.

또한 예외가 종료되지 않는 경우 작업 상태가 '실패' 상태가 되지 않습니다.

TLDR:

# Works with both terminating and non terminating errors
$j = start-job {1/0} | wait-job; try { receive-job $j -ErrorAction Stop } catch { "err $_" } 

언급URL : https://stackoverflow.com/questions/8751187/how-to-capture-the-exception-raised-in-the-scriptblock-of-start-job

반응형