Read-Host in While loop with if statement - powershell

This should be really simple, but I cannot make it work. I'm new to the PowerShell so my mistake is probably obvious. I'm trying to ask a user for an input using a while loop, and prompting the user to try again if what was entered was not numeric. In bash it would look like this:
while read -p "What is the first number? " first; do
if [[ $first = *[[:digit:]]* ]]; then
break # if $first is numeric, break loop
else
echo "$first is not numeric. Enter a numeric value. "
fi
done
Here's what I have for the PS:
While ($first = (Read-Host "What is the first number?") -as [double]) {
if ($first -eq $null) { Write-Host "Please enter a numeric value." }
else { break }
}
In the example above, I can break the loop fine when a number is entered, but I can't see the Write-Host statement if I type a string.

Looking at the While line:
While ($first = (Read-Host "What is the first number?") -as [double])
This will only enter/continue the loop body when the input is already a double, because it rolls up the cast to double as part of the loop condition. You want to enter the loop body on any input, and only check if it's a double afterwards. At least, that's what the bash code does:
While ($first = (Read-Host "What is the first number?")) {
if ( ($first -as [double]) -eq $null) { Write-Host "Please enter a numeric value." }
else { break }
}
Or you could continue using the cast as part of the condition by negating the whole expression, and thus avoid the need for the awkward break:
While (-not ($first = (Read-Host "What is the first number?") -as [double])) {
Write-Host "Please enter a numeric value."
}

You could use this to keep prompting for a valid number input as you are looking for.
Do {
"Please enter a numeric value." | Out-Host
$first = (Read-Host "What is the first number?") -as [double]
} While($null -eq $first)

Related

User input validation in PowerShell

I have this piece of code in PowerShell. I need user input validation to integer with writing output saying what is wrong with the input and expecting correct input.
$FromObj = "Please input object number"
$FromInput = Read-Host $FromObj
while(($FromInput -isnot [int])) {
#I also want to put in the while that the input has to be an integer, -gt 0, and -lt 800
Write-Output "Your input has to be a number."
$FromInput = Read-Host $FromObj
}
if ($FromInput -le 0) {
Write-Output "Your input has to be a number greater than 0!"
$FromInput = Read-Host $FromObj
}
elseif ($FromInput -ge 800) {
Write-Output "Your input has to be a number less than 800!"
$FromInput = Read-Host $FromObj
}
else {
$FromInput = $FromInput -as [int]
}
However, this is not working for me. Could you help me with validating it with writing outputs as the ones displayed above?
I think Nicks's link in comment already provides different right answers to your question i.e.: using regex to match \d+ (digits) or using [int]::TryParse(...) but to explain why your code is not working:
Read-Host will store user input as string unless you manipulate it which is what you were already doing on your last condition (the else {...} statement).
This is why you never get past the $FromInput -isnot [int] condition.
To fix the code you could simply attempt to store user input -as [int] since the beginning and since you have 3 Read-Host on your code you could save the user input attempt -as [int] in a ScriptBlock which then can be easily executed as many times as needed:
$FromObj = "Please input object number"
$giveMeNumber = { (Read-Host $FromObj) -as [int] }
$FromInput = & $giveMeNumber
while($FromInput -isnot [int]) {
Write-Output "Your input has to be a number."
$FromInput = & $giveMeNumber
}
if ($FromInput -le 0) {
Write-Output "Your input has to be a number greater than 0!"
$FromInput = & $giveMeNumber
}
elseif ($FromInput -ge 800) {
Write-Output "Your input has to be a number less than 800!"
$FromInput = & $giveMeNumber
}
Note, even though this works, the statement is not entirely correct since you're breaking out of the while loop after the input is [int] the user could force an incorrect input.
Try this instead which will execute indefinitely until right input:
Clear-Host
$ErrorActionPreference = 'Stop'
$FromObj = "Please input object number"
$scriptBlock = {
try
{
$FromInput = [int](Read-Host $FromObj)
# Note I'm using Write-Host instead of Write-Ouput, this is because
# we don't want to store the invalid inputs messages in the
# $userInput variable.
if ($FromInput -le 0) {
Write-Host "Your input has to be a number greater than 0!"
& $scriptBlock
}
elseif ($FromInput -ge 800) {
Write-Host "Your input has to be a number less than 800!"
& $scriptBlock
}
else {
$FromInput
}
}
catch
{
Write-Host "Your input has to be a number."
& $scriptBlock
}
}
$userInput = & $scriptBlock

