我想按照以下规则重定向PowerShell中命令的输出:
-
命令存储到变量中
-
输出必须实时写入控制台(即"ping"结果(,包括错误
-
输出必须存储到变量中,包括错误(此处不强制要求实时(
以下是我的测试,假设:
$command = "echo:"
测试错误重定向,以及:
$command = "ping 127.0.0.1"
以测试实时输出。
输出是实时写入的,错误根本不会重定向
Invoke-Expression $command 2>&1 | Tee-Object -Variable out_content
输出是实时写入的,错误仅重定向到控制台
Invoke-Expression ($command 2>&1) | Tee-Object -Variable out_content Invoke-Expression $command | Tee-Object -Variable out_content 2>&1
输出不是实时写入的,错误被正确地重定向到两者
(Invoke-Expression $command) 2>&1 | Tee-Object -Variable out_content
是否有可能让这些规则协同工作?
一些一般性建议:
-
通常应该避免
Invoke-Expression
,因为它可能是一种安全风险并带来引用头痛;通常有更好更安全的解决方案可用;最好养成避免Invoke-Expression
的习惯,除非没有其他解决方案。 -
永远没有理由使用
Invoke-Expression
来简单地执行带有参数的外部程序,例如ping 127.0.0.1
;只需直接调用它 - 支持这种直接调用是任何 shell 的核心功能,PowerShell 也不例外。 -
如果你确实需要将命令存储在变量中或将其作为参数传递以供以后调用,请使用脚本块(
{ ... }
(;例如,使用$command = { ping 127.0.0.1 }
代替$command = 'ping 127.0.0.1'
,并使用调用运算符&
或点源运算符.
按需调用该脚本块。
调用外部程序时,两个运算符表现出相同的行为;调用PowerShell 本机命令时,&
在子作用域中执行代码,而.
(通常(在调用方的当前作用域中执行。
该Invoke-Expression $command 2>&1
无法按预期工作看起来像一个错误(从PowerShell Core 7.0.0-preview.3开始(,并且已在此GitHub问题中报告。
至于您的问题的解决方法:
PetSerAl和以前无数次一样,在对这个问题的评论中提供了一个解决方案:
& { Invoke-Expression $command } 2>&1 | Tee-Object -Variable out_content
{ ... }
是包含Invoke-Expression
调用的脚本块文本,它使用&
调用运算符调用,该运算符允许将流重定向表达式2>&1
应用于绕过 bug 的&
调用。
如果$command
包含要在当前范围内直接执行的 PowerShell 本机命令(如函数定义(,则应使用.
而不是&
。