source

-Wait 대신 Start-Process 및 WaitForExit을 사용하여 종료 코드 가져오기

nicesource 2023. 4. 29. 09:27
반응형

-Wait 대신 Start-Process 및 WaitForExit을 사용하여 종료 코드 가져오기

PowerShell에서 프로그램을 실행하고 종료를 기다렸다가 종료 코드에 액세스하려고 하지만 운이 좋지 않습니다.사용 안 함-Wait백그라운드에서 진행할 처리가 필요하기 때문에.

다음은 간단한 테스트 스크립트입니다.

cd "C:\Windows"

# ExitCode is available when using -Wait...
Write-Host "Starting Notepad with -Wait - return code will be available"
$process = (Start-Process -FilePath "notepad.exe" -PassThru -Wait)
Write-Host "Process finished with return code: " $process.ExitCode

# ExitCode is not available when waiting separately
Write-Host "Starting Notepad without -Wait - return code will NOT be available"
$process = (Start-Process -FilePath "notepad.exe" -PassThru)
$process.WaitForExit()
Write-Host "Process exit code should be here: " $process.ExitCode

이 스크립트를 실행하면 메모장이 시작됩니다.수동으로 닫으면 종료 코드가 인쇄되고 사용하지 않고 다시 시작됩니다.-wait종료 시 종료 코드가 제공되지 않습니다.

Starting Notepad with -Wait - return code will be available
Process finished with return code:  0
Starting Notepad without -Wait - return code will NOT be available
Process exit code should be here:

프로그램을 시작하고 종료할 때까지 추가 처리를 수행할 수 있어야 하므로 사용할 수 없습니다.-Wait이 작업을 수행하면서 에 액세스할 수 있는 방법은 무엇입니까?이 프로세스에서 Code 속성을 종료하시겠습니까?

여기서 기억해야 할 두 가지가 있습니다.하나는 다음을 추가하는 것입니다.-PassThru인수와 두 번째는 추가하는 것입니다.-Wait논쟁.결함 때문에 wait 인수를 추가해야 합니다.

-PassThru [<SwitchParameter>]
    Returns a process object for each process that the cmdlet started. By default,
    this cmdlet does not generate any output.

이 작업을 수행하면 프로세스 개체가 다시 전달되고 해당 개체의 ExitCode 속성을 확인할 수 있습니다.다음은 예입니다.

$process = start-process ping.exe -windowstyle Hidden -ArgumentList "-n 1 -w 127.0.0.1" -PassThru -Wait
$process.ExitCode

# This will print 1

를 사용하지 않고 실행할 경우-PassThru또는-Wait아무것도 출력되지 않습니다.

같은 대답이 여기에 있습니다.윈도우즈 설치 관리자를 실행하고 PowerShell에서 성공/실패 값을 얻는 방법은 무엇입니까?

위의 "결함 보고서" 링크에 언급된 해결 방법이 있는데, 이는 다음과 같습니다.

# Start the process with the -PassThru command to be able to access it later
$process = Start-Process 'ping.exe' -WindowStyle Hidden -ArgumentList '-n 1 -w 127.0.0.1' -PassThru

# This will print out False/True depending on if the process has ended yet or not
# Needs to be called for the command below to work correctly
$process.HasExited

# This will print out the actual exit code of the process
$process.GetType().GetField('exitCode', 'NonPublic, Instance').GetValue($process)

위의 최종 제안을 시도하는 동안, 저는 훨씬 더 간단한 해결책을 발견했습니다.프로세스 핸들을 캐시하기만 하면 되었습니다.내가 그것을 하자마자 $process.종료 코드가 올바르게 작동했습니다.프로세스 핸들을 캐시하지 않았다면 $process.종료 코드가 null입니다.

예:

$proc = Start-Process $msbuild -PassThru
$handle = $proc.Handle # cache proc.Handle
$proc.WaitForExit();

if ($proc.ExitCode -ne 0) {
    Write-Warning "$_ exited with status code $($proc.ExitCode)"
}

당신이 할 수 있는 두 가지는...

  1. 시스템을 만듭니다.진단.개체를 수동으로 처리하고 시작-프로세스를 생략합니다.
  2. 백그라운드 작업에서 실행 파일 실행(비대화형 프로세스에만 해당)

다음 중 하나를 수행할 수 있는 방법은 다음과 같습니다.

$pinfo = New-Object System.Diagnostics.ProcessStartInfo
$pinfo.FileName = "notepad.exe"
$pinfo.RedirectStandardError = $true
$pinfo.RedirectStandardOutput = $true
$pinfo.UseShellExecute = $false
$pinfo.Arguments = ""
$p = New-Object System.Diagnostics.Process
$p.StartInfo = $pinfo
$p.Start() | Out-Null
#Do Other Stuff Here....
$p.WaitForExit()
$p.ExitCode

OR

Start-Job -Name DoSomething -ScriptBlock {
    & ping.exe somehost
    Write-Output $LASTEXITCODE
}
#Do other stuff here
Get-Job -Name DoSomething | Wait-Job | Receive-Job

프로세스가 끝났음에도 불구하고 '-Wait' 옵션이 차단되는 것처럼 보였습니다.

아드리안의 해결책을 시도해봤는데 효과가 있었습니다.하지만 저는 프로세스 핸들을 가져오는 부작용에 의존하는 대신 Wait-Process를 사용했습니다.

그래서:

$proc = Start-Process $msbuild -PassThru
Wait-Process -InputObject $proc

if ($proc.ExitCode -ne 0) {
    Write-Warning "$_ exited with status code $($proc.ExitCode)"
}

또는 추가해 보십시오...

$code = @"
[DllImport("kernel32.dll")]
public static extern int GetExitCodeProcess(IntPtr hProcess, out Int32 exitcode);
"@
$type = Add-Type -MemberDefinition $code -Name "Win32" -Namespace Win32 -PassThru
[Int32]$exitCode = 0
$type::GetExitCodeProcess($process.Handle, [ref]$exitCode)

이 코드를 사용하면 PowerShell에서 리디렉션된 출력/오류 스트림을 관리하도록 할 수 있지만 시스템에서는 이를 수행할 수 없습니다.진단.과정.()를 직접 시작합니다.

여기 이 주제에 대한 변형이 있습니다.Cisco Amp를 제거하고 기다려 종료 코드를 가져오려고 합니다.그러나 제거 프로그램은 "un_a"라는 두 번째 프로그램을 시작하고 종료합니다.이 코드를 사용하면 un_a가 완료될 때까지 기다릴 수 있습니다. 종료 코드는 "재부팅 필요"를 의미하는 3010입니다.이것은 실제로 .bat 파일 안에 있습니다.

만약 당신이 folding@home을 제거하고 싶다면, 그것은 비슷한 방식으로 작동합니다.

rem uninstall cisco amp, probably needs a reboot after

rem runs Un_A.exe and exits

rem start /wait isn't useful
"c:\program files\Cisco\AMP\6.2.19\uninstall.exe" /S

powershell while (! ($proc = get-process Un_A -ea 0)) { sleep 1 }; $handle = $proc.handle; 'waiting'; wait-process Un_A; exit $proc.exitcode

언급URL : https://stackoverflow.com/questions/10262231/obtaining-exitcode-using-start-process-and-waitforexit-instead-of-wait

반응형