2

Catching Ctrl+C in Powershell (console) can be done in two methods posted here:
First:

[console]::TreatControlCAsInput = $true
while ($true)
{
    write-host "Processing..."
    if ([console]::KeyAvailable)
    {
        $key = [system.console]::readkey($true)
        if (($key.modifiers -band [consolemodifiers]"control") -and ($key.key -eq "C"))
        {
            Add-Type -AssemblyName System.Windows.Forms
            if ([System.Windows.Forms.MessageBox]::Show("Are you sure you want to exit?", "Exit Script?", [System.Windows.Forms.MessageBoxButtons]::YesNo) -eq "Yes")
            {
                "Terminating..."
                break
            }
        }
    }
}

Second:

while ($true)
{
    Write-Host "Do this, do that..."

    if ($Host.UI.RawUI.KeyAvailable -and (3 -eq [int]$Host.UI.RawUI.ReadKey("AllowCtrlC,IncludeKeyUp,NoEcho").Character))
    {
            Write-Host "You pressed CTRL-C. Do you want to continue doing this and that?" 
            $key = $Host.UI.RawUI.ReadKey("NoEcho, IncludeKeyDown")
            if ($key.Character -eq "N") { break; }
    }
}

But PowerShell_ISE is not considered as a console. It is considered as a GUI as Microsoft stated here:

Windows PowerShell Integrated Scripting Environment (ISE) is a graphical host application

When running one of the above function on PowerShell_ISE, an error pops up:

enter image description here

Capturing any keys other than Ctrl+C on GUI, such as PowerShell_ISE, is possible with this function (credit to Matt McNabb):

function Test-KeyPress
{
    <#
    .SYNOPSIS
    Checks to see if a key or keys are currently pressed.

    .DESCRIPTION
    Checks to see if a key or keys are currently pressed. If all specified keys are pressed then will return true, but if 
    any of the specified keys are not pressed, false will be returned.

    .PARAMETER Keys
    Specifies the key(s) to check for. These must be of type "System.Windows.Forms.Keys"

    .EXAMPLE
    Test-KeyPress -Keys ControlKey

    Check to see if the Ctrl key is pressed

    .EXAMPLE
    Test-KeyPress -Keys ControlKey,Shift

    Test if Ctrl and Shift are pressed simultaneously (a chord)

    .LINK
    Uses the Windows API method GetAsyncKeyState to test for keypresses
    http://www.pinvoke.net/default.aspx/user32.GetAsyncKeyState

    The above method accepts values of type "system.windows.forms.keys"
    https://msdn.microsoft.com/en-us/library/system.windows.forms.keys(v=vs.110).aspx

    .LINK
    http://powershell.com/cs/blogs/tips/archive/2015/12/08/detecting-key-presses-across-applications.aspx

    .INPUTS
    System.Windows.Forms.Keys

    .OUTPUTS
    System.Boolean
    #>

    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true)]
        [ValidateNotNullOrEmpty()]
        [System.Windows.Forms.Keys[]]
        $Keys
    )

    # use the User32 API to define a keypress datatype
    $Signature = @'
    [DllImport("user32.dll", CharSet=CharSet.Auto, ExactSpelling=true)] 
    public static extern short GetAsyncKeyState(int virtualKeyCode); 
'@
    $API = Add-Type -MemberDefinition $Signature -Name 'Keypress' -Namespace Keytest -PassThru

    # test if each key in the collection is pressed
    $Result = foreach ($Key in $Keys)
    {
        [bool]($API::GetAsyncKeyState($Key) -eq -32767)
    }

    # if all are pressed, return true, if any are not pressed, return false
        $Result -notcontains $false
}

While($true){
    if(Test-KeyPress -Keys ([System.Windows.Forms.Keys]::ControlKey),([System.Windows.Forms.Keys]::Z)){
            break
    }
}

It worked well with Ctrl+Z but with Ctrl+C it doesn't because Ctrl+C cancel the session before it capture it.

Any idea how to capture Ctrl+C on PowerShell_ISE ?

E235
  • 11,560
  • 24
  • 91
  • 141
  • 1
    Missing ) bracket in your 'If (test-Keypress' statement – Vincent K Nov 22 '17 at 16:18
  • @VincentK re-edited, thanks. – E235 Nov 22 '17 at 16:20
  • Just one more reason to not use the ISE for testing code... – EBGreen Nov 22 '17 at 16:32
  • What problem are you solving? – Bill_Stewart Nov 22 '17 at 17:07
  • @Bill_Stewart I have script with threads. If you press `Ctrl+C` it won't kill all the threads, just the main thread. I want that when the user will press `Ctrl+C` it will kill all the threads and then exist the program. I wanted that it will work also in PowerShell_ISE in case he will run it there. The workaround is just to tell him to use different key stroke like `Ctrl+Z` but I wanted to avoid it. – E235 Nov 22 '17 at 17:15

0 Answers0