powershell 等待用户输入超时

2exbekwf  于 2023-02-23  发布在  Shell
关注(0)|答案(9)|浏览(255)

我已经搜索过了,但很明显我的google foo很弱。我需要的是一种方法,在控制台提示用户输入,并在一段时间后让请求超时,如果没有输入进来,则继续执行脚本。据我所知,Read-Host不提供此功能。$host.UI.PromptForChoice()和$host.UI.RawUI.ReadKey()也不提供此功能。提前感谢您的任何提示。
编辑:非常感谢Lars Truijens找到了答案。我已经把他指出的代码封装到了一个函数中。注意,我实现它的方式意味着在用户点击一个键和脚本继续执行之间可能会有长达一秒的延迟。

function Pause-Host
{
    param(
            $Delay = 1
         )
    $counter = 0;
    While(!$host.UI.RawUI.KeyAvailable -and ($counter++ -lt $Delay))
    {
        [Threading.Thread]::Sleep(1000)
    }
}
jhdbpxl9

jhdbpxl91#

找到一些内容here

$counter = 0
while(!$Host.UI.RawUI.KeyAvailable -and ($counter++ -lt 600))
{
      [Threading.Thread]::Sleep( 1000 )
}
ntjbwcob

ntjbwcob2#

这是相当古老的现在,但我如何解决它基于相同的KeyAvailable方法是在这里:
https://gist.github.com/nathanchere/704920a4a43f06f4f0d2
它等待x秒,在最长等待时间内每隔一秒显示一个.,如果按下某个键,它返回$true,否则返回$false

Function TimedPrompt($prompt,$secondsToWait){   
    Write-Host -NoNewline $prompt
    $secondsCounter = 0
    $subCounter = 0
    While ( (!$host.ui.rawui.KeyAvailable) -and ($count -lt $secondsToWait) ){
        start-sleep -m 10
        $subCounter = $subCounter + 10
        if($subCounter -eq 1000)
        {
            $secondsCounter++
            $subCounter = 0
            Write-Host -NoNewline "."
        }       
        If ($secondsCounter -eq $secondsToWait) { 
            Write-Host "`r`n"
            return $false;
        }
    }
    Write-Host "`r`n"
    return $true;
}

并用途:

$val = TimedPrompt "Press key to cancel restore; will begin in 3 seconds" 3
Write-Host $val
yptwkmov

yptwkmov3#

对于正在寻找一种现代解决方案的人,如果该解决方案具有在按下预定义键时退出PowerShell脚本的附加约束,则以下解决方案可能会对您有所帮助:

Write-Host ("PowerShell Script to run a loop and exit on pressing 'q'!")
$count=0
$sleepTimer=500 #in milliseconds
$QuitKey=81 #Character code for 'q' key.
while($count -le 100)
{
    if($host.UI.RawUI.KeyAvailable) {
        $key = $host.ui.RawUI.ReadKey("NoEcho,IncludeKeyUp")
        if($key.VirtualKeyCode -eq $QuitKey) {
            #For Key Combination: eg., press 'LeftCtrl + q' to quit.
            #Use condition: (($key.VirtualKeyCode -eq $Qkey) -and ($key.ControlKeyState -match "LeftCtrlPressed"))
            Write-Host -ForegroundColor Yellow ("'q' is pressed! Stopping the script now.")
            break
        }
    }
    #Do your operations
    $count++
    Write-Host ("Count Incremented to - {0}" -f $count)
    Write-Host ("Press 'q' to stop the script!")
    Start-Sleep -m $sleepTimer
}
Write-Host -ForegroundColor Green ("The script has stopped.")

脚本输出示例:

有关处理更多组合的关键状态,请参阅Microsoft document
学分:Technet Link

but5z9lq

but5z9lq4#

下面是一个击键实用程序函数,它接受:

  • 验证字符集(作为1字符正则表达式)。
  • 可选消息
  • 可选超时(秒)

只有匹配的击键才会反映到屏幕上。
用法:

$key = GetKeyPress '[ynq]' "Run step X ([y]/n/q)?" 5

