및 속성에 Start-Process
액세스 할 때 PowerShell의 명령에 버그가 있습니까?StandardError
StandardOutput
다음을 실행하면 출력이 표시되지 않습니다.
$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
답변
그것이 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
답변
질문에 주어진 코드에서 시작 변수의 ExitCode 속성을 읽는 것이 작동해야한다고 생각합니다.
$process = Start-Process -FilePath ping -ArgumentList localhost -NoNewWindow -PassThru -Wait
$process.ExitCode
(귀하의 예에서 -PassThru
와 같이) 및 -Wait
매개 변수 를 추가해야합니다 (잠시 동안 저를 잡았습니다).
답변
나는 또한이 문제가 있었고 Andy의 코드 를 사용하여 여러 명령을 실행해야 할 때 정리하는 함수를 만들었습니다.
stderr, stdout 및 종료 코드를 객체로 반환합니다. 한 가지주의 할 점 : 함수는 .\
경로에서 허용되지 않습니다 . 전체 경로를 사용해야합니다.
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"
답변
중대한:
위에서 제공 한 LPG 기능을 사용하고 있습니다 .
그러나 여기에는 많은 출력을 생성하는 프로세스를 시작할 때 발생할 수있는 버그가 포함되어 있습니다. 이로 인해이 기능을 사용할 때 교착 상태가 발생할 수 있습니다. 대신 아래의 개조 된 버전을 사용하십시오.
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를 호출하고 자식 프로세스가 리디렉션 된 스트림을 채우기에 충분한 텍스트를 쓰는 경우 교착 상태가 발생할 수 있습니다. 부모 프로세스는 자식 프로세스가 종료 될 때까지 무기한 대기합니다. 자식 프로세스는 부모가 전체 StandardError 스트림에서 읽을 때까지 무기한 대기합니다.
답변
저는 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
답변
다음은 3 개의 새 속성으로 표준 System.Diagnostics.Process를 반환하는 내 버전의 함수입니다.
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.WindowStyle = 'Hidden'
$pinfo.CreateNoWindow = $True
$pinfo.Arguments = $commandArguments
$p = New-Object System.Diagnostics.Process
$p.StartInfo = $pinfo
$p.Start() | Out-Null
$stdout = $p.StandardOutput.ReadToEnd()
$stderr = $p.StandardError.ReadToEnd()
$p.WaitForExit()
$p | Add-Member "commandTitle" $commandTitle
$p | Add-Member "stdout" $stdout
$p | Add-Member "stderr" $stderr
}
Catch {
}
$p
}
답변
다음은 다른 powershell 프로세스에서 출력을 얻는 복잡한 방법입니다.
start-process -wait -nonewwindow powershell 'ps | Export-Clixml out.xml'; import-clixml out.xml