Powershell 如何捕获启动作业的scriptblock中引发的异常?

Powershell 如何捕获启动作业的scriptblock中引发的异常?,powershell,powershell-2.0,Powershell,Powershell 2.0,我有下面的脚本 $createZip = { Param ([String]$source, [String]$zipfile) Process { echo "zip: $source`n --> $zipfile" throw "test" } } try { Start-Job -ScriptBlock $createZip -ArgumentList "abd", "acd" echo "**D

我有下面的脚本

$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
Id Name State HasMoreData Location命令
--              ----            -----      -----------     --------             -------                  
343作业343正在运行真正的本地主机。。。
**如果有错误,请不要到这里**
343作业343未通过真正的本地主机。。。
邮编:abd
-->acd
接收作业:测试
第18行字符:22

+Get Job | receive Job使用
throw
将作业对象的
状态
属性更改为“失败”。关键是使用从
开始作业
获取作业
返回的作业对象,并检查
状态
属性。然后可以从作业对象本身访问异常消息

根据您的请求,我更新了示例,使其也包含并发性

$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]。错误

As
$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中工作

请注意,如果作业中的错误是非终止的,则后续行将继续执行。但是,这在接收作业返回的输出中并不明显,因为接收作业“中途终止”——当遇到错误对象时,它会抛出自身

避免这种情况的一种方法是将整个块包装在try{}catch{throw;}

此外,如果异常为非终止状态,则作业状态不会为“失败”:

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


我更新了我的答案,向你展示了你在上一个问题中是如何做的。不清楚你想通过这份工作完成什么。似乎您同时需要异步和同步行为,这是不可能的。您想什么时候执行脚本中的下一行?谢谢,我更新了这个问题-如果发生错误,我不希望在压缩后执行日志记录。可能吗?谢谢。但是,
Wait作业
将阻止try块中语句的执行,try块将在一个大循环中运行。我使用start job的目的是在主循环中并行任务并压缩。。。听起来好像我正在寻找一些异步执行…@NickW抱歉没有检查就发布了。有一个问题。我刚刚更新了一个测试版本,请试一试。@NickW是的,我提供的示例只接收来自后台作业的错误。如果您需要额外成本的异步循环支持;-)(虽然这很可行)谢谢。我想我需要更改
$Jobs+=start job
以包含一些额外的信息。也许$Jobs应该是一个字典。对我来说,对异常对象的访问权限是
$job.ChildJobs[0]。JobStateInfo.Reason
。我还能够“重现”错误。ChicldJobs[0]。错误为空。
$job.ChildJobs[0]。错误
返回所有非终止错误<代码>$job.ChildJobs[0]。JobStateInfo.State
返回终止错误(如果有)(状态==失败)。