Nilzor
Nilzor

Reputation: 18603

How can I interrupt an executable invoked inside a script without interrupting the script itself?

Let's say you have the following script saved in a file outermost.ps1:

powershell.exe -Command "while ( 1 -eq 1 ) {} "
echo "Done"

When running outermost.ps1 you can only abort this by pressing Ctrl+C, and no output will be written to console. How can I modify it so that the outermost script continues and executes echo "Done" when Ctrl+C is pressed?

This is a simplified version of a real-life scenario where the inner script is actually an executable which only is stoppable by pressing Ctrl+C.

Edit: The script could also be:

everlooping.exe
echo "Done"

but I wanted to provide an example everyone could copy-paste into an editor if they wanted to "try at home".

Upvotes: 2

Views: 293

Answers (2)

Nilzor
Nilzor

Reputation: 18603

The simplest solution to this is:

    Start-Process -Wait "powershell.exe" -ArgumentList "while ( 1 -eq 1 ) {}"
    echo "Done"

This will spawn a second window unlinke ansgar-wiechers solution, but solves my problem with the least amount of code.

Thanks to Jaqueline Vanek for the tip

Upvotes: 0

Ansgar Wiechers
Ansgar Wiechers

Reputation: 200573

Start your infinite command/statement as a job, make your PowerShell script process Ctrl+C as regular input (see here), and stop the job when that input is received:

[Console]::TreatControlCAsInput = $true

$job = Start-Job -ScriptBlock {
  powershell.exe -Command "while ( 1 -eq 1 ) {} "
}

while ($true) {
  if ([Console]::KeyAvailable) {
    $key = [Console]::ReadKey($true)
    if (($key.Modifiers -band [ConsoleModifiers]::Control) -and $key.Key -eq 'c') {
      $job.StopJob()
      break
    }
  }
  Start-Sleep -Milliseconds 100
}

Receive-Job -Id $job.Id
Remove-Job -Id $job.Id

echo "Done"

If you need to retrieve output from the job while it's running, you can do so like this in an else branch to the outer if statement:

if ($job.HasMoreData) { Receive-Job -Id $job.Id }

Upvotes: 4

Related Questions