Powershell, check for blank input, zero evaluates as blank/null - powershell

I am trying to validate a simple powershell input. I want to allow the number zero as valid input, but blank (just pressing enter) is not valid input. I am having the most difficult time with the validation. Everything works EXCEPT when the user enters the number zero.
I have tried checking the length, checking for null, etc.
Consider the code below.
If you enter 0 (zero) the output is the same as if you just press [enter] (no input)
Pick a number 0-6: 0
You picked 0
blank input
equals zero
too short
$OUchoice = -1
do
{
try{
$OUchoice = Read-Host "Pick a number 0-6"
}
catch{
write-host "invalid input"
}
Write-Host "You picked $OUchoice"
if ($OUchoice -gt 6) {write-host "too high"}
if ($OUchoice -lt 0) {write-host "too low"}
if ($OUchoice -eq "") {write-host "blank input"}
if ($OUchoice -eq 0 ) {write-host "equals zero"}
if ($OUchoice -eq $null ) {write-host "Null"}
if (!($OUchoice)) {write-host "too short"}
}
until (($OUchoice -ge 0) `
-and ($OUchoice -le 6) `
-and (($ouchoice)))
write-host "OK"
I have tried -eq $NULL and -eq "". What is the proper way to allow zero and disallow blank input?

Problem lies in this:
PS> 0 -eq ""
True
When two values of different type are compared second argument is casted to the type of the first. Unfortunately for you:
PS> [int]""
0
empty string when casted to int produces 0. In your case fix is easy: just reverse the order of operands as 0 casted to string would end up being '0':
if ("" -eq $OUchoice) {write-host "blank input"}

This is what I came up with. I ensure that the $OUChoice is an Int when you compare it against other numbers. This ensures that null input is a 0 and also allows for negative values.
$OUchoice = -1
do
{
try{
$OUchoice = Read-Host "Pick a number 0-6"
}
catch{
write-host "invalid input"
}
Write-Host "You picked $OUchoice"
Switch ($OUchoice) {
{
[string]::IsNullOrEmpty($OUchoice)} {
write-host "Null Input"
Break
}
{
[int]$OUchoice -gt 6} {
write-host "too high"
Break
}
{
[int]$OUchoice -lt 0} {
write-host "too low"
Break
}
{
[int]$OUchoice -eq 0 } {
write-host "equals zero"
Break
}
}
}
until (([int]$OUchoice -ge 0) -and ([int]$OUchoice -le 6) -AND (-NOT [string]::IsNullOrEmpty($OUchoice)))
write-host "OK"

Nest your ifs (I didn't test much, but did check the zero and blank cases):
if (-not ($OUchoice -eq ""))
{
if ($OUchoice -gt 6) {write-host "too high"}
if ($OUchoice -lt 0) {write-host "too low"}
if ($OUchoice -eq 0 ) {write-host "equals zero"}
if ($OUchoice -eq $null ) {write-host "Null"}
if (!($OUchoice)) {write-host "too short"}
}
else
{
Write-Output "blank input"
}
Output:
PS C:\users\mattp_000> .\x.ps1
Pick a number 0-6:
You picked
blank input
Pick a number 0-6: 0
You picked 0
equals zero
OK
PS C:\users\mattp_000> .\x.ps1
Pick a number 0-6: 3
You picked 3
OK
PS C:\users\mattp_000>

Related

Color Guessing Game in Powershell [closed]

Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed last year.
Improve this question
I'm working on writing a script in PowerShell for a Color guessing game. The computer randomly picks a color then the player tries to guess the color. I had it working up until I switched some lines of code in the script in an attempt to get these two variables to display correctly. Now, I can't get the code to run past the point where a player declares if they want to play the game or not. My current error is with a do loop, where the console doesn't see that I have a while loop, and so throws an error and won't run the rest of the code.
I managed to get the formatting fixed with Visual Studio Code's format document feature, but I still can't get this one while loop problem figured out.
Write-Host ''; 'Hello again my friend!'; ''
$name = Read-Host "What is your name?"
Write-Host ''; "It's good to see you again, $name! Would you like to guess my favorite color?"; ''
$command = Read-Host #'
"How do you answer? (Yes or No?)"
1. Yes (y)
2. No (n)
3. Quit (q)
Enter Choice
'#
switch -Wildcard ($command) {
'Y' { 'Yes!'; '' }
{ $_ -eq 'y' -or $_ -like 'Ye*' } {
Write-Host "This will be fun! Let us begin!"
Break
}
'N' { 'No!'; '' }
{ $_ -eq 'n' -or $_ -like 'No*' } {
Write-Host "That's too bad, perhaps another day!"
Exit
}
'Q' { 'Quit'; '' }
{ $_ -eq 'q' -or $_ -like 'qu*' } {
Write-Host 'So long!'
Exit
}
default {
'Invalid Command, Please start over.'
Exit
}
}
[string]$playagain = 'y'
[int]$playerwins = 0
[int]$compwins = 0
[int]$totalguesses = 0
[int]$playergames = 0
[int]$compgames = 0
[int]$round = 1
[int]$game = 1
$cpuchoice = $color
while ($playagain -eq 'y') {
Write-Host ''; "Game $game!"; ''
$cpuchoice = #([System.Enum]::GetValues([System.ConsoleColor])) | Get-Random -Count 1
do {
Write-Host "Round $round! What is my favorite color?"; ''
$listcolor = Read-Host "Would you like to see a list of available colors? Choose 'y' for yes, and 'n' for no."
if ($listcolor -eq 'y') {
[System.Enum]::GetValues([System.ConsoleColor])
}
elseif ($listcolor -eq 'n') {
Write-Host "Suit yourself, let's start."
}
else {
Write-Host "Your choice was invalid. Please choose 'y' for yes, or 'n' for no."
}
do {
$playerchoice = Read-host "Enter your guess"
} while (([System.Enum]::GetValues([System.ConsoleColor])) -notcontains $playerchoice) {
if ($playerchoice -eq $cpuchoice ) {
Write-Host "You win, my favorite color is $cpuchoice." -ForegroundColor $cpuchoice; ''
$playerwins = $playerwins + 1
$totalguesses = $totalguesses + 1
}
elseif ($playerchoice -ne $cpuchoice ) {
Write-Host "You lose, try again."; ''
$playerguesses += $playerchoice
$playerguesses = $playerguesses.Split(',')
$totalguesses = $totalguesses + 1
Write-Host "Here are your guesses so far: "
$playerguesses
''
}
$round = $round + 1
}
until($playerwins -eq 1) {
$playergames = $playergames + 1
Write-Host "You've won this round and have won $playergames games." -ForegroundColor Green
Write-Host "Your total guesses: $totalguesses."
Write-Host "Your wins - $playergames" -ForegroundColor Yellow
Write-Host "Computer wins - $compgames" -ForegroundColor Yellow
''
}
$playagain = Read-Host "I enjoyed this game. Would you like to challenge again, $name? Y or N"
while (("y", "n") -notcontains $playagain) {
if ($playagain -eq "y") {
Write-Host "I look forward to our next battle!"; ''
$playerwins = 0
$compwins = 0
$game = $game + 1
}
elseif ($playagain -eq "n") {
Write-Host "Thank you for playing!"
exit
}
}
}
}
The do loop that causes the error is the one that starts with "Write-Host "Round $round!" after the first while statement.
Any help is appreciated! Thanks!
Your program is being parsed like this:
while ($playagain -eq 'y')
{
# do loop #1
do
{
# do loop #2
do {
}
while (([System.Enum]::GetValues([System.ConsoleColor])) -notcontains $playerchoice)
# floating script block #1
# (doesn't execute the scriptblock, but it gets sent to the output stream instead)
{
if ($playerchoice -eq $cpuchoice ) {
... etc ...
}
# try to invoke a cmdlet "until" with 2 parameters
# i.e. ($playerwins -eq 1) and { ... }
until ($playerwins -eq 1) {
$playergames = $playergames + 1
... etc ...
}
# while loop #1
while (("y", "n") -notcontains $playagain) {
...
}
}
}
The error is telling you the first do (do loop #1) doesn't have a trailing while or until.
There's no clear and simple fix I can offer to make your code run short of a significant rework because there's a number of issues (e.g. the floating script block #1, the dangling until and the while \ until-less do), but that's what the current error is saying anyway...

to avoid null characters in powershell

$q = 0
do {
$a = write-input "enter value"
switch ($a) {
1.{ some option }
2.{}
default {}
}
} while ($a -gt $q)
In the above code, if we give $a=$null value then switch terminates from while loop. Please help me out to skip null checking and to continue in the loop.
As Ansgar Wiechers points out in the comments, the comparison $null -gt 0 is False. This terminates your While loop. You could update your while statement to while ($a -eq $null -or $a -gt $q)
Another alternative would be use a recursive function,
function Example-Function {
switch (Read-Host "Enter Value") {
1 { "Option 1"; Example-Function }
2 { "Option 2"; Example-Function }
default { "Invalid Option, Exiting" }
}
}

Powershell IF with multiple conditions not working

It's not making any sense.
If I put this lines in my script
it will still accept a number as 123 even if it's supposed to be just between 1 and 32.
It's the line until ($setSubNetMask -cle 32 -and $setSubNetMask -cge 1) I'm having the problem with.
What's going on here?
do
{
$setSubNetMask = 0
$setSubNetMask = Read-Host -Prompt "Subnetmask (CIDR)"
if ($setSubNetMask -cge 32 -or $setSubNetMask -cle 2)
{
write-host "Felaktig CIDR (1-32)"
}
}
until ($setSubNetMask -cle 32 -and $setSubNetMask -cge 1)
Read-Host is giving you a string. You're comparing it to a number, which is being implicitly converted to a string because it's on the right side of the comparison.
What you want to do is convert to a number first:
do
{
$setSubNetMask = 0
[int]$setSubNetMask = Read-Host -Prompt "Subnetmask (CIDR)"
if ($setSubNetMask -cge 32 -or $setSubNetMask -cle 2)
{
write-host "Felaktig CIDR (1-32)"
}
}
until ($setSubNetMask -cle 32 -and $setSubNetMask -cge 1)
PowerShell also supports ranges, so your conditionals might better be expressed as:
do
{
$setSubNetMask = 0
$setSubNetMask = Read-Host -Prompt "Subnetmask (CIDR)"
if (1..32 -notcontains $setSubNetMask)
{
write-host "Felaktig CIDR (1-32)"
}
}
until (1..32 -contains $setSubNetMask)
In PowerShell v3 and higher, you can reverse the order using the -in operator instead of -contains, depending on what feels more natural to you:
do
{
$setSubNetMask = 0
$setSubNetMask = Read-Host -Prompt "Subnetmask (CIDR)"
if ($setSubNetMask -notin 1..32)
{
write-host "Felaktig CIDR (1-32)"
}
}
until ($setSubNetMask -in 1..32)
Note that in these examples, I removed the [int] cast; it's not needed and the conversion will be done implicitly in either case.
As #briantist noted, it's due to the Read-Host returning a string value, and then comparing that to an [int].
When comparing dissimilar object types, Powershell will attempt to do the perform the operation by trying to cast the value on the RH side to match the type on the LH side. This means you can implicitly re-cast the strings to [int] by reversing the order of your comparison arguments so that the [int] is on the LH side:
do
{
$setSubNetMask = 0
$setSubNetMask = Read-Host -Prompt "Subnetmask (CIDR)"
if (32 -le $setSubNetMask -or 2 -gt $setSubNetMask)
{
write-host "Felaktig CIDR (1-32)"
}
}
until (32 -le $setSubNetMask -and 1 -le $setSubNetMask)

Powershell -or on multiple checks

I have the following script that is causing an issue. It's doing a simple check to see if the number of characters entered is either 7 or 8. However, even after entering either 7 or 8 characters it doesn't move onto the else statement and displays "invalid number of characters".
If I remove the -or and stick to just one check then it works fine. I can't seem to get it to work when checking with the -or operator. All the examples I've found seem to suggest the code should work fine so can anyone spot what I'm missing?
Function number {
$global:change = read-host "Enter a number"
if ($global:change.length -ne 7 -or $global:change.length -ne 8) {
write-host $global:change.length
write-host -foregroundcolor red "Invalid number of characters"
number
}
else {
write-host "You entered the correct amount of characters"
}
}
number
You just need to flip your logic a bit to get this working. Based on the logic in your code, one of the cases will always be true. If you change the code to the following, you will get the desired effect.
Function number {
$global:change = read-host "Enter a number"
if (($global:change.length -eq 7) -or ($global:change.length -eq 8))
{
write-host "You entered the correct amount of characters"
}
else
{
write-host $global:change.length
write-host -foregroundcolor red "Invalid number of characters"
number
}
}
number
This will test whether you enter a value that is either 7 or 8 and loop if another value is entered.
Change the -or in an -and or style the code in this way:
Function number {
$global:change = read-host "Enter a number"
if ($global:change.length -eq 7 -or $global:change.length -eq 8) {
write-host "You entered the correct amount of characters"
}
else {
write-host $global:change.length
write-host -foregroundcolor red "Invalid number of characters"
number
}
}
number

If statement in an if statement

For an assignment I have to prove that if statements can be placed within if statements in a Powershell script. Therefore I made the enclosed script. I am however not sure whether the script I have describes two separate if statements or would be considered an if within an if.
[int]$a = Read-host "Please input a number."
if ($a –eq 5) {
Write-Host “a is 5” }
if ($a –ne 5) {
Write-Host “a isn't 5” }
Read-host
Any help on this one?
Thank you for your answer. Why does this not work however?
if ($a –lt 2) {
if ($a –lt 3) {
if ($a –lt 4) {
if ($a –lt 5) {
Write-Host “a is less than 5” }
Write-Host “a is less than 4” }
Write-Host “a is less than 3” }
Write-Host “a is less than 2” }
Nah, these are two separate if statements. Nested would be:
if ($a –lt 5) {
if ($a –ne 2) {
Write-Host “a isn't 2” }
Write-Host “a is lt 5” }