2012-01-05 34 views
16

我有以下腳本,如何捕獲start-job的scriptblock中引發的異常?

$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 
+0

我更新了我的回答,以向您展示您之前的問題。 – 2012-01-05 23:05:51

+0

目前還不清楚你在這份工作中想完成什麼。看起來好像你同時需要異步和同步行爲,這是不可能的。你什麼時候想要執行腳本中的下一行? – zdan 2012-01-06 01:03:39

回答

19

使用throw將改變作業對象的State屬性設置爲「失敗」。關鍵是使用從Start-JobGet-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 
    } 
} 
+0

謝謝,我更新了這個問題 - 我不想在發生錯誤時執行壓縮後執行日誌記錄。可能嗎? – ca9163d9 2012-01-05 23:17:32

+0

@NickW當然是。看到我更新的答案。 – 2012-01-05 23:22:35

+0

謝謝。然而'Wait-Job'將阻止try塊中的語句的執行,這將在一個大循環中運行。我的使用開始工作的目的是平行的主循環中的任務和壓縮...這聽起來像我看着一些異步執行... – ca9163d9 2012-01-05 23:28:42

5

這應該是一個真正的評論,但我沒有留下評論的聲望。

我的回答是,你應該使用安迪·阿里斯門迪的回答,而且輸出$job.ChildJobs[0].Error

由於$job.ChildJobs[0].JobStateInfo.Reason.Message並不總是有用的。

+0

對我來說,訪問異常對象是'$ job.ChildJobs [0] .JobStateInfo.Reason'。我也能夠「重新拋出」錯誤。 ChicldJobs [0] .Error是空的。 – Patrick 2016-03-01 02:27:57

2

我能夠通過使用「重新拋出」在主線程中的異常:

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。

請注意,如果作業中的錯誤未終止,則後續行將繼續執行。但是,從Receive-Job返回的輸出中,這並不明顯,因爲Receive-Job「中途終止」 - 當遇到錯誤對象時,它會拋出它自己。避免

一種方法是整個包住塊在一個try {}趕上{拋出;}

此外,工作狀態將不會被「失敗」如果異常是非終止

相關問題