validate for a 2-digit number

I need to in powershell
-Ask the user for a 2-digit number
-Validate this number is two numeric digits
-Take into account leading zeroes
-If the number is invalid, have the user try again
It seemed that using
$2digit = read-host
$2digit -match "[0-9][0-9]"
was working but it stopped out of nowhere. Any advice?
You are probably getting an a false result when you entered more than 2 characters.
eg:
This is because you have not specified length.
Resolution:
$2digit = read-host
($2digit.Length -le 2) -and ($2digit -match "[0-9][0-9]")
You can also change your regex pattern
$2digits -match "^[0-9][0-9]$"
^ - start of string or line
$ - end of string or line
I was able to figure it out
do{
do {
write-host -nonewline "Enter the two digit number: "
$2d = read-host
$value = $2d -as [Double]
$ok = $value -ne $NULL
if ( -not $ok ) { write-host "!!ERROR:You must enter numeric values!!" }
}
until ( $ok )
if ($2d.Length -eq 2){$holder = $true}
elseif($2d.Length -ne 2){Write-host "!!ERROR:The number must be 2 digits!!"}
}
while ( $holder -ne $true )
The first do loop will verify that the input is numeric and the second do loop will check it to be 2 numbers.
Regular expressions are your friend. This will only accept digits 0-9 with a length of two. Anything else will not be accepted.
do {
$input = Read-Host -Prompt 'Enter the two digit number(0-9)'
if ( $input -match '^\d{2}$' ) {
break
}
Write-Host "The value must be a two digit number; $input is invalid"
} while ( $true )

Why is pressing "Enter" equivalent to the number 0?

I don't understand why pressing enter key is the same as pressing 0 on the keyboard.
[int] $Choice = -1
$Count = 2
while ($Choice -lt 0 -or $Choice -gt $Count)
{
Write-Host "Input number"
$Choice = Read-Host
Write-Host "choice:"
Write-Host $Choice
}
The output will be 0 even if just press enter. I want the user to explicitly input 0.
In the very first statement:
[int] $Choice = -1
... you type-cast $choice to [int].
When you apply a cast to the left-hand side of an assignment (to the left of the variable name), PowerShell will "remember" it as a type-constraint and treat the variable as strongly typed - PowerShell will attempt to convert anything you assign to $choice from there on out to an [int].
Hitting enter in the prompt without any other input results in Read-Host returning an empty string (like "")
The conversion logic treats the empty string as $null, and casting $null to [int] results in the value 0. You can see this by casting an empty string to [int] directly:
PS C:\> [int]""
0
You should probably validate the input from Read-Host before assigning to $Choice if you explicitly require a number:
$inputString = Read-Host
if($inputString -notmatch '^\d+$') {
Write-Host "Digits only please!"
continue
}

checking parameter passed is string and integer

