用Start-Process捕获标准和错误
访问StandardError
和StandardOutput
属性时,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块的结尾。