if ($key -eq $null)
{
    Write-Host "No key was pressed.";
}
else
{
    Write-Host "The key was '$($key)'."
}

实施:

Function GetKeyPress([string]$regexPattern='[ynq]', [string]$message=$null, [int]$timeOutSeconds=0)
{
    $key = $null

    $Host.UI.RawUI.FlushInputBuffer() 

    if (![string]::IsNullOrEmpty($message))
    {
        Write-Host -NoNewLine $message
    }

    $counter = $timeOutSeconds * 1000 / 250
    while($key -eq $null -and ($timeOutSeconds -eq 0 -or $counter-- -gt 0))
    {
        if (($timeOutSeconds -eq 0) -or $Host.UI.RawUI.KeyAvailable)
        {                       
            $key_ = $host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown,IncludeKeyUp")
            if ($key_.KeyDown -and $key_.Character -match $regexPattern)
            {
                $key = $key_                    
            }
        }
        else
        {
            Start-Sleep -m 250  # Milliseconds
        }
    }                       

    if (-not ($key -eq $null))
    {
        Write-Host -NoNewLine "$($key.Character)" 
    }

    if (![string]::IsNullOrEmpty($message))
    {
        Write-Host "" # newline
    }       

    return $(if ($key -eq $null) {$null} else {$key.Character})
}
dy2hfwbg

dy2hfwbg5#

timeout.exe 5

仍然从powershell工作。等待5秒钟或直到按键。
或许不雅。但很容易。
但是,
在Powershell_ISE中,它会弹出一个新的命令提示符窗口,并立即返回,所以它不会等待(在Powershell控制台中,它使用该控制台并等待).您可以让它在ISE中等待,但需要多做一些工作(仍然会弹出自己的窗口):

if ($psISE) {
    start -Wait timeout.exe 5
} else {
    timeout.exe 5
}
lrl1mhuk

lrl1mhuk6#

另一种选择:您可以使用choice shell命令,该命令随Windows 2000以后的每个Windows版本提供

Choice /C yn /D n /t 5 /m "Are you sure? You have 5 seconds to decide"
if ($LASTEXITCODE -eq "1") # 1 for "yes" 2 for "no"
{
    # do stuff
}
else
{
    # don't do stuff
}

堆栈溢出语法高亮显示不适用于powershell,#在这里表示"注解"

gcuhipw9

gcuhipw97#

function ReadKeyWithDefault($prompt, $defaultKey, [int]$timeoutInSecond = 5 ) {
    $counter =  $timeoutInSecond * 10
    do{
        $remainingSeconds = [math]::floor($counter / 10)
        Write-Host "`r$prompt (default  $defaultKey  in $remainingSeconds seconds): " -NoNewline
        if($Host.UI.RawUI.KeyAvailable){
            $key = $host.UI.RawUI.ReadKey("IncludeKeyUp")
            Write-Host 
            return $key
        }
        Start-Sleep -Milliseconds 100
    }while($counter-- -gt 0)

    Write-Host $defaultKey
    return $defaultKey
}

$readKey = ReadKeyWithDefault "If error auto exit( y/n )" 'y' 5
ff29svar

ff29svar8#

为了在脚本退出之前选择性地暂停脚本(对于运行headless脚本和在错误输出时暂停非常有用),我在nathanchere's answer后面追加了:

if ([Console]::KeyAvailable) { $pressedKey = [Console]::ReadKey($true); read-host; break; }
  elseif ($secondsCounter -gt $secondsToWait) { 
      Write-Host "`r`n"
      return $false;
  }
lokaqttq

lokaqttq9#

$Host.UI.RawUI.KeyAvailable似乎有缺陷,所以我使用[Console]::KeyAvailable时运气更好:

function keypress_wait {
    param (
        [int]$seconds = 10
    )
    $loops = $seconds*10
    Write-Host "Press any key within $seconds seconds to continue"
    for ($i = 0; $i -le $loops; $i++){
        if ([Console]::KeyAvailable) { break; }
        Start-Sleep -Milliseconds 100
    }
if ([Console]::KeyAvailable) { return [Console]::ReadKey($true); }
else { return $null ;}
}

相关问题