执行命令时如何忽略PowerShell中的特定错误?

How to ignore specific error in PowerShell when executing a command?

我知道 ErrorAction 论点,还有 $ErrorActionPreference$Error$.

上下文

我想解决的问题是当 运行 一个外部命令(例如 choco 或 git)它给出了应该警告或什至没有警告的错误,至少在我的任务上下文中.

由于它们的退出代码,PowerShell 认为该结果在任何意义上都是错误,例如将红色写入输出等,这在我的任务上下文中是不可取的。

我可以使用 -ErrorAction2> $null 抑制这些命令错误输出,但我对通过这种方式完全消失 any 错误有一种不好的感觉特定命令。

我只想忽略已知的 "not a problem in this context for me" 类型错误。

问题

有没有什么方法可以忽略某些特定的命令错误,但正常处理所有其他错误情况?

我以前用 git 遇到过这种情况,然后使用 $LASTEXITCODE.

解决了这个问题

不确定它是否适用于您的情况,或者是否适用于 choco,因为我没有遇到过问题。

# using git in powershell console sends everything to error stream
# this causes red text when it's not an error which is annoying
# 2>&1 redirects all to stdout, then use exit code to 'direct' output

$git_output = Invoke-Expression "& [git pull etc] 2>&1"

# handle output using exitcode
if ($LASTEXITCODE -ne 0) { throw $git_output }
else { Write-Output $git_output }
  • 在常规控制台中 window,在 PowerShell v3 及更高版本中,stderr 行打印就像 stdout 行.

    • 这是可取的,因为 stderr 不仅被许多程序用于报告真正的错误,而且还用于报告任何 非数据 ,例如状态消息.

    • Stderr 行(除非重定向 - 见下文)直接通过控制台打印(而 stdout 行被发送到 PowerShell 的成功输出流,在那里它们可以收集在一个变量中,通过管道发送,或使用 > / >>).

    • 重定向
  • 遗憾的是,PowerShell ISE,即使在 v5.1确实red中以与PowerShell错误相同的格式打印标准错误行[=46] =]

      使用 PowerShell 扩展的
    • Visual Studio Code 没有这个问题,并且总体上值得迁移到,因为所有未来的开发工作都将集中在那里,并且它也适用于跨平台PowerShell Core 版本。
  • 行为良好的控制台应用程序使用它们的退出代码来表示成功(退出代码 0) 与失败(任何非零退出代码)。 PowerShell 将最近调用的控制台应用程序的退出代码保存在其 自动 $LASTEXITCODE 变量 .

  • 顺便说一句:

    • 公共参数-ErrorAction-ErrorVariable不能与外部程序一起使用。
    • 同样,自 PowerShell v5.1 / PowerShell Core 6.2 起,首选项变量 $ErrorActionPreference 无效(除了 意外 ,由于 this bug。 0-预览.4).
    • try / catch 不能用于检测和处理外部程序的故障。
    • 有关 PowerShell 复杂错误处理规则的全面概述,请参阅 this GitHub docs issue

注意:我在下面的示例中使用了以下外部命令,它们产生 1 行 stdout 和 1 行 stderr 输出(注意重定向 >&2cmd 处理,不是 PowerShell,因为它在 '...' 里面;它用于产生 stderr 输出):

cmd /c 'echo stdout & echo stderr >&2' 

通过非零退出代码 (exit 1) 使命令信号 失败 的变体:

cmd /c 'echo stdout & echo stderr >&2 & exit 1' 

因此,通常以下内容就足够了:

$stdOut = cmd /c 'echo stdout & echo stderr >&2' # std*err* will print to console
if ($LASTEXITCODE -ne 0) { Throw "cmd failed." } # handle error

这会在变量 $stdout 中捕获 stdout 输出并将 stderr 输出传递到控制台。


如果你想收集以后的stderr输出并且只在[=92=的情况下显示它们]错误:

$stdErr = @() # initialize array for collecting stderr lines.

# Capture stdout output while collecting stderr output in $stdErr.
$stdOut = cmd /c 'echo stdout & echo stderr >&2 & exit 1' 2>&1  | Where-Object { 
  $fromStdErr = $_ -is [System.Management.Automation.ErrorRecord]
  if ($fromStdErr) { $stdErr += $_.ToString() }
  -not $fromStdErr # only output line if it came from stdout
}

# Throw an error, with the collected stderr lines included.
if ($LASTEXITCODE -ne 0) { 
  Throw "cmd failed with the following message(s): $stdErr"
}
  • 注意 2>&1 重定向,它指示 PowerShell 通过管道(流 1,错误流)发送 stderr 行(流 2,错误流)成功流)。

  • Where-Object 块中,$_ -is [System.Management.Automation.ErrorRecord] 用于标识 stderr 行,因为 PowerShell 在该实例中包装了这些行类型。

或者,您可以在临时文件 (2>/path/to/tmpfile) 中收集 stderr 输出,读取其内容,然后将其删除。

This GitHub issue 提议在 变量 中引入收集重定向 stderr 输出的选项,类似于您如何询问 cmdlets通过公共参数
-ErrorVariable.

收集变量中的错误

有两个注意事项:

  • 本质上,通过仅打印 stderr 行 later,与 stdout 输出相关的特定上下文可能会丢失.

  • 由于 bug as of Windows PowerShell v5.1 / PowerShell Core 6.2.0$ErrorActionPreference = Stop 不能 生效,因为 2>&1 重定向一旦收到第一个 stderr 行,就会触发 脚本终止错误


如果您想有选择地对接收到的 stderr 行采取行动:

注:

  • 本质上,当你处理这些行时,你还不知道程序最终会报告失败还是成功。

  • $ErrorActionPreference = 'Stop' 警告也适用于此。

以下示例过滤掉 stderr 行 stderr1 并将行 stderr2 以红色打印到控制台(仅文本,不像 PowerShell 错误)。

$stdOut = cmd /c 'echo stdout & echo stderr1 >&2 & echo stderr2 >&2' 2>&1 |
  ForEach-Object { 
    if ($_ -is [System.Management.Automation.ErrorRecord]) { # stderr line
      $stdErrLine = $_.ToString()
      switch -regex ($stdErrLine) {
        'stderr1' { break } # ignore, if line contains 'stderr1'
        default   { Write-Host -ForegroundColor Red $stdErrLine }
      }
    } else { # stdout line
      $_ # pass through
    }
  }

# Handle error.
if ($LASTEXITCODE -ne 0) { Throw "cmd failed." }