2012-01-05 15 views
16

que tienen la siguiente secuencia de comandos,Cómo capturar la excepción planteada en el scriptblock de 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 

Sin embargo, la excepción planteada en otra instancia PowerShell no puede ser capturado. ¿Cuál es la mejor manera de capturar la excepción?

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 actualicé mi respuesta para mostrarte cómo en tu pregunta anterior. –

+0

No está claro lo que está tratando de lograr con el trabajo. Parece que quieres un comportamiento asincrónico y sincrónico al mismo tiempo, lo cual es imposible. ¿Cuándo quieres ejecutar la siguiente línea en tu script? – zdan

Respuesta

19

Usando throw va a cambiar la propiedad del objeto de trabajo State a "Error". La clave es usar el objeto de trabajo devuelto por Start-Job o Get-Job y verificar la propiedad State. A continuación, puede acceder al mensaje de excepción desde el objeto de trabajo.

Según su solicitud, actualicé el ejemplo para incluir también concurrencia.

$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

Gracias, actualicé la pregunta: no quiero que el registro después de la compresión se ejecute si se produce un error. ¿Es posible? – ca9163d9

+0

@NickW Claro que sí. Ver mi respuesta actualizada. –

+0

Gracias. Sin embargo, el 'Wait-Job' bloqueará la ejecución de las instrucciones en el bloque try, que se ejecutará en un gran bucle. Mi propósito de utilizar start-job es paralelizar la tarea en el ciclo principal y comprimir ... Parece que estoy buscando una ejecución asincrónica ... – ca9163d9

5

Esto debería ser un comentario realmente, pero no tengo la reputación de dejar comentarios.

Mi respuesta es que se debe usar la respuesta de Andy Arismendi, sino también la producción $job.ChildJobs[0].Error

Como $job.ChildJobs[0].JobStateInfo.Reason.Message no siempre es útil.

+0

Para mí, el acceso al objeto de excepción fue '$ job.ChildJobs [0] .JobStateInfo.Reason'. También pude 'volver a lanzar' el error. ChicldJobs [0] .Error estaba vacío. – Patrick

2

que era capaz de "volver a lanzar" la excepción en el hilo principal mediante el uso de:

Receive-Job $job -ErrorAction Stop 

voy a mi caso uso como un ejemplo. Se puede aplicar fácilmente al 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 

Funciona en v2.0.

Tenga en cuenta que si el error dentro del trabajo no es definitivo, las líneas subsiguientes continuarán ejecutándose. Sin embargo, esto no será obvio en el resultado devuelto por Receive-Job, ya que Receive-Job "termina a medio camino", sale de sí mismo cuando se encuentra el objeto de error.

Una forma de evitar que se va a envolver todo el bloque en un intento de captura {} {throw;}

Además, el estado de empleo no serán 'fracasado' si la excepción no es la terminación

Cuestiones relacionadas