我正在编写一个Powershell cmdlet,它需要执行命令并将其stderr输出存储到临时文件中以供以后处理。此输出列出了cmdlet稍后可能使用的COM端口。
# mostly side-effect-free information gathering
$info = [IO.Path]::GetTempFileName()
info-gather.exe 2>$info
Get-Content $info | ForEach-Object {
# processing
}
Remove-Item $info
# serious things with serious side effects start here
我希望这个cmdlet能够实现-WhatIf
,因为它会产生非平凡的副作用。但是,-WhatIf
行为将接管info-gather.exe
命令,并且它永远不会被执行。相反,它打印:
如果:在目标“temp \ path \ to \ tmp78A4.tmp”上执行“输出到文件”操作
因为永远不会执行此命令,所以内部处理也不会发生,并且我的cmdlet的其余部分都没有执行,因为它不知道要使用哪些端口,因此{{1}很大程度上没用。
如何在不阻止cmdlet其余部分的情况下绕过此块的-WhatIf
?
答案 0 :(得分:2)
您可以使用try...finally
设置然后重置$WhatIfPreference
variable。
$script:oldWhatIfPrefernence = $WhatIfPreference
try {
$WhatIfPreference = $false
$info = [IO.Path]::GetTempFileName()
info-gather.exe 2>$info
Get-Content $info | ForEach-Object {
# processing
}
Remove-Item $info
} finally {
$WhatIfPreference = $script:oldWhatIfPreference
}
如果您没有使用2>
重定向,还有另一种方法。您可以明确地将-WhatIf
开关传递给多个cmdlet,并仅覆盖-WhatIf
部分。
Remove-Item $info -WhatIf:$false
尽管如此,zneak's answer不涉及临时文件也非常优雅。
答案 1 :(得分:1)
一种解决方案是"重定向" stderr到stdout。执行此操作,Powershell将错误记录附加到标准输出,可以使用Out-String
将其转换为常规字符串。在我的情况下(YMMV取决于程序),第一个错误记录显示"该程序出现错误"第二个错误记录是实际的完整stderr输出。命令不会向标准输出写入任何内容,这也简化了这一点,因此无法进行过滤。
我能够改变foreach循环来使用它:
((info-gather.exe 2>&1)[1] | Out-String) -split "[`r`n]" | foreach-object
由于这不会写入文件,-WhatIf
不再覆盖它。
可能有一种更简单,更简洁的方法(例如,如果有办法将stderr直接传递给Out-String
)。