如何在不污染PowerShell错误输出的情况下重定向stdout和stderr [英] How can I redirect stdout and stderr without polluting PowerShell error output

查看:55
本文介绍了如何在不污染PowerShell错误输出的情况下重定向stdout和stderr的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试通过PowerShell运行命令并捕获其stdout和stderr 而没有将它们打印在屏幕上(命令噪音很大,并且污染了控制台).

I am trying to run a command via PowerShell and capture its stdout and stderr without printing them on screen (command is incredibly noisy and pollutes the console).

我想捕获变量中的stdout和stderr,然后在发现特定字符串的情况下引发异常.

I want to capture the stdout and stderr in a variable and then throw an exception if particular strings are found.

我的逻辑似乎正在运行,我可以使cmdlet失败/通过,但是输出与我的期望不符,而不是返回我指定的错误消息,我得到的是我所相信的而不是命令中的stderr?

My logic seems to be working and I can make the cmdlet fail/pass when I expect it to, however the output does not match what I expect, instead of returning the error message that I am specifying I get what I believe is the stderr from the command instead?

(简化后易于阅读)
第一个cmdlet:

(Simplified for easier reading)
First 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调用哪个:

Which is called by a second 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 

如您所见,似乎正在从我正在运行的命令(pdk)返回输出,而不是"模块验证失败.退出代码:$($ LASTEXITCODE)." 消息,我在Test-Validation cmdlet中定义.

As you can see it seems to be returning the output from the command I'm running (pdk) instead of the "Module validation has failed. Exit code: $($LASTEXITCODE)." message I am defining in the Test-Validation cmdlet.

为什么我没有收到我想要的错误消息,对我来说有什么办法可以实现我想要的?除了提供任何代码建议外,我将非常感谢您对问题的进一步阅读,以便我可以更好地理解这些内容.

Why am I not getting the error message I want and is there any way for me the achieve what I'm looking for? Alongside any code suggestions I would very much appreciate any further readings around my issues to so I can better understand these things.

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

N.B.: This is being run by PoSh Core on MacOS

推荐答案

您的症状暗示 $ ErrorActionPreference ='Stop'在时间函数中有效
Test-Validation 执行.(暂时)将其设置为'继续'以解决您的问题-希望在未来版本中不再需要该问题(请参见下文).

Your symptom implies that $ErrorActionPreference = 'Stop' is in effect at the time function
Test-Validation executes. (Temporarily) set it to 'Continue' to fix your problem - which in future versions will hopefully no longer required (see below).

观察到的行为的原因是,从PowerShell 7.1开始,使用错误流重定向( 2> )使PowerShell路由外部程序的stderr通过PowerShell的错误流输出 (请参阅

The reason for the observed behavior is that, as of PowerShell 7.1, using an error-stream redirection (2>) makes PowerShell route an external program's stderr output through PowerShell's error stream (see about_Redirection), and $ErrorActionPreference = 'Stop' therefore throws a script-terminating error once the first stderr line is received.

这种行为很不幸,因为假设外部程序实际上对任何都使用标准错误流stderr,则不能假定外部程序的stderr输出代表了 error 条件.例如,除了数据(包括状态信息)之外.

This behavior is unfortunate, because stderr output from external programs cannot be assumed to represent an error condition, given that external programs in effect use stderr, the standard error stream, for anything that other than data, which includes status information, for instance.

PowerShell 7.2的预览版本(截至撰写本文时尚未发布7.2)具有

The preview versions of PowerShell 7.2 (7.2 hasn't been released yet as of this writing) have an experimental feature named PSNotApplyErrorActionToStderr, which changes this behavior for the better: stderr output is no longer routed through PowerShell's error stream, which means that:

首选项变量 $ ErrorActionPreference 不再对外部程序的stderr输出产生任何影响.

Preference variable $ErrorActionPreference no longer has any impact on stderr output from external programs.

automatic $?变量指示最近执行的语句的成功状态,不再错误地设置为 $ false 当进程退出代码为 0 时,也恰好有stderr输出-尽管请注意,您始终可以通过自动 $ LASTEXITCODE 变量

The automatic $? variable, which indicates the success status of the most recently executed statement, is no longer incorrectly set to $false when the process exit code is 0 and there also happens to be stderr output - though note that you can always infer success vs. failure of external programs via the automatic $LASTEXITCODE variable

注意:

  • 在PowerShell的 preview 版本中,所有实验功能默认情况下均打开,而在<发布候选版本正式发布的版本.

  • In preview versions of PowerShell all experimental features are turned on by default, whereas they're off by default in release candidates and officially released versions.

不能保证实验性功能会成为正式功能;是否根据用户反馈和使用情况数据确定.至少从形式上来讲,眼前的变化代表了重大变化.

An experimental feature is not guaranteed to become an official feature; whether it will is determined based on user feedback and usage data. At least formally, the change at hand represents a breaking change.

这篇关于如何在不污染PowerShell错误输出的情况下重定向stdout和stderr的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