I am new to powershell scripting. I am supposed to check to see if the first parameter passed is a string and second parameter is an int.
function positions {
param (
[string] $inputstring,
[int] $num )
}
$inputstring=read-host "Enter your name"
if ( !$inputstring -eq "" ) {
Write-Output "The first recieved parameter is: " $inputstring "and its type is a string"}
else { Write-Output "The first received parameter is:" $inputstring "and its type is not a string" }
$num=read-Host "Enter a number"
if ( $num -eq int ) {
Write-Output "This second parameter is" $num "and its type is a integer"}
else { Write-Output "This second parameter is" $num "and its type is not a integer"}
I believe the if statement for the string is wrong because it give me right input only if i negate it with '!'
Also, for the int, if statement it is not reading 'int' after -eq.
I am extremely new to this so need help.
Firstly, when you take input from screen using read-host the input will be read and stored as a string, irrespective of what you enter. You can confirm this by running the following command and entering a number:
($checkInt = read-host).GetType().Name
This will output string, no matter what you enter. The equivalent would be to define the input variable like this:
$checkInt = "10"
$StringVariable = "This is a string"
$IntVariable = 10
$StringIntVariable = "10"
## Print out variable types
"String variable is type " + $StringVariable.GetType().Name
"Int variable is type " + $IntVariable.GetType().Name
"StringInt variable is type " + $StringIntVariable.GetType().Name
Which again, if you check the type of that variable will return string.
What you need to do is cast to an int and check if the value is null or check if the value is numeric:
## Checking if user input is alphanumeric
$stringIntVariable = Read-Host "Enter a number"
if (($stringIntVariable -as [int]) -ne $null) {
"StringIntVariable is numeric"
}
else {
"StringIntVariable is not numeric"
}
With regards to your code, the below will work how you want it to:
$inputstring = read-host "Enter your name"
if (($inputstring -as [int]) -eq $null) { ## Check if not castable to int
Write-Output "The first recieved parameter is: " $inputstring "and its type is a string"
}
else {
Write-Output "The first received parameter is:" $inputstring "and its type is not a string"
}
$num=read-Host "Enter a number"
## Checking if user input is numeric
if (($num -as [int]) -ne $null) {
Write-Output "This second parameter is" $num "and its type is a integer"
}
else {
Write-Output "This second parameter is" $num "and its type is not a integer"
}
As #TheMadTechnician pointed out using ($num -as [int]) -ne $null is more forgiving than using a regex match.
You can use GetType().
When checking for type equality put square brackets around the type ([string]):
if ( $inputstring.GetType() -eq [string] )
{
# $inputstring is type String
}
else
{
...
}
The value coming from Read-Host will always be a string, so one option to verify $num is an int is to cast it to an int. However, this will throw an exception if the input is not actually an integer, so instead of if else you could use try catch block:
$num = read-Host "Enter a number"
try {
# cast to int
$num = [int]$num
# $num is type int (Int32)
}
catch
{
# $num is not an int
}

Powershell while and until loop counting

I am new to powershell and trying to learn loops but i'm currently confused and stuck trying to create a while and until loop that,Asks input from the user, Allow input until a sentinel value is reached, Count the number of times the loop went thru, print out the user input onto new lines, then print the loop number.
while ($UserNumber = Read-Host -Prompt "Input a number from 1 to 10" )
echo "You have entered $UserNumber, now it will count until 20."
This is only the start and I have no idea how to continue. Any and all help would be greatly appreciated.
This may help
$loopCount = 0
do{
$answer = Read-Host "Input a number 1 - 10"
Write-Host "You entered $answer"
$loopCount++
if($answer -eq 4){
$answered = $true
}
} until ($answered -eq $true)
Write-Host ("Looped {0} times" -f $loopCount)
What's in your while (or until) statement needs to result in a boolean value, much like an if statement.
What you're likely going to want to do here is first ask the user for a number:
[int] $UserNumber = Read-Host -Prompt "Input a number from 1 to 10"
Write-Host "You have entered $UserNumber, now it will count until 20."
Note that I've specified that the $UserNumber is an integer... this is to stop PowerShell treating it as a string, which it would be default.
Then you'll want to construct a loop that runs while a certain condition is true (I'm assuming that the number is "less than 20" is what you're thinking about here.)
while ($UserNumber -lt 20) {
$UserNumber += 1 # Increase the value stored in the variable by 1.
$UserNumber
}
That loop will continue, incrementing that number by one (and output it) each iteration, until it reaches 20 or higher. The last time it is output, it will display "20".
$num=0
$total=0
$counter=0
do
{
$num = Read-Host " Input Number"
$total=$total + $num
$counter++
Echo "Counter : $counter and Total : $total"
}
until($total -ge 20 -or $counter -eq 10)
Write-Host "Output : $total and Number Input : $counter"
Results