30

How do I catch and handle Ctrl+C in a PowerShell script? I understand that I can do this from a cmdlet in v2 by including an override for the Powershell.Stop() method, but I can't find an analog for use in scripts.

I'm currently performing cleanup via an end block, but I need to perform additional work when the script is canceled (as opposed to run to completion).

JasonMArcher
  • 12,386
  • 20
  • 54
  • 51
Justin R.
  • 21,845
  • 21
  • 102
  • 147
  • Possible duplicate of [Is there a way to catch ctrl-c and ask the user to confirm?](https://stackoverflow.com/questions/10733718/is-there-a-way-to-catch-ctrl-c-and-ask-the-user-to-confirm) – jpaugh Aug 15 '19 at 19:31

3 Answers3

63

The documentation for try-catch-finally says:

A Finally block runs even if you use CTRL+C to stop the script. A Finally block also runs if an Exit keyword stops the script from within a Catch block.

See the following example. Run it and cancel it by pressing ctrl-c.

try
{
    while($true)
    {
        "Working.."
        Start-Sleep -Seconds 1
    }
}
finally
{
    write-host "Ended work."
}
zett42
  • 14,113
  • 3
  • 17
  • 55
staale.skaland
  • 991
  • 1
  • 7
  • 15
  • The is true, but Finally will run not only because Exit was called, but also if the Try block succeeds. As I indicated in my question, I need to perform additional work when the script is canceled (as opposed to run to completion). – Justin R. Apr 04 '13 at 00:18
  • 8
    @fatcat111 use a Boolean flag. For example, set `$didcomplete = $true` at the end of your `try` and check it with `if ($didcomplete) { Write-Host "Ended work." }` inside the `finally` – Jacob Krall Mar 15 '14 at 18:48
  • 2
    Unfortunately, the finally block is not executed if the PowerShell console window is closed. – AndreasHassing Dec 29 '17 at 10:11
  • The finally block is also called when stopping a remote PSSession invoke-command or Job! – Brain2000 Dec 20 '18 at 18:14
11

You could use the method described on here on PoshCode

Summary:

Set

[console]::TreatControlCAsInput = $true

then poll for user input using

if($Host.UI.RawUI.KeyAvailable -and (3 -eq  
    [int]$Host.UI.RawUI.ReadKey("AllowCtrlC,IncludeKeyUp,NoEcho").Character))
staale.skaland
  • 991
  • 1
  • 7
  • 15
FkYkko
  • 931
  • 1
  • 11
  • 17
2

There is also a Stopping property on $PSCmdlet that can be used for this.

  • `Stopping` is `false` even when stopping per [PowerShell/PowerShell#6322](https://github.com/PowerShell/PowerShell/issues/6322). – alx9r Mar 06 '18 at 17:46