2012-01-05 7 views
16

Ho la seguente script,Come catturare l'eccezione generata nello scriptblock di start-job?

$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 

Tuttavia, l'eccezione sollevata in un'altra istanza PowerShell non può essere catturato. Qual è il modo migliore per catturare l'eccezione?

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

I aggiornato la mia risposta per mostrarvi come nella vostra domanda precedente. –

+0

Non è chiaro cosa si sta cercando di realizzare con il lavoro. Sembra che tu voglia sia il comportamento asincrono che quello sincrono allo stesso tempo, il che è impossibile. Quando vuoi eseguire la riga successiva nel tuo script? – zdan

risposta

19

Utilizzando throw cambierà proprietà dell'oggetto lavoro State a "Failed". La chiave è utilizzare l'oggetto lavoro restituito da Start-Job o Get-Job e verificare la proprietà State. È quindi possibile accedere al messaggio di eccezione dall'oggetto di lavoro stesso.

Per vostra richiesta ho aggiornato l'esempio per includere anche la concorrenza.

$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

Grazie, ho aggiornato la domanda: non voglio che la registrazione dopo lo zipping sia eseguita se si verifica un errore. È possibile? – ca9163d9

+0

@NickW Sure è. Vedi la mia risposta aggiornata. –

+0

Grazie. Tuttavia, il "Wait-Job" bloccherà l'esecuzione delle istruzioni nel blocco try, che verrà eseguito in un grande ciclo. Il mio scopo di usare start-job è di fare il parallelismo del task nel ciclo principale e zippare ... Sembra che sto guardando un po 'di esecuzione asincrona ... – ca9163d9

5

Questo dovrebbe essere un commento davvero, ma non ho la reputazione di lasciare commenti.

La mia risposta è che si dovrebbe usare la risposta di Andy Arismendi, ma anche l'uscita $job.ChildJobs[0].Error

Come $job.ChildJobs[0].JobStateInfo.Reason.Message non è sempre utile.

+0

Per me, l'accesso all'oggetto eccezione era '$ job.ChildJobs [0] .JobStateInfo.Reason'. Sono stato anche in grado di "ripensare" l'errore. ChicldJobs [0]. L'errore era vuoto. – Patrick

2

sono stato in grado di "rigenerare" l'eccezione nel thread principale utilizzando:

Receive-Job $job -ErrorAction Stop 

io il mio caso d'uso come esempio. Può essere facilmente applicato all'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 

Funziona nella versione 2.0.

Si noti che se l'errore all'interno del processo non è terminato, le righe successive continueranno a essere eseguite. Ma questo non sarà ovvio nell'output restituito da Receive-Job, dato che Receive-Job "termina a metà strada" - si getta fuori da sé quando viene rilevato l'oggetto error.

Un modo per evitare che è quello di avvolgere l'intero blocco in un try {} catch {gettare;}

Inoltre, lo stato di lavoro non saranno 'Impossibile' se l'eccezione è non fatale

Problemi correlati