GetAsyncKeyState or KeyAvailable in PsRemote session

This topic contains 1 reply, has 2 voices, and was last updated by Profile photo of Don Jones Don Jones 1 week ago.

  • Author
    Posts
  • #61659
    Profile photo of Ili Metuki
    Ili Metuki
    Participant

    Hi

    I wrote a function that check if you are pressing or pressed Ctrl-Q from the last time the function run and if so exit the script

    This is useful for example if you have a long loop and you want to have the option to stop it by pressing a key but unlike Ctrl-C do it in a controlled position at the end of the loop

    So you can click Ctrl-Q, the loop will continue as normal until the end of the current loop and then stop

    I used the [console]/$Host methods KeyAvailable and ReadKey() and it's working grate but not in Powershell ISE
    so I fund a workaround for ISE by using GetAsyncKeyState() instead in it

    But the problem now is that if I Enter-PSSession this two solutions not working in there, GetAsyncKeyState() always return 0 and ReadKey return "Cannot see if a key has been pressed when either application does not have a console or when console input has been redirected from a file. Try Console.In.Peek."

    function Stop-IfKey
    {
        
        [CmdletBinding()]
        param
        (
            [Parameter(Mandatory=$false, Position=0)]
            [Switch]
            $InitializeIse
        )
        if ($InitializeIse)
        {
            if (!('Win32Functions.Win32GetAsyncKeyState' -as [type]))
            {
                $Signature = '[DllImport("user32.dll")]public static extern short GetAsyncKeyState(int vKey);'
                Add-Type -MemberDefinition $Signature -Name 'Win32GetAsyncKeyState' -Namespace Win32Functions
                Add-Type -AssemblyName System.Windows.Forms
            }
            $null = [Win32Functions.Win32GetAsyncKeyState]::GetAsyncKeyState([Windows.Forms.Keys]::LControlKey)
            $null = [Win32Functions.Win32GetAsyncKeyState]::GetAsyncKeyState([Windows.Forms.Keys]::RControlKey)
            $null = [Win32Functions.Win32GetAsyncKeyState]::GetAsyncKeyState([Windows.Forms.Keys]::Q)
            Return
        }
        
        $QuittingMassage = 'Quitting, user pressed control Q...'
        if ($Host.Name -notin 'Windows PowerShell ISE Host')
        {
            #[console]::TreatControlCAsInput = $true # For Ctrl-C
            if ([console]::KeyAvailable) # Or ($Host.UI.RawUI.KeyAvailable)
            {
                $key = [console]::readkey($true) # Or $key = $Host.UI.RawUI.ReadKey()
                if (($key.modifiers -band 'control') -and ($key.key -eq 'Q'))
                {
                    #Write-Warning -Message $QuittingMassage
                    #Exit
                    throw $QuittingMassage
                }
            }
        }
        else
        {
            if (([Win32Functions.Win32GetAsyncKeyState]::GetAsyncKeyState([Windows.Forms.Keys]::LControlKey) -or [Win32Functions.Win32GetAsyncKeyState]::GetAsyncKeyState([Windows.Forms.Keys]::RControlKey)) -and [Win32Functions.Win32GetAsyncKeyState]::GetAsyncKeyState([Windows.Forms.Keys]::Q))
            {
                #Write-Warning -Message $QuittingMassage
                #Exit
                throw $QuittingMassage
            }
        }
    }
    Stop-IfKey -InitializeIse
    
    $collection = @(1..5)
    foreach ($item in $collection)
    {
        'Loop {0}' -f $item
        Start-Sleep -Seconds 5 # Do stuff
        Stop-IfKey
    }
    'End'
  • #61954
    Profile photo of Don Jones
    Don Jones
    Keymaster

    You're not going to be able to duplicate this. PSSessions aren't like a Telnet or SSH session; you're still typing in your local console until you hit Enter, at which point the remote process runs. There's no "console connection" per se.

You must be logged in to reply to this topic.