如何从 Start-Process 获取输出

27 浏览
0 Comments

如何从 Start-Process 获取输出

当访问PowerShell的Start-Process命令的StandardErrorStandardOutput属性时,是否存在bug?

如果我运行以下命令,将不会有任何输出:

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

但是,如果将输出重定向到文件中,我会得到预期的结果:

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

0
0 Comments

问题的原因是在使用Start-Process函数时,当启动的进程生成大量输出时,可能会导致死锁。在原始函数中,使用了ReadToEnd()方法来读取进程的标准输出和标准错误输出,但当子进程写入足够的文本来填充重定向的流时,父进程在调用p.WaitForExit之前调用p.StandardError.ReadToEnd可能会导致死锁。为了解决这个问题,提供了一个修复的函数Execute-Command,采用异步方式读取进程的输出,避免了死锁的问题。

修复的函数Execute-Command的代码如下:

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

}

}

在这个修复的函数中,使用异步方式读取进程的标准输出和标准错误输出,避免了死锁的问题。

据说,这个修复的函数已经解决了作者遇到的问题。作者承认自己并不完全理解为什么会出现死锁,但是看起来空的标准错误输出会阻塞进程的结束。作者表示奇怪的是,这个函数在很长一段时间内都正常工作,但在圣诞节之前突然开始失败,导致很多Java进程挂起。

最后,还提到了一个问题,是否有一个示例展示如何使用这个修复的函数Execute-Command,但文章中并没有给出这个示例。

0
0 Comments

问题原因:

问题出现的原因是在使用Start-Process命令时,无法获取输出结果。

解决方法:

要解决这个问题,可以通过以下步骤来获取Start-Process命令的输出结果:

1. 在命令中使用-PassThru参数,以便将进程对象存储在变量中。

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

2. 使用$process.WaitForExit()等待进程执行完毕。

3. 使用$process.ExitCode来获取进程的退出代码。

代码示例:

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

需要注意的是,参数-PassThru-Wait在命令中需要被添加,否则无法获取输出结果。

其他问题解决方法:

如果参数列表中包含变量,可以将参数列表放在引号中来展开变量。

$process = Start-Process -FilePath ping -ArgumentList " -t localhost -n 1" -NoNewWindow -PassThru -Wait

如果想要在PowerShell窗口中显示输出结果并将其记录到日志文件中,可以使用以下方法:

$process = Start-Process -FilePath ping -ArgumentList localhost -NoNewWindow -PassThru -Wait | Tee-Object -FilePath "logfile.txt"

需要注意的是,使用-NoNewWindow参数时无法与-Verb runAs参数一起使用。

0
0 Comments

问题:如何从Start-Process获取输出?

原因:Start-Process是为了某些原因而设计的。但是,它可以通过以下方式获取输出而不发送到文件:

$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

解决方法:使用System.Diagnostics.Process对象的StandardOutput和StandardError属性来获取输出。但这些属性只在UseShellExecute属性设置为false时可用。因此,这取决于PowerShell团队在幕后如何实现Start-Process。如果无法以这种方式运行进程,请参阅此处的已接受答案,其中对WaitForExit和StandardOutput.ReadToEnd进行了轻微修改。

0