Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Obtaining ExitCode using Start-Process and WaitForExit instead of -Wait

I'm trying to run a program from PowerShell, wait for the exit, then get access to the ExitCode, but I am not having much luck. I don't want to use -Wait with Start-Process, as I need some processing to carry on in the background.

Here's a simplified test script:

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 

Running this script will cause Notepad to be started. After this is closed manually, the exit code will be printed, and it will start again, without using -wait. No ExitCode is provided when this is quit:

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: 

I need to be able to perform additional processing between starting the program and waiting for it to quit, so I can't make use of -Wait. How can I do this and still have access to the .ExitCode property from this process?

like image 474
Richard Avatar asked Apr 21 '12 19:04

Richard


2 Answers

There are two things to remember here. One is to add the -PassThru argument and two is to add the -Wait argument. You need to add the wait argument because of this defect.

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

Once you do this a process object is passed back and you can look at the ExitCode property of that object. Here is an example:

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

If you run it without -PassThru or -Wait, it will print out nothing.

The same answer is here: How do I run a Windows installer and get a succeed/fail value in PowerShell?

It's also worth noting that there's a workaround mentioned in the "defect report" link above, which is as following:

# 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) 
like image 178
Daniel McQuiston Avatar answered Sep 17 '22 08:09

Daniel McQuiston


While trying out the final suggestion above, I discovered an even simpler solution. All I had to do was cache the process handle. As soon as I did that, $process.ExitCode worked correctly. If I didn't cache the process handle, $process.ExitCode was null.

example:

$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)" } 
like image 44
Adrian Avatar answered Sep 18 '22 08:09

Adrian