【问题标题】:PowerShell, stream Process output and errors while running external processPowerShell,流 运行外部进程时的进程输出和错误
【发布时间】:2014-04-23 08:43:04
【问题描述】:

我正在使用 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 中做同样的事情吗?

【问题讨论】:

    标签: powershell process


    【解决方案1】:

    在 PowerShell 中有什么方法可以在进程运行时流式传输输出和错误的内容?在纯 .NET 中我们可以订阅 Process 类的事件,我可以在 PowerShell 中做同样的事情吗?

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

    对象事件是一个.Net对象,它不仅在对象中具有通常的PropertiesMethods,而且还有另一个名为Event的成员strong>,您可以使用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 $_}
    

    【讨论】:

    • 只是一个简短的评论。不要考虑在进程上调用WaitForExit,因为在进程完成之前不会生成任何输出。
    • 请注意,取消注册事件很重要。没有它,即使在进程退出后几秒钟甚至脚本本身完成后,我也会发生一些事件。我脚本中的 Write-Host:s 将在命令行提示符后打印它们的输出!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-01-25
    • 2017-08-08
    • 2019-08-27
    • 2012-02-06
    • 1970-01-01
    • 2018-03-28
    相关资源
    最近更新 更多