2012-01-06 2 views
61

StandardErrorStandardOutput 속성에 액세스 할 때 Powershell의 Start-Process 명령에 버그가 있습니까? 나는 다음을 실행하면시작 프로세스의 표준 출력 및 오류 캡처

나는 더 출력을

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

을 얻을하지만 출력을 파일로 리디렉션 있다면 어떤 이유로 설계되었습니다 방법 Start-Process의 예상 된 결과

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

이 특별한 경우에는 실제로 시작 프로세스가 필요합니까? ...'$ process = ping localhost'#는 출력을 프로세스 변수에 저장합니다. – mjsr

+1

참. 나는 반환과 논쟁을 다루는 더 깨끗한 방법을 찾고 있었다. 나는 당신이 보여준대로 대본을 쓰는 것을 끝내었다. – jzbruno

답변

84

를 얻을. 여기에 파일을 전송하지 않고 그것을 얻을 수있는 방법이있다 : 질문에 주어진 코드

$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 
+6

답변을 수락합니다. 나는 그들이 사용되지 않는 속성을 만들지 않았 으면 좋겠다. 매우 혼란 스럽다. – jzbruno

+1

@jzbruno PowerShell 팀은 StandardOutput/StandardError 속성을 만들지 않았습니다 ... 기본 [System.Diagnostics.Process] (http://msdn.microsoft.com/en-us/library/system)의 일부입니다. diagnostics.process.aspx) 개체를 만듭니다. 그러나 'UseShellExecute' 속성이 false로 설정된 경우에만 사용할 수 있습니다. 따라서 PowerShell 팀이 백그라운드에서 '시작 프로세스'를 구현 한 방법에 따라 ... 불행히도 소스 코드를 볼 수 없습니다 .-( –

+2

이 방법으로 프로세스를 실행하는 데 문제가 있으면 여기에서 대답을 참조하십시오 http : //itackoverflow.com/questions/11531068/powershell-capturing-standard-out-and-error-with-process-object, WaitForExit 및 StandardOutput에 약간의 수정이 있습니다 .ReadToEnd –

13

, 나는 개시 변수가 ExitCode 속성을 읽는 것은 일을해야한다고 생각합니다.

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

참고가 -PassThru와 잠깐 PARAMS을 추가해야합니다 (예에서와 같이)는

+0

인수 목록에 변수가 들어 있으면 어떻게 될까요? 그것은 확대되지 않는 것 같습니다. –

+1

당신은 따옴표로 인자 목록을 넣을 것입니다. 그게 효과가 있니? ... $ process = 시작 프로세스 -FilePath ping -ArgumentList "-t localhost -n 1"-NoNewWindow -PassThru -Wait – JJones

8

나는 또한이 문제를했고 Andys 코드를 사용하여 결국 (이 잠시 동안 나를 붙 잡았다) 있음 여러 명령을 실행해야 할 때 정리할 함수를 만들려면 stderr, stdout 및 exit 코드를 객체로 반환합니다. 함수에서 주목해야 할 점은 경로에서 \를 받아들이지 않으므로 전체 경로를 사용해야한다는 것입니다.

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 
    } 
} 

여기 @Andy 아리스 멘디와 @LPG에서 위의 그 사례로

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

좋은 생각이지만 문법이 제대로 작동하지 않는 것 같습니다. 매개 변수 목록에서 param ([type] $ ArgumentName) 구문을 사용하면 안됩니까? 이 함수에 예제 호출을 추가 할 수 있습니까? – Lockszmith

4

정말 한 문제를 사용하는 방법은 다음과 같습니다. 당신은 항상 사용해야합니다

$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 
+0

이것이 교착 상태 문제를 해결합니까? –

+0

어디서 읽었습니까? "$ p.WaitForExit()"전에 항상 $ p.StandardOutput.ReadToEnd()를 사용해야합니다. 실행 한 라인이 WaitForExit이고 프로세스가 완료되지 않은 경우 (나중에 더 많은 stderr 또는 stdout을 출력하는 경우) 나중에 출력이 더 많아지면 버퍼가 고갈되면 출력이 사라집니다. – CJBS

+0

위의 내 의견에 대해서는 나중에 큰 출력의 경우 교착 상태 및 버퍼 오버 플로우와 관련된 대답에 대한 의견을 보았습니다.하지만 버퍼가 끝까지 읽혀지기 때문에 프로세스가 완료되었으므로 더 많은 출력이 누락 될 수 있습니다. 내가 놓친 게 있니? – CJBS

3

중요 :

우리는 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 
    } 
} 
이 문제에 대한

추가 정보를 찾을 수 at MSDN : 부모 프로세스가 p.StandardError.ReadToEnd 전에 p.WaitForExit를 호출하는 경우

이 교착 상태가 발생할 수 있습니다 대신에 아래의 적응 버전을 사용 자식 프로세스는 리디렉션 된 스트림을 채우기에 충분한 텍스트를 씁니다. 부모 프로세스는 자식 프로세스가 종료 될 때까지 무기한 대기합니다. 자식 프로세스는 부모가 전체 StandardError 스트림에서 읽을 수 있도록 무기한 대기합니다.

편집 : Try 블록의 끝에 중괄호가 누락되었습니다.

+1

이 코드는 여전히 MSDN 링크와 마찬가지로 ReadToEnd()에 대한 동기 호출로 인해 교착 상태가 발생합니다. – bergmeister

+0

이제 내 문제가 해결 된 것 같습니다. 나는 왜 그것이 매달렸는지 완전히 이해하지 못한다는 것을 인정해야하지만, 빈 stderr가 프로세스가 끝내는 것을 막은 것으로 보인다. 이상한 일은 오랜 시간 동안 작동했기 때문에 갑자기 Xmas가 시작되기 직전에 실패하여 많은 Java 프로세스가 중단되었습니다. – rhellem

관련 문제