【问题标题】:How to capture the exception raised in the scriptblock of start-job?如何捕获 start-job 脚本块中引发的异常?
【发布时间】:2020-04-22 21:22:04
【问题描述】:

我有以下脚本,

$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

【问题讨论】:

  • 我更新了我的答案,以向您展示您上一个问题中的方法。
  • 不清楚你想通过这份工作完成什么。似乎您同时想要异步和同步行为,这是不可能的。您希望何时执行脚本中的下一行?

标签: powershell powershell-2.0


【解决方案1】:

使用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 
    }
}

【讨论】:

  • 谢谢,我更新了问题 - 如果发生错误,我不希望执行压缩后的日志记录。有可能吗?
  • 谢谢。但是Wait-Job 将阻止try 块中语句的执行,这将在一个大循环中运行。我使用 start-job 的目的是在主循环和压缩中并行任务......听起来我正在寻找一些异步执行......
  • @NickW 抱歉,未经检查就发布了。有一个问题。我刚刚更新了一个测试版,试试这个。
  • @NickW 是的,我提供的示例仅地址接收来自后台作业的错误。如果您想要异步循环支持,那将需要额外的费用;-)(虽然它非常可行)。
  • 谢谢。我想我需要更改$Jobs += start-job 以包含一些额外的信息。也许 $Jobs 应该是一本字典。
【解决方案2】:

这确实应该是评论,但我没有离开cmets的声誉。

我的回答是你应该用安迪·阿里斯门迪的回答,还要输出$job.ChildJobs[0].Error

因为$job.ChildJobs[0].JobStateInfo.Reason.Message 并不总是有用的。

【讨论】:

  • 对我来说,访问异常对象是$job.ChildJobs[0].JobStateInfo.Reason。我也能够“重新抛出”错误。 ChicldJobs[0].Error 为空。
  • $job.ChildJobs[0].Error 返回所有非终止错误。 $job.ChildJobs[0].JobStateInfo.State 返回终止错误(如果有)(状态 == 失败)。 source
【解决方案3】:

我能够使用以下方法在主线程中“重新抛出”异常:

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 {} catch{throw;}

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

【讨论】:

    【解决方案4】:

    TLDR:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-07-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-12-21
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多