为何Invoke-Expression不支持直接重定向错误流?
为什么
Invoke-Expression直接重定向会丢失错误流? 核心原因
Invoke-Expression(常缩写为iex)的设计存在特殊行为:它执行的脚本/命令产生的非终止错误(也就是Write-Error输出的这类错误),不会通过iex自身的输出管道传递,而是直接发送到当前会话的顶层错误流。这就导致你直接对iex使用*>&1时,只能捕获iex命令本身产生的流,而它内部代码抛出的错误流会绕过这个重定向,无法被后续的Tee-Object捕获。
两种测试情况的解析
情况1:直接重定向Invoke-Expression
Invoke-Expression "Test-Log" *>&1 | Tee-Object -Variable output | Out-Null
这里的*>&1仅作用于iex自身的输出流,而Test-Log中Write-Error输出的内容并没有进入iex的管道,直接流向了会话的顶层错误流,所以最终$output里看不到错误信息。
情况2:用脚本块包裹Invoke-Expression
&{Invoke-Expression "Test-Log"} *>&1 | Tee-Object -Variable output | Out-Null
脚本块&{...}是一个独立的执行单元,会收集其内部所有命令产生的全部流(包括iex转发过来的错误流)。此时*>&1重定向的是脚本块的所有输出流,自然就能把错误流一并捕获到$output中。
替代解决方案
除了用脚本块包裹的方式,还有两种实用的处理方法:
用
Invoke-Command替代Invoke-ExpressionInvoke-Command会正确传递内部执行代码的所有流,直接重定向即可捕获错误:# 直接调用已定义的函数 Invoke-Command -ScriptBlock ${function:Test-Log} *>&1 | Tee-Object -Variable output | Out-Null # 执行字符串形式的命令 Invoke-Command -ScriptBlock ([scriptblock]::Create("Test-Log")) *>&1 | Tee-Object -Variable output | Out-Null临时修改错误行为偏好
将$ErrorActionPreference设为"Stop",会把非终止错误转为终止错误,此时iex的*>&1就能捕获到这类错误(注意:这会改变错误的默认处理逻辑,非终止错误会中断执行,需根据场景使用):$originalErrorPref = $ErrorActionPreference $ErrorActionPreference = "Stop" try { Invoke-Expression "Test-Log" *>&1 | Tee-Object -Variable output | Out-Null } finally { $ErrorActionPreference = $originalErrorPref }
内容的提问来源于stack exchange,提问作者Little Train
相关产品推荐
相关产品推荐

