用Start-Process捕获标准和错误

访问StandardErrorStandardOutput属性时,Powershell的Start-Process命令中是否存在错误?

如果我运行以下,我得不到输出

 $process = Start-Process -FilePath ping -ArgumentList localhost -NoNewWindow -PassThru -Wait $process.StandardOutput $process.StandardError 

但是,如果我redirect到一个文件的输出,我得到了预期的结果

 $process = Start-Process -FilePath ping -ArgumentList localhost -NoNewWindow -PassThru -Wait -RedirectStandardOutput stdout.txt -RedirectStandardError stderr.txt 

Start-Process就是这样devise的。 这是一种不用发送到文件就能获得的方法:

 $pinfo = New-Object System.Diagnostics.ProcessStartInfo $pinfo.FileName = "ping.exe" $pinfo.RedirectStandardError = $true $pinfo.RedirectStandardOutput = $true $pinfo.UseShellExecute = $false $pinfo.Arguments = "localhost" $p = New-Object System.Diagnostics.Process $p.StartInfo = $pinfo $p.Start() | Out-Null $p.WaitForExit() $stdout = $p.StandardOutput.ReadToEnd() $stderr = $p.StandardError.ReadToEnd() Write-Host "stdout: $stdout" Write-Host "stderr: $stderr" Write-Host "exit code: " + $p.ExitCode 

在问题给出的代码中,我认为阅读启动variables的ExitCode属性应该工作。

 $process = Start-Process -FilePath ping -ArgumentList localhost -NoNewWindow -PassThru -Wait $process.ExitCode 

请注意,(在你的例子中),你需要添加-PassThru和-Wait params(这让我出了一阵子)

我也有这个问题,并最终使用Andys代码来创build一个函数来清理多个命令需要运行时,它会返回stderr,标准输出和退出代码作为对象。 有一点要注意的是函数不会接受。在path中,必须使用完整path。

 Function Execute-Command ($commandTitle, $commandPath, $commandArguments) { $pinfo = New-Object System.Diagnostics.ProcessStartInfo $pinfo.FileName = $commandPath $pinfo.RedirectStandardError = $true $pinfo.RedirectStandardOutput = $true $pinfo.UseShellExecute = $false $pinfo.Arguments = $commandArguments $p = New-Object System.Diagnostics.Process $p.StartInfo = $pinfo $p.Start() | Out-Null $p.WaitForExit() [pscustomobject]@{ commandTitle = $commandTitle stdout = $p.StandardOutput.ReadToEnd() stderr = $p.StandardError.ReadToEnd() ExitCode = $p.ExitCode } } 

这里是如何使用它

 $DisableACMonitorTimeOut = Execute-Command -commandTitle "Disable Monitor Timeout" -commandPath "C:\Windows\System32\powercfg.exe" -commandArguments " -x monitor-timeout-ac 0" 

上面这些来自@Andy Arismendi和@LPG的例子真的有麻烦了。 你应该总是使用:

 $stdout = $p.StandardOutput.ReadToEnd() 

打电话之前

 $p.WaitForExit() 

完整的例子是:

 $pinfo = New-Object System.Diagnostics.ProcessStartInfo $pinfo.FileName = "ping.exe" $pinfo.RedirectStandardError = $true $pinfo.RedirectStandardOutput = $true $pinfo.UseShellExecute = $false $pinfo.Arguments = "localhost" $p = New-Object System.Diagnostics.Process $p.StartInfo = $pinfo $p.Start() | Out-Null $stdout = $p.StandardOutput.ReadToEnd() $stderr = $p.StandardError.ReadToEnd() $p.WaitForExit() Write-Host "stdout: $stdout" Write-Host "stderr: $stderr" Write-Host "exit code: " + $p.ExitCode 

重要:

我们一直在使用LPG上面提供的function。 但是,这包含您在启动生成大量输出的进程时可能遇到的错误。 由于这个原因,使用这个函数可能会导致死锁。 请使用下面的改编版本:

 Function Execute-Command ($commandTitle, $commandPath, $commandArguments) { Try { $pinfo = New-Object System.Diagnostics.ProcessStartInfo $pinfo.FileName = $commandPath $pinfo.RedirectStandardError = $true $pinfo.RedirectStandardOutput = $true $pinfo.UseShellExecute = $false $pinfo.Arguments = $commandArguments $p = New-Object System.Diagnostics.Process $p.StartInfo = $pinfo $p.Start() | Out-Null [pscustomobject]@{ commandTitle = $commandTitle stdout = $p.StandardOutput.ReadToEnd() stderr = $p.StandardError.ReadToEnd() ExitCode = $p.ExitCode } $p.WaitForExit() } Catch { exit } } 

有关此问题的更多信息,请参阅MSDN :

如果父进程在p.StandardError.ReadToEnd之前调用p.WaitForExit并且subprocess写入足够的文本来填充redirect的stream,则可能会导致死锁情况。 父进程将无限期地等待subprocess退出。 subprocess将无限期地等待父进程从完整的StandardErrorstream中读取。

编辑:添加一个缺less大括号在Try块的结尾。