Pausing a Windows PowerShell Script to Receive Keyboard Input


 

Summary: Pausing execution of a Windows PowerShell script to receive keyboard input can be as simple as using the Read-Host cmdlet. But other methods are available.

 

Hey, Scripting Guy! QuestionHey, Scripting Guy! I would like to pause a Windows PowerShell script and wait for user input. When the user types a particular key on the keyboard, I would like the script to continue. I found an old Hey, Scripting Guy! post called How Can I Pause a Script and Then Resume It When a User Presses a Key on the Keyboard? but it is written for VBScript. I do not think I want to attempt using stdin from a Windows PowerShell script. I also found an article called Can I Pause and Resume Scripts with Windows PowerShell? that was written for the 2009 Summer Scripting Games, but that does not work with user input. Is the absence of a solution indicative that I cannot accomplish this using Windows PowerShell?

-- TC

 

Hey, Scripting Guy! AnswerHello TC,

Microsoft Scripting Guy Ed Wilson here. I was up late last night talking to the System Administrators Guild of Australia (SAGE-AU) at their conference in Tasmania. It was fun, but I would rather have been there in person. Tasmania is one of the places I have not had the chance to visit. I fell in love with Tasmanian strawberries when I was in Sydney because they are super sweet, but recently they have started growing strawberries that are in the shape of a heart. Those would make a wonderful present for my significant other.

Anyway, TC, sometimes things are so simple that they do not receive much publicity. One such example is pausing a script to wait for user input.

PauseScriptReadName.ps1

$a = read-host "what is your name?"
"hello $a"

When the PauseScriptReadName.ps1 script runs in the Windows PowerShell ISE, a pop-up window appears, as shown in the following image.

There is, of course, one teeny tiny problem with the script as written. It will pause forever and ever, until the user enters data, or until the computer either restarts or shuts down. This behavior could have adverse consequences to say the least.

TC, a completely different approach is seen in the pauseTimer.ps1 script shown here:

pauseTimer.ps1

#Requires -version 2.0
Param($timer = 10)
Function Test-IsIseHost
{
<#
.Synopsis
Determines if you are running in the Windows PowerShell ISE
.Description
This function determines if you are running in the Windows Powershell
ISE by querying the $ExecutionContext automatic variable.
.Example
Test-IsIseHost
Prints out True if running inside the ISE, False if run in console
.Example
if(Test-IsIseHost) { "Using the ISE" }
Prints out Using the ISE when run inside the ISE, otherwise nothing
.Inputs
None
.Outputs
[Boolean]
.Notes
Name: Test-IsIseHost
Book: Windows PowerShell Best Practices, Microsoft Press, 2009
Author: Ed Wilson
Version: 1.0
Date: 4/5/2009
.Link
about_Automatic_variables
Http://www.ScriptingGuys.Com
#>
$ExecutionContext.Host.name -match "ISE Host$"
} #end Test-IsIseHost
function Select-Destination($strIN)
{ 
Clear-Host
switch($strIN.character)
{
"l"
{ "$($strIN.Character): local selected" ; exit }
"r"
{ "$($strIN.Character): Remote selected" ; exit }
DEFAULT { "$($strIN.Character) is not valid. CountDown Resuming ..." ; break}
}
} #end function Select-Destination
# *** Entry point to script ***
If(Test-IsIseHost) {"This script does not run in ISE" ; exit}
"Select machine:"
" l <ocal> r <emote> "
$i = 1
Do
{
Write-host -ForeGroundColor green -noNewLine "Script will time out in $($timer-$i) seconds"
$pos = $host.UI.RawUI.get_cursorPosition()
# $pos.set_x(0) # This was 1.0 syntax
$pos.X = 0 # this is 2.0 syntax
$host.UI.RawUI.set_cursorPosition($Pos)
if($host.UI.RawUI.KeyAvailable) 
{ 
Select-Destination($host.ui.rawui.readkey()) 
}
start-Sleep -Seconds 1
if( [math]::log10($timer-$i) -eq [math]::truncate([math]::log10($timer-$i)) )
{ Clear-Host }
$i++
}While ($i -le $timer) ; Clear-Host ; "Script timed out after $timer seconds" ; exit

Keep in mind that the pauseTimer.ps1 script does not run in the Windows PowerShell ISE. As a result, the Test-IsIseHost function is used. If the ISE host is found, the script will exit after displaying a message that the script does not run in the ISE host. The Test-IsIseHost function is shown here:

Function Test-IsIseHost
{
<#
.Synopsis
Determines if you are running in the Windows PowerShell ISE
.Description
This function determines if you are running in the Windows Powershell
ISE by querying the $ExecutionContext automatic variable.
.Example
Test-IsIseHost
Prints out True if running inside the ISE, False if run in console
.Example
if(Test-IsIseHost) { "Using the ISE" }
Prints out Using the ISE when run inside the ISE, otherwise nothing
.Inputs
None
.Outputs
[Boolean]
.Notes
Name: Test-IsIseHost
Book: Windows PowerShell Best Practices, Microsoft Press, 2009
Author: Ed Wilson
Version: 1.0
Date: 4/5/2009
.Link
about_Automatic_variables
Http://www.ScriptingGuys.Com
#>
$ExecutionContext.Host.name

Comments (4)

  1. jrv says:

    PS > sleep 1

    PS > sleep 2

    PS > sleep 3

    PS >sleep ($perchance_to_dream=10);'Aye! – there's the rub!'

    Aye! – there's the rub!

  2. jrv says:

    The post is spot -on.  It is just showing us how to timeout a read.

    Here is a trivial demo of the same thing:

    How to timeout a keystroke….

    Just probe for the key

    $i=0

    While(-not $host.UI.RawUI.KeyAvailable){

        $i++

        write-host $i

        sleep 2

    }

    $host.UI.RawUI.ReadKey()

  3. SteveTN says:

    Part 2

    # Put the cursor back to the spot it was on the screen prior to calling the progress bar.

    $host.UI.RawUI.set_cursorPosition($posEnd)

    if ($inputCheck -and $inputCheck.ReturnCode -eq 0) {

       # Here I can handle what I want to do with one of the 2 choices.

       "Choice: $($inputCheck.Choice)"

    } else {

       "Script timed out after $timer seconds"

    }

    exit

  4. SteveTN says:

    My part 1 of my code never shows up in the comments. I previously wrote:

    "I realize this is an old post, but I thought I would comment since this helped in something I was doing. I wanted a prompt to ask the user if they wanted to continue or not, but also wanted the choice to timeout.  Since I wanted a timeout, that eliminated using $host.ui.PromptForChoice. I also didn't want to fall back and use the dos choice command.  I wanted a pure PowerShell solution.  I ended up modifying your pauseTimer.ps1 script to use the  Write-progress cmdlet to give a slicker solution to the problem.   I'm posting my modified code on the off chance someone else would like to incorporate this solution into their script."

Skip to main content