PowerShell,stream在运行外部进程时处理输出和错误

Raf*_*aeu 8 powershell process

我正在使用PowerShell脚本来执行控制台应用程序,我试图从那里重定向标准输出和标准错误.我使用的代码如下:

$ProcessInfo = New-Object System.Diagnostics.ProcessStartInfo 
$ProcessInfo.FileName = "myExe.exe"
$ProcessInfo.Arguments = "bla bla bla"
$ProcessInfo.RedirectStandardError = $true 
$ProcessInfo.RedirectStandardOutput = $true 
$ProcessInfo.UseShellExecute = $false 
$Process = New-Object System.Diagnostics.Process 
$Process.StartInfo = $ProcessInfo 

$Process.Start() | Out-Null 
$output = $Process.StandardOutput.ReadToEnd() 
$errors = $Process.StandardError.ReadToEnd()
$Process.WaitForExit() 
$output 
$errors 

return $Process.ExitCode
Run Code Online (Sandbox Code Playgroud)

到目前为止一切都那么好,如果我有错误,我可以看到它重定向到我的PowerShell控制台,如果我有输出,它也被重定向.问题是这个过程需要10分钟,与此同时我们不知道发生了什么.

在PowerShell中是否有任何方法我可以在进程运行时流式传输输出和错误的内容?在纯.NET中,我们可以订阅Process类的事件,我可以在PowerShell中执行相同的操作吗?

bea*_*ker 15

在PowerShell中是否有任何方法我可以在进程运行时流式传输输出和错误的内容?在纯.NET中,我们可以订阅Process类的事件,我可以在PowerShell中执行相同的操作吗?

你当然可以!你需要的是一个对象事件:

对象事件是一个.Net对象,它不仅具有对象中常用的属性方法,而且还有另一个名为Event的成员,您可以使用Register-ObjectEvent注册订阅

以下是来自PowerShell论坛的略微修改的示例.它将异步输出ping命令中的数据(至少从脚本的角度来看):

# Setup stdin\stdout redirection
$StartInfo = New-Object System.Diagnostics.ProcessStartInfo -Property @{
                FileName = 'ping.exe'
                Arguments = '-t 127.0.0.1'
                UseShellExecute = $false
                RedirectStandardOutput = $true
                RedirectStandardError = $true
            }

# Create new process
$Process = New-Object System.Diagnostics.Process

# Assign previously created StartInfo properties
$Process.StartInfo = $StartInfo

# Register Object Events for stdin\stdout reading
$OutEvent = Register-ObjectEvent -Action {
    Write-Host $Event.SourceEventArgs.Data
} -InputObject $Process -EventName OutputDataReceived

$ErrEvent = Register-ObjectEvent -Action {
    Write-Host $Event.SourceEventArgs.Data
} -InputObject $Process -EventName ErrorDataReceived

# Start process
[void]$Process.Start()

# Begin reading stdin\stdout
$Process.BeginOutputReadLine()
$Process.BeginErrorReadLine()

# Do something else while events are firing
do
{
    Write-Host 'Still alive!' -ForegroundColor Green
    Start-Sleep -Seconds 1
}
while (!$Process.HasExited)

# Unregister events
$OutEvent.Name, $ErrEvent.Name |
    ForEach-Object {Unregister-Event -SourceIdentifier $_}
Run Code Online (Sandbox Code Playgroud)

  • 快速评论一下.不要考虑在进程上调用`WaitForExit`,因为在进程完成之前不会生成任何输出. (5认同)
  • 请注意,注销事件很重要。如果没有它,即使在进程退出几秒钟后甚至在脚本本身完成后,我也会发生一些事件。我的脚本中的 Write-Host:s 将在命令行提示后打印其输出! (2认同)