Wait for input, then timeout to default

All,

Am a veritable PowerShell noob, so please bear with me if this question it foolish and/or obvious. Ok, disclaimer taken care of. Here goes:

Designing a script that waits for user input selections. Something to the effect of this below:

Do { Write-Host "Selection (A-C)?: " -NoNewLine

$Answer = Read-Host
}
Until(“A”,“B”,“C” -ccontains $Answer.ToUpper())

Works great. However, what I’d really like to do is enforce a default (say force option “A”) and exit the loop if 90 seconds (for example) have passed without input.

Possible? Again, relatively new to PS, so it’s not obvious to me.

Thanks.

PowerShell’s Read-Host can’t do what you’e asking, no. Broadly speaking, this isn’t what PowerShell’s main use case is. It isn’t strictly intended to be an event-based user interface responder, and its ability to present user interface - without getting into WinForms or something complex - is fairly primitive. It’s mean to be run as directives, meaning you tell it what to do by running commands, not by displaying menus. I’m not saying you absolutely cannot do what you’re asking - just that it’s going to be a lot more complex than you may realize, so you need to decide if it’s worth a lot of extra coding, much of which will essentially be .NET coding.

This was much harder to do than I expected. I read several examples online where people have tried to achieve similar results. Using some of them as inspiration, I have come up with the following which pretty much achieves the objective.

The loop runs until a key is pressed or until the timeout period is reached. If a key is pressed, the key is read and assigned to $response. If no key has been pressed, then $response is assigned a default value. I have just written out $response but it could be passed to a Switch construct to implement menu functionality.

Note: this won’t work in the ISE, only in the PowerShell console.

function Read-KeyOrTimeout {

    Param(
           [int]$seconds = 5,
        [string]$prompt = 'Hit a key',
        [string]$default = 'A'
    )

    $startTime = Get-Date
    $timeOut = New-TimeSpan -Seconds $seconds

    Write-Host $prompt

    while (-not $host.ui.RawUI.KeyAvailable) {

        $currentTime = Get-Date

        if ($currentTime -gt $startTime + $timeOut) {

            Break
    
        }
    
    }

    if ($host.ui.RawUI.KeyAvailable) {

        [string]$response = ($host.ui.RawUI.ReadKey("IncludeKeyDown,NoEcho")).character

    }

    else {
    
        $response = $default

    }

    Write-Output "You typed $($response.toUpper())"

}

Read-KeyOrTimeOut