如何重定向 stdout 和 stderr 而不污染 PowerShell 错误输出

Ste*_*own 2 error-handling powershell stderr

问题:

我试图通过 PowerShell 运行命令并捕获其 stdout 和 stderr而不将它们打印在屏幕上(命令非常嘈杂并污染控制台)。

我想捕获变量中的 stdout 和 stderr,然后在找到特定字符串时抛出异常。

我的逻辑似乎正常工作,我可以在我期望的时候使 cmdlet 失败/通过,但是输出与我的期望不匹配,而不是返回我指定的错误消息,我得到的是我认为是 stderr 的内容命令代替?

我的代码:

(为了便于阅读而进行了简化)
第一个 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"
}
Run Code Online (Sandbox Code Playgroud)

由第二个 cmdlet 调用:

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

    try
    {
      Test-Validation
    }
    catch
    {
      throw "$($_.Exception.Message)"
    }
    try
    {
      Test-Unit
    }
    catch
    {
      throw "$($_.Exception.Message)"
    }
}
Run Code Online (Sandbox Code Playgroud)

预期产出

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.

Run Code Online (Sandbox Code Playgroud)

实际产量

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 

Run Code Online (Sandbox Code Playgroud)

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

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

注意:这是由 PoSh Core 在 MacOS 上运行的

mkl*_*nt0 9

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

观察到的行为的原因是,在 Windows PowerShell 和 PowerShell (Coe) 7.1之前的版本中,使用错误流重定向( ) 使 PowerShell通过 PowerShell 的错误流路由外部程序的 stderr 输出2>(请参阅about_Redirection),$ErrorActionPreference = 'Stop'因此一旦收到第一个 stderr 行,就会抛出脚本终止错误。

这种行为是不幸的,因为外部程序的 stderr 输出不能被假定为表示错误条件,因为外部程序实际上使用 stderr(标准错误流)来处理除 data 之外的任何内容,例如,其中包括状态信息。

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