简体   繁体   中英

How to configure a timeout for Read-Host in PowerShell

Like I said, this code works in PowerShell version 2, but not in PowerShell version 5.

function wait
      {
       $compte = 0
        Write-Host  "To continue installation and ignore configuration warnings      type [y], type any key to abort"
          While(-not $Host.UI.RawUI.KeyAvailable -and ($compte -le 20))
         {
          $compte++
          Start-Sleep -s 1
          }
           if ($compte -ge 20)
           {
        Write-Host "Installation aborted..."
           break
           }
        else
            {
        $key = $host.ui.rawui.readkey("NoEcho,IncludeKeyup")
            }
         if ($key.character -eq "y")
            {Write-Host "Ignoring configuration warnings..."}
         else 
            {Write-Host "Installation aborted..." 
            }}

The official documentation or Read-Host -? will tell that it's not possible to use Read-Host in that manner. There is no possible parameter to tell it to run with some kind of timeout.

But there are various other questions detailing how to do this in PowerShell (usually utilizing C#).

The idea seems to be to check whenever the user pressed a key using $Host.UI.RawUI.KeyAvailable and check that for the duration of your timeout.

A simple working example could be the following:

$secondsRunning = 0;
Write-Output "Press any key to abort the following wait time."
while( (-not $Host.UI.RawUI.KeyAvailable) -and ($secondsRunning -lt 5) ){
    Write-Host ("Waiting for: " + (5-$secondsRunning))
    Start-Sleep -Seconds 1
    $secondsRunning++
}

You could use $host.UI.RawUI.ReadKey to get the key that was pressed. This solution probably would not be acceptable if you need more complex input than a simple button press. See also:

Seth, thank you for your solution. I expanded on the example you provided and wanted to give that back to the community.

The use case is a bit different here - I have a loop checking if an array of VMs can be migrated and if there are any failures to that check the operator can either remediate those until the checks clear or they can opt to "GO" and have those failing VMs excluded from the operation. If something other than GO is typed state remains within the loop.

One downside to this is if the operator inadvertently presses a key the script will be blocked by Read-Host and may not be immediately noticed. If that's a problem for anyone I'm sure they can hack around that;-)

Write-Host "Verifying all VMs have RelocateVM_Task enabled..."
Do {
    $vms_pivoting = $ph_vms | Where-Object{'RelocateVM_Task' -in $_.ExtensionData.DisabledMethod}
    if ($vms_pivoting){
        Write-Host -ForegroundColor:Red ("Some VMs in phase have method RelocateVM_Task disabled.")
        $vms_pivoting | Select-Object Name, PowerState | Format-Table -AutoSize
        Write-Host -ForegroundColor:Yellow "Waiting until this is resolved -or- type GO to continue without these VMs:" -NoNewline
        $secs = 0
        While ((-not $Host.UI.RawUI.KeyAvailable) -and ($secs -lt 15)){
            Start-Sleep -Seconds 1
            $secs++
        }
        if ($Host.UI.RawUI.KeyAvailable){
            $input = Read-Host
            Write-Host ""
            if ($input -eq 'GO'){ 
                Write-Host -ForegroundColor:Yellow "NOTICE: User prompted to continue migration without the blocked VM(s)"
                Write-Host -ForegroundColor:Yellow "Removing the following VMs from the migration list"
                $ph_vms = $ph_vms | ?{$_ -notin $vms_pivoting} | Sort-Object -Property Name
            }
        }
    } else {
        Write-Host -ForegroundColor:Green "Verified all VMs have RelocateVM_Task method enabled."
    }
} Until(($vms_pivoting).Count -eq 0)

Also note that all this $Host.UI stuff doesn't work from the Powershell ISE. To find out from within a script you could test for $Host.Name -eq "ConsoleHost" . When true you can use the code from this topic. Otherwise you could use $Host.UI.PromptForChoice or any other way of showing a dialog box. With System.Windows.Forms.Timer you can then set a timer, and code to close the dialog box or form can be run when it expires.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM