如何将所有输出流写入 PowerShell 中的变量? 为什么不使用 -ErrorAction 来更改错误操作首选项?为什么输出通过管道传送到 Out-Null?

问题描述

在 PowerShell 中,我无法将错误输出写入变量。

在不将输出保存到变量的情况下运行命令将导致任何流的输出可见,但唉,我需要将输出写入变量。

& terraform $action $arguments

最初我开始使用它。但是,只有成功流被写入变量(如预期)。

$res = & terraform $action $arguments

于是我咨询了docs for about_Redirection,但问题是,当我将错误流(或所有流)重定向到成功流时,我仍然只看到成功流写入变量。我做了几次尝试,都失败了。

$res = & terraform $action $arguments 2>&1
$res = & terraform $action $arguments *>&1
$res = & terraform $action $arguments *>&1 | ForEach-Object { $_.ToString() }

但是,如果我将错误重定向一个文件,那么该流将按预期写入。

$res = & terraform $action $arguments 2>> terraform-errors.log

如何将所有流的输出写入变量?

解决方法

我终于找到了答案,问题出在设置 $ErrorActionPreference = Stop 上。

当终止发生时,脚本在重定向输出之前被终止。要解决此问题,必须更改错误操作首选项,然后可以使用 Invoke-Expression 和一些 common parameters 将错误和输出发送到变量。

$ErrorActionPreference = "SilentlyContinue"
Invoke-Expression "& terraform $action $arguments 2>&1" -ErrorVariable terraformError -OutVariable terraformState | Out-Null
$ErrorActionPreference = "Stop"

### Check if there was an error.
if ($terraformError) {
    throw $terraformError
}

为什么不使用 -ErrorAction 来更改错误操作首选项?

遗憾的是 -ErrorAction 仅适用于非终止错误。由于脚本的错误操作首选项是 Stop,这意味着无论 Invoke-Expression 公共参数的值如何,-ErrorAction 命令都将始终触发终止错误。

要解决此问题,必须在运行 Invoke-Expression 命令之前更改错误操作首选项,然后在运行完成后更改回来。

为什么输出通过管道传送到 Out-Null

尽管将错误和输出保存到变量中,但输出也会流式传输到控制台,而无需通过管道将其传输到 Out-Null

显然这是可选的,因为在某些情况下可能可以接受/预期输出也将流式传输到控制台。