【发布时间】:2017-11-13 06:23:58
【问题描述】:
我想在 PowerShell 中捕获一些流输出。例如
cmd /c "echo hi && foo"
这个命令应该先打印 hi 然后再炸弹。我知道我可以使用 -ErrorVariable:
Invoke-Command { cmd /c "echo hi && foo" } -ErrorVariable ev
但是有一个问题:对于长时间运行的命令,我想流式传输输出,而不是捕获它,并且只在命令末尾获取 stderr/stdout 输出
理想情况下,我希望能够将 stderr 和 stdout 拆分并通过管道传输到两个不同的流 - 并将 stdout 传输回调用者,但要准备好在发生错误时抛出 stderr。类似的东西
$stdErr
Invoke-Command "cmd" "/c `"echo hi && foo`"" `
-OutStream (Get-Command Write-Output) `
-ErrorAction {
$stdErr += "`n$_"
Write-Error $_
}
if ($lastexitcode -ne 0) { throw $stdErr}
我能得到的最接近的是使用管道,但这并不能让我区分 stdout 和 stderr 所以我最终抛出了整个输出流
function Invoke-Cmd {
<#
.SYNOPSIS
Executes a command using cmd /c, throws on errors.
#>
param([string]$Cmd)
)
$out = New-Object System.Text.StringBuilder
# I need the 2>&1 to capture stderr at all
cmd /c $Cmd '2>&1' |% {
$out.AppendLine($_) | Out-Null
$_
}
if ($lastexitcode -ne 0) {
# I really just want to include the error stream here
throw "An error occurred running the command:`n$($out.ToString())"
}
}
常见用法:
Invoke-Cmd "GitVersion.exe" | ConvertFrom-Json
请注意,仅使用 ScriptBlock 的类似版本(并且检查 [ErrorRecord] 的输出流是不可接受的,因为有许多“不喜欢”直接从 PowerShell 进程执行的程序
.NET System.Diagnostics.Process API 让我可以做到这一点......但我不能从流处理程序内部流式输出(因为线程和阻塞 - 虽然我想我可以使用 while 循环和流/清除收集到的输出)
【问题讨论】:
标签: powershell stream powershell-4.0 piping