Guessing a number with if-else statement - powershell

I have write a short powershell script for a guessing number game. This looks like following:
clear-host
$Guess = "11"
$response=read-host "Enter your guess"
if ($response -eq $guess)
{
write-host "Congratulations"
}
else {
write-host "Try again"
}
Now, if I want to do in such way that after a certain number of times wrong guessing for example, 3 times wrong guessing the program will exit. How I can do this? Can you please shade some light on that issue?

Here is a solution with a while loop
$count = 0
$answered = $false
while ($count -lt 3 -and $answered -eq $false) {
clear-host
$Guess = "11"
$response=read-host "Enter your guess"
if ($response -eq $guess)
{
$answered = $true
write-host "Congratulations"
}
else {
write-host "Try again"
}
$count++
}

Related

is there a better way for me to write a script for quiz in shell

I have been at this script for 24 hours and I am getting nowhere. I am so desperate for help.
I am trying to create a quiz and I need the switches to verify if the user's input matches the 3 options; 'Y' 'N' 'G' and if true move to the next question. If not, I need the switch to then prompt the user of the default output each time the user enter's anything else besides those 3 options.
function Test-statement ($Y,$N,$G,$YY,$NN,$GG){
$check = $Y -eq $YY
$check =$check -and ($N -eq $NN)
$check =$check -and ($G -eq $GG)
$check
}
$questions = #{
"what is the current year now" = #('2023','2023','2023')
"what is the previous year" = #('2022','2022','2022')
}
foreach ($key in $questions.keys) {
$check = $false
do{
write-host ("$key" + "?")
$Y = read-host "1"
$N = read-host "2"
$G = read-host "3"
$YY = $questions.$key[0]
$NN = $questions.$key[1]
$GG = $questions.$key[2]
$check = Test-statement $Y $N $G $YY $NN $GG
if (!($check)){write-host "not true" -ForegroundColor red}
} until ($check)
}

PowerShell Password Timeout [duplicate]

I have searched but apparently my google foo is weak. What I need is a way to prompt for user input in the console and have the request time out after a period of time and continue executing the script if no input comes in. As near as I can tell, Read-Host does not provide this functionality. Neither does $host.UI.PromptForChoice() nor does $host.UI.RawUI.ReadKey(). Thanks in advance for any pointers.
EDIT: Much thanks to Lars Truijens for finding the answer. I have taken the code that he pointed out and encapsulated it into a function. Note that the way that I have implemented it means there could be up to one second of delay between when the user hits a key and when script execution continues.
function Pause-Host
{
param(
$Delay = 1
)
$counter = 0;
While(!$host.UI.RawUI.KeyAvailable -and ($counter++ -lt $Delay))
{
[Threading.Thread]::Sleep(1000)
}
}
Found something here:
$counter = 0
while(!$Host.UI.RawUI.KeyAvailable -and ($counter++ -lt 600))
{
[Threading.Thread]::Sleep( 1000 )
}
It's quite old now but how I solved it based on the same KeyAvailable method is here:
https://gist.github.com/nathanchere/704920a4a43f06f4f0d2
It waits for x seconds, displaying a . for each second that elapses up to the maximum wait time. If a key is pressed it returns $true, otherwise $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;
}
And to use:
$val = TimedPrompt "Press key to cancel restore; will begin in 3 seconds" 3
Write-Host $val
For people who are looking for a modern age solution with an additional constraint for exiting a PowerShell script on a pre-defined key press, the following solution might help you:
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.")
Sample script output:
Refer Microsoft document on key states for handling more combinations.
Credits: Technet Link
Here is a keystroke utility function that accepts:
Validation character set (as a 1-character regex).
Optional message
Optional timeout in seconds
Only matching keystrokes are reflected to the screen.
Usage:
$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)'."
}
Implementation:
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})
}
timeout.exe 5
still works from powershell. Waits 5 seconds or until key press.
Inelegant perhaps. But easy.
However,
From the Powershell_ISE it pops up a new command prompt window, and returns immediately, so it doesnt wait (From the powershell console it uses that console and does wait). You can make it wait from the ISE with a little more work (still pops up its own window tho):
if ($psISE) {
start -Wait timeout.exe 5
} else {
timeout.exe 5
}
Another option: you can use choice shell command which comes with every Windows version since Windows 2000
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
}
Stackoverflow syntax higlighting doesn't work for powershell, # means "comment" here
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
To optionally pause the script before it exits (useful for running headless scripts and pausing on error output), I appended nathanchere's answer with:
if ([Console]::KeyAvailable) { $pressedKey = [Console]::ReadKey($true); read-host; break; }
elseif ($secondsCounter -gt $secondsToWait) {
Write-Host "`r`n"
return $false;
}
The $Host.UI.RawUI.KeyAvailable seems to be buggy so I had more luck using [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 ;}
}

