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

时间:2014-04-23 08:43:05

标签: 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

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

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

1 个答案:

答案 0 :(得分:14)

  

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

当然可以!您需要的是Object Events

  

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

注册订阅

以下是PowerShell forums的略微修改示例。它将异步输出ping命令中的数据(at least from the script point of view):

# 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 $_}