21

I want to repeatedly execute a program in a loop.

Sometimes, the program crashes, so I want to kill it so the next iteration can correctly start. I determine this via timeout.

I have the timeout working but cannot get the Exit Code of the program, which I also need to determine its result.

Before, I did not wait with timeout, but just used -wait in Start-Process, but this made the script hang if the started program crashed. With this setup I could correctly get the exit code though.

I am executing from ISE.

for ($i=0; $i -le $max_iterations; $i++)
{
    $proc = Start-Process -filePath $programtorun -ArgumentList $argumentlist -workingdirectory $programtorunpath -PassThru
    # wait up to x seconds for normal termination
    Wait-Process -Timeout 300 -Name $programname
    # if not exited, kill process
    if(!$proc.hasExited) {
        echo "kill the process"
        #$proc.Kill() <- not working if proc is crashed
        Start-Process -filePath "taskkill.exe" -Wait -ArgumentList '/F', '/IM', $fullprogramname
    }
    # this is where I want to use exit code but it comes in empty
    if ($proc.ExitCode -ne 0) {
       # update internal error counters based on result
    }
}

How can I

  1. Start a process
  2. Wait for it to orderly execute and finish
  3. Kill it if it is crashed (e. g. hits timeout)
  4. get exit code of process
Andreas Reiff
  • 7,961
  • 10
  • 50
  • 104
  • [How to wait and kill a timeout process in Powershell](https://stackoverflow.com/q/19532998/995714) – phuclv Feb 18 '18 at 00:43

1 Answers1

31

You can terminate the process more simply using $proc | kill or $proc.Kill(). Be aware, that you won't be able to retrieve a exit code in this case, you should rather just update the internal error counter:

for ($i=0; $i -le $max_iterations; $i++)
{
    $proc = Start-Process -filePath $programtorun -ArgumentList $argumentlist -workingdirectory $programtorunpath -PassThru

    # keep track of timeout event
    $timeouted = $null # reset any previously set timeout

    # wait up to x seconds for normal termination
    $proc | Wait-Process -Timeout 4 -ErrorAction SilentlyContinue -ErrorVariable timeouted

    if ($timeouted)
    {
        # terminate the process
        $proc | kill

        # update internal error counter
    }
    elseif ($proc.ExitCode -ne 0)
    {
        # update internal error counter
    }
}
Luk
  • 5,371
  • 4
  • 40
  • 55
Martin Brandl
  • 56,134
  • 13
  • 133
  • 172
  • Thank you! The Wait-Process waits correctly for 400s in your solution, but the "# terminate the process" clause never hits after timeout - so also, the process is never killed, and after next iteration, 2 processes are running. (I tested with a small timeout to force this case.) – Andreas Reiff Apr 29 '16 at 10:15
  • 2
    You are right, I thought Wait-Process will return something. I edited my answer, now I assign the error message to $timeouted and in case a timeout occurred, It is set. – Martin Brandl Apr 29 '16 at 10:22
  • Thanks! (There was a minor typo.) Working great! – Andreas Reiff Apr 29 '16 at 11:42
  • @MartinBrandl Can you elaborate on what the `-ea 0 -ev timeouted` values are? I can't find these documented anywhere but I do need to determine if a Wait-Process timed out or not, and it looks like those are what you are using in your example code. – rom99 Jul 30 '18 at 10:56
  • 1
    Sorry, shouldnt used aliases. `ea` means `ErrorAction` and 0 is the enum value for SilentlyContinue - so I set the ErrorAction for this line to SilentlyContinue (which prevents the script to stop if an error occurred). `-ev` stands for `ErrorVariable`. I basically define that if an error occurres, write it to the `$timeout` variable. – Martin Brandl Jul 30 '18 at 11:00
  • Shouldn't timeouted in the Wait-Process call be $timouted? – Alek Davis Mar 06 '20 at 19:43
  • 2
    @AlekDavis No, you omit the `$` sign there. – Martin Brandl Mar 10 '20 at 06:25
  • Oh, I see. The value holds the name of the variable, not the actual variable. Thanks. – Alek Davis Mar 12 '20 at 18:07