Prompt for choice. Re-prompt if option is invalid

I'm wondering how to re-prompt if someone typos or enters something other than yes/no
Would it have to be a created as a prompting function or is there an easier way?
$Continue = Read-Host -Prompt "Continue? Yes/No"
Switch($Continue){
'Yes' { Write-host -ForegroundColor Yellow "Moving on..." }
'No' {Write-host "...GoodBye"
Exit
}
default { #HOW TO RE-PROMPT USER FOR YES/No?
}
}
Using a While loop which a check variable. If Yes is typed then $Check will equal $true exiting the loop. Else it will stay false and rerun the loop again.
$Check = $false
while($Check -eq $false){
Switch(Read-Host -Prompt "Continue? Yes/No"){
'Yes' {
Write-host -ForegroundColor Yellow "Moving on..."
$Check = $true
}
'No' {
Write-host "...GoodBye"
return
}
}
}

Function not outputting value?

I'm working on a PowerShell script for some work use, and am having trouble getting a function it's data directly to a variable. Below is the function and my test:
function validateInput {
Param(
[string]$Text = 'Put text here'
)
do {
try {
$numOk = $true
$GetMyANumber = Read-Host "$text"
if ($GetMyANumber -gt 3){
$numOK = $false
}
} catch {
$numOK = $false
}
if ($numOK -ne $true) {
cls
Write-Host "Please enter a valid number" -Foreground Red
}
} until (($GetMyANumber -ge 0 -and $GetMyANumber -le 3) -and $numOK)
}
$firstName = validateInput($firstNamePrompt)
$lastName = validateInput ($lastNamePrompt)
Write-Host "First name length is $firstname"
Write-Host "Last name length is $lastname"
My understanding is that the in the last few lines, the function SHOULD assign it's output to the variables $firstName and $lastName, but I output that, they are blank. I'm sure I'm missing something obvious here, but can anyone let me know what I'm screwing up?

Is there a similar timeout function in Powershell as in CMD prompt? [duplicate]

I have searched but apparently my google foo is weak. What I need is a way to prompt for user input in the console and have the request time out after a period of time and continue executing the script if no input comes in. As near as I can tell, Read-Host does not provide this functionality. Neither does $host.UI.PromptForChoice() nor does $host.UI.RawUI.ReadKey(). Thanks in advance for any pointers.
EDIT: Much thanks to Lars Truijens for finding the answer. I have taken the code that he pointed out and encapsulated it into a function. Note that the way that I have implemented it means there could be up to one second of delay between when the user hits a key and when script execution continues.
function Pause-Host
{
param(
$Delay = 1
)
$counter = 0;
While(!$host.UI.RawUI.KeyAvailable -and ($counter++ -lt $Delay))
{
[Threading.Thread]::Sleep(1000)
}
}
Found something here:
$counter = 0
while(!$Host.UI.RawUI.KeyAvailable -and ($counter++ -lt 600))
{
[Threading.Thread]::Sleep( 1000 )
}
It's quite old now but how I solved it based on the same KeyAvailable method is here:
https://gist.github.com/nathanchere/704920a4a43f06f4f0d2
It waits for x seconds, displaying a . for each second that elapses up to the maximum wait time. If a key is pressed it returns $true, otherwise $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;
}
And to use:
$val = TimedPrompt "Press key to cancel restore; will begin in 3 seconds" 3
Write-Host $val
For people who are looking for a modern age solution with an additional constraint for exiting a PowerShell script on a pre-defined key press, the following solution might help you:
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.")
Sample script output:
Refer Microsoft document on key states for handling more combinations.
Credits: Technet Link
Here is a keystroke utility function that accepts:
Validation character set (as a 1-character regex).
Optional message
Optional timeout in seconds
Only matching keystrokes are reflected to the screen.
Usage:
$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)'."
}
Implementation:
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})
}
timeout.exe 5
still works from powershell. Waits 5 seconds or until key press.
Inelegant perhaps. But easy.
However,
From the Powershell_ISE it pops up a new command prompt window, and returns immediately, so it doesnt wait (From the powershell console it uses that console and does wait). You can make it wait from the ISE with a little more work (still pops up its own window tho):
if ($psISE) {
start -Wait timeout.exe 5
} else {
timeout.exe 5
}
Another option: you can use choice shell command which comes with every Windows version since Windows 2000
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
}
Stackoverflow syntax higlighting doesn't work for powershell, # means "comment" here
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
To optionally pause the script before it exits (useful for running headless scripts and pausing on error output), I appended nathanchere's answer with:
if ([Console]::KeyAvailable) { $pressedKey = [Console]::ReadKey($true); read-host; break; }
elseif ($secondsCounter -gt $secondsToWait) {
Write-Host "`r`n"
return $false;
}
The $Host.UI.RawUI.KeyAvailable seems to be buggy so I had more luck using [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 ;}
}