我正在使用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中执行相同的操作吗?
答案 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 $_}