这是处理管道中错误/异常的正确方法吗?

本文关键字:方法 异常 处理 管道 错误 | 更新日期: 2023-09-27 18:17:09

这是我上一个问题的后续问题,只是想澄清一下。

因为ThrowTerminatingError()将终止cmdlet并停止处理管道中的项。在管道中处理"问题"对象的正确方法是什么,但您仍然希望继续处理剩余的项目?

我将在这里使用一个非常简单的例子,考虑这个函数:
Function Do-Something
{
    [CmdletBinding()]
    Param(
        [Parameter(Mandatory=$True,
        ValueFromPipeline=$True)]
        [int]$value
    )
    process 
    {
        if($value -eq 3)
        {
            // Terminate if $value is 3.
        }
        Write-Output($value)
    }
}

现在假设这个函数像这样被调用…

1..10 | Do-Something

使用throw:

if($value -eq 3)
{
    throw '$value was 3'
}

输出:

1
2
$value was 3
At C:'Users'Me'Desktop'Untitled1.ps1:51 char:12
+            throw '$value was 3'
+            ~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : OperationStopped: ($value was 3:String) [], RuntimeException
    + FullyQualifiedErrorId : $value was 3

使用ThrowTerminatingError():

if($value -eq 3)
{
    $PSCmdlet.ThrowTerminatingError((New-Object System.Management.Automation.ErrorRecord -ArgumentList (new-object System.Exception -ArgumentList ('$value was 3')), 'ValueWas3', 'NotSpecified', $value))       
}

产生类似的输出:

1
2
Do-Something : $value was 3
At C:'Users'Me'Desktop'Untitled1.ps1:57 char:9
+ 1..10 | Do-Something
+         ~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (3:Int32) [Do-Something], Exception
    + FullyQualifiedErrorId : ValueWas3,Do-Something

但是如果我使用Write-Error和return语句:

if($value -eq 3)
{
    Write-Error((New-Object System.Management.Automation.ErrorRecord -ArgumentList (new-object System.Exception -ArgumentList ('$value was 3')), 'ValueWas3', 'NotSpecified', $value))
    return
}

项目全部处理,报告第三个错误:

1
2
Do-Something : $value was 3
At C:'Users'Me'Desktop'Untitled1.ps1:58 char:9
+ 1..10 | Do-Something
+         ~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [Write-Error], WriteErrorException
    + FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException 
   ,Do-Something
4
5
6
7
8
9
10

这是正确的方式,我应该处理与管道对象的问题,或者我应该看看我的函数的结构?

基本上,我只是想知道我应该如何处理管道中无法处理的对象,但我想继续处理任何剩余的对象。

我想要这样的东西的原因是在一个函数的end块中,我有时可能想要报告哪些项目被成功处理,哪些失败(可能有一个原因)。

这是处理管道中错误/异常的正确方法吗?

在编写PowerShell命令时,您有两个广泛的选项来表示错误:non-terminatingterminating错误。

如果命令可以继续,则使用non-terminating错误。例如,您正在复制1000个文件,第一个文件被锁定。整个行动完全失败是没有意义的。在这种情况下,使用Write-Error并将错误信息写入该文件的error流并继续复制其他文件就足够了。

在遇到无法继续的错误时使用terminating错误。例如,如果命令的第一步是建立到远程服务的连接,而该服务没有响应,则无法继续。在终止错误的情况下,您的选项是:A)抛出,B)使用ThrowTerminatingError()或C)让异常逃离命令的实现。这些都是抛出(或不捕捉)异常的变体。

Write-Error之后是否使用return语句取决于您是否想为当前管道对象执行更多代码(可能是清理代码)