Wait for input, then timeout to default

This topic contains 2 replies, has 3 voices, and was last updated by  Matt Bloomfield 2 years ago.

  • Author
    Posts
  • #32673

    John Muirhead
    Participant

    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.

  • #32681

    Don Jones
    Keymaster

    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.

  • #32685

    Matt Bloomfield
    Participant

    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
    

You must be logged in to reply to this topic.