Я искал, но, видимо, мой google foo слабый. Что мне нужно, так это способ запросить ввод данных пользователем в консоли и тайм-аут запроса по истечении определенного периода времени и продолжить выполнение сценария, если ввод не поступает. Насколько я могу судить, Read-Host не предоставляет этого функциональность. Ни $ host.UI.PromptForChoice (), ни $ host.UI.RawUI.ReadKey () тоже. Заранее благодарим за любые указатели.
Обновлено: Большое спасибо Ларсу Труидженсу за то, что он нашел ответ. Я взял код, который он указал, и инкапсулировал его в функцию. Обратите внимание, что способ, которым я это реализовал, означает, что между тем, когда пользователь нажимает клавишу, и продолжением выполнения скрипта может быть задержка до одной секунды.
function Pause-Host
{
param(
$Delay = 1
)
$counter = 0;
While(!$host.UI.RawUI.KeyAvailable -and ($counter++ -lt $Delay))
{
[Threading.Thread]::Sleep(1000)
}
}





Нашел кое-что здесь:
$counter = 0
while(!$Host.UI.RawUI.KeyAvailable -and ($counter++ -lt 600))
{
[Threading.Thread]::Sleep( 1000 )
}
В PowerShell 2 также есть командлет Start-Sleep.
Сейчас он довольно старый, но вот как я решил его на основе того же метода 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
Проблема с вышесказанным заключается в том, что любое нажатие клавиши не «проглатывается». Чтобы проглотить его, вы можете положить перед окончательным возвратом следующее: $host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
Небольшой совет, вам нужна только 1 переменная таймера внутри функции, вы можете обновить экран (хост записи), используя уравнение модуля. По сути, сохраните и переименуйте subCounter (в elapsedTime или что-то в этом роде), а затем вместо «if ($ subCounter -eq 1000)» вы можете сделать «if ($ elapsedTime% 1000 -eq 0)» И во втором, если бы у вас было умножить secondsToWait на 1000 (поскольку вы измеряете в мс) или просто измените проход в мс вместо секунд.
Если я использую $val = TimedPrompt "Press key to cancel restore; will begin in 3 seconds" 3 Write-Host $val более одного раза в скрипте, он не будет ждать второй раз.
Для людей, которые ищут современное решение с дополнительным ограничением для выхода из сценария 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 по состояниям клавиш для обработки дополнительных комбинаций.
Кредиты: Technet Link
Вот служебная функция нажатия клавиш, которая принимает:
На экране отображаются только совпадающие нажатия клавиш.
Использование:
$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})
}
Exception calling "FlushInputBuffer" with "0" argument(s): "The method or operation is not implemented." PSVersion = 5.1.17763.771
Ах, исключение случается только в PowerShell ISE. В прямом окне PS нормально. Похоже, необработанный пользовательский интерфейс вообще нельзя проверить в ISE, так что будьте осторожны.
Большое Вам спасибо. Я склоняюсь перед твоим могущественным гугл-фу.