如何在不污染 PowerShell 错误输出的情况下重定向 stdout 和 stderr

How can I redirect stdout and stderr without polluting PowerShell error output

问题:

我正在尝试通过 PowerShell 运行 一个命令并捕获它的标准输出和标准错误 而不 在屏幕上打印它们(命令非常嘈杂并且污染了控制台)。

我想在变量中捕获标准输出和标准错误,然后在找到特定字符串时抛出异常。

我的逻辑似乎在工作,我可以在我期望的时候创建 cmdlet fail/pass,但是输出与我的期望不匹配,而不是返回我指定的错误消息我得到我认为命令中的标准错误是什么?

我的代码:

(已简化以便于阅读)
第一个 cmdlet:

function Test-Validation
{
    [CmdletBinding()]
    param(
        [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, Position = 0)]
        [Array]
        $ValidExitCodes = @(0),

        [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, Position = 1)]
        [bool]
        $FailOnWarning = $true
    )
    $Validation = . pdk validate 2>&1

    if ($LASTEXITCODE -notin $ValidExitCodes)
    {
        throw "Module validation has failed. Exit code: $($LASTEXITCODE)."
    }
    $Warnings = $Validation -match 'pdk \(WARNING\)'
    if (($Warnings) -and ($FailOnWarning -eq $true))
    {
        throw "Module validation contains warnings.`n$Warnings"
    }
    Write-Verbose "Module successfully passed validation"
}

由第二个 cmdlet 调用:

function Test-Module
{
    [CmdletBinding()]
    param
    ()

    try
    {
      Test-Validation
    }
    catch
    {
      throw "$($_.Exception.Message)"
    }
    try
    {
      Test-Unit
    }
    catch
    {
      throw "$($_.Exception.Message)"
    }
}

预期输出

PS /opt/script/test/> Test-Module
Exception: /opt/script/test/Test-Module.ps1:13:9
Line |
  13 |          throw "$($_.Exception.Message)"
     |          ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     | Module validation has failed. Exit code: 1.

实际产量

PS /opt/script/test/> Test-Module
Exception: /opt/script/test/Test-Module.ps1:13:9
Line |
  13 |          throw "$($_.Exception.Message)"
     |          ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     | pdk (INFO): Using Ruby 2.5.8 

如您所见,它似乎正在返回命令 I'm 运行ning (pdk) 的输出,而不是我在 Test-Validation cmdlet 中定义的 "Module validation has failed. Exit code: $($LASTEXITCODE)." 消息。

为什么我没有收到我想要的错误消息,有什么方法可以实现我想要的吗? 除了任何代码建议,我将非常感谢任何关于我的问题的进一步阅读,以便我能更好地理解这些事情。

N.B.:这是由 PoSh Core 在 MacOS

上 运行

您的症状表明$ErrorActionPreference = 'Stop'在函数
时有效 Test-Validation 执行。 (暂时)将其设置为 'Continue' 以解决您的问题 - 希望在 未来 版本中不再需要(见下文)。

观察到的行为的原因是,在 Windows PowerShell 和 PowerShell (Coe) 7.1 中,使用错误流重定向 (2>) 使 PowerShell 路由外部程序的标准错误输出通过 PowerShell 的错误流(参见 about_Redirection),并且 $ErrorActionPreference = 'Stop' 因此在收到第一行 stderr 后抛出脚本终止错误。

这种行为很不幸,因为外部程序的 stderr 输出不能假定代表 error 条件,假设外部程序实际上使用 stderr,标准错误流,用于数据以外的任何内容,例如,包括状态信息。

PowerShell 7.2 及更高版本更好地改变了此行为:stderr 输出不再通过 PowerShell 的错误流进行路由,这意味着: