Home > OS >  PowerShell timing loop doesn't complete, hangs at random spot
PowerShell timing loop doesn't complete, hangs at random spot

Time:09-22

I've created a very simple function in a powershell module which should capture a keystroke if a key is pressed within a short time window.

function get-mycommand{
    $count=0
    $sleepTimer=2 #in milliseconds
    while ($count -le 100)
    {
        if($host.UI.RawUI.KeyAvailable) {
            $key = $host.UI.RawUI.ReadKey('NoEcho, IncludeKeyDown')
            return $key.character
        } else {
            $count  
            Write-Host $count
            Start-Sleep -m $sleepTimer
        }
    }
    return "fail"
}

function test-get-command{
    $myvalue = get-mycommand
    Write-Host  'return ' $myvalue
}

This works fine so long as I press a key quickly. If I don't press a key then it will count up to some random number, usually less than 20, and then stop updating. It won't do anything until I press a key and it never times out. When I do press a key, even after several minutes it will return with the character. I never see the 'fail' message at all.

Using a longer timer interval doesn't change anything.I've tried a sleeptimer of 2, 20 & 200. They all behave the same.

CodePudding user response:

Unfortunately, $host.UI.RawUI.KeyAvailable can have false positives in Windows PowerShell as well as in PowerShell (Core) up to at least v7.2.0-preview.9 (current as of this writing).

  • On Windows, it seemingly thinks a key is available even when there isn't, so that $key = $host.UI.RawUI.ReadKey('NoEcho, IncludeKeyDown') is executed, which indefinitely waits for an actual keypress.

    • In a regular console window this seems to happen after a few iterations at the latest.
    • In Windows Terminal, it seems to happen consistently on the first iteration, so that your function produces no output at all.
  • GitHub issue #959 seems relevant, although it relates to the PSReadLine module.

    • While unloading the module (Remove-Module PSReadLine) - which you wouldn't want to do in a interactive session - does fix the problem in regular console windows, it doesn't help in Windows Terminal.

Workaround:

Replace $host.UI.RawUI.KeyAvailable with [Console]::KeyAvailable

Note that this limits use to consoles (terminals), but your original code wouldn't work in the obsolescent ISE anyway, because $host.UI.RawUI.KeyAvailable there seemingly never reports a pending keypress.

  • Related