Powershell - Check number for several ranges - powershell

Hi I am new to Powershell and need some help:
My Script gets a number by userinput. I want to check this number if it´s between these ranges. So far so easy, but the input from 1-9 is with a leading zero.
With google, I got this working without the special case "leading zero".
do {
try {
$numOk = $true
$input = Read-host "Write a number between 1-12"
} # end try
catch {$numOK = $false }
} # end do
# check numbers
until (
($input -ge 1 -and $input -lt 13) -or
($input -ge 21 -and $input -lt 25) -or
($input -ge 41 -and $input -lt 49) -or
($input -ge 61 -and $input -lt 67) -and $numOK)
Write-Host $input
For example:
Input "5" Output "5"
Input "05" stucks in loop, should be "05"
AddOn: Is it possible to block inputs like 1-9 and just accept inputs like 01-09?

you can use the -f operator to format the string here is to get a 2 digits number
PS>"{0:00}" -f 5
05
some readings : http://ss64.com/ps/syntax-f-operator.html

Related

My if loop is taking effect even when it should not

I am making a random number guessing program where users try to guess a number between 1 and 100 while receiving whether they were higher or lower. one of the stipulations was that there must be a function to quit the program upon the user entering Q or q so I formatted my loop as such:
$RandomNumber = Get-Random -Minimum 1 -Maximum 101
write-output $RandomNumber
$GuessNumber = 0
While ($RandomNumber -ne $Guess)
{
$Guess = Read-Host -Prompt 'Guess a number between 1 and 100 Or enter Q to quit'
if ($Guess -eq 'q' -or 'Q')
{
Write-output "Thank you for playing"
BREAK
}
if ($Guess -gt 100 -or $Guess -le 1)
{
Write-Output 'Invalid Input please enter a number between 1 and 100'
}
if ($Guess -le $RandomNumber)
{
Write-output 'Your number is lower than the hidden number please guess again'
$GuessNumber = $GuessNumber +1
}
if ($Guess -gt $RandomNumber)
{
Write-output 'Your number is higher than the hidden number please guess again'
$GuessNumber = $GuessNumber +1
}
if ($Guess -eq $RandomNumber)
{
$GuessNumber = $GuessNumber +1
Write-output 'Congratulations you guessed the number in' $GuessNumber 'tries'
}
}
the issue I run into is even when the input is equal to 10 for example it still outputs "Thank you for playing" meaning that if loop has taken effect. I am not sure why this occurs as I'm new to powershell and a reasoning for this happening would be helpful
Replace
if ($Guess -eq 'q' -or 'Q')
with
if ($Guess -eq 'q' -or $Guess -eq 'Q')
Your error partially comes from -or 'Q' which evaluates to $true always:
$false -or 'somestring' # => True
And it's also worth noting, -eq is case insensitive ('q' -eq 'Q' is $true).The other error comes from comparing a string with an integer. The output from Read-Host is System.String in this case:
'50' -gt 100 # => True
'50' -lt 100 # => False
On the other hand, you could make your code more readable using a switch statement. For input validation you could use a recursive script block to make sure its always right (between 1 and 100 or Q). To break the outer while loop you can use a labeled break.
$RandomNumber = Get-Random -Minimum 1 -Maximum 101
$validation = {
$choice = Read-Host 'Guess a number between 1 and 100 Or enter Q to quit'
if($choice -notmatch '^([1-9][0-9]?|100|q)$') {
Write-Warning 'Invalid Input, try again.'
return & $validation
}
$choice
}
$attempts = 0
:outer while($true) {
$choice = & $validation
if($choice -eq 'q') {
# End the Game
'Thanks for Playing'
break
}
$attempts++
switch([int]$choice) {
{$_ -gt $RandomNumber} {
"$_ was greater than hidden number"
break
}
{$_ -lt $RandomNumber} {
"$_ was lower than hidden number"
break
}
default {
"You guessed right after $attempts tries, Congratulations!"
break outer
}
}
}
The condition is wrong. $Guess -eq 'q' -or 'Q' returns true always, it should be $Guess -eq 'q' -or $Guess -eq 'Q'.

powershell function that prints letter grade with a range [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 4 years ago.
Improve this question
so far i got this need help writing this function:
if (grades$Final[i] >=90) {
"A"
}
else if (grades$Final[i] >=80){
"B"
}
else if(grades$Final[i] >=70){
"C"
}
else if(grades$Final[i] >=60){
"D"
}
else {"F"}
}
}
Hello in this case i would suggest using a switch instead of a bunch of If statements
In powershell we use -lt (less than) -gt (Greater than) -eq (Equal) -ge (Greater or equal) -le (Less than or equal)
I noticed you are using [i] to call the index in an array i assume.
In powershell you can pipe |. So You can take an array and pipe it to a function. You can create an array using #().
#("Hello","World") | Foreach-object{
"$_ TEST"
}
Output
Hello TEST
World TEST
So i bet you are wondering what $_ is. Well When you pipe its the object that was piped so as in the example above since the array had 2 entries the first loop it equaled Hello and the second time it equaled World
So here is a function to get Int to Grade Letters. As you can see at bottom piping Ints into the function
function Get-LetterGrade(){
param(
[Parameter(Position=1, ValueFromPipeline=$true)]
[int]$Grade
)
process{
switch($Grade){
{$_ -ge 90} { "A" }
{$_ -ge 80 -and $_ -lt 90} { "B" }
{$_ -ge 70 -and $_ -lt 80} { "C" }
{$_ -ge 60 -and $_ -lt 70} { "D" }
{$_ -lt 60} { "F" }
}
}
}
90,80,70,60,50 | Get-LetterGrade
Output would be
A
B
C
D
F
In Powershell numeric comparison operators are a little different...
is -gt
< is -lt
= is -ge
There is a ton (...ton) of documentation on comparison operators in Powershell, which you can get via Google.
"else if" would be "elseif". Your variable name is a little weird. In Powershell, we start variable names with a dollar sign, "$". It sort of looks like you have an array named "grades$Final". It's confusing. Stick to conventions on variable names; descriptive and adhering to naming rules.
If I had to re-write your logic, I'd use something like...
$grades = #(12, 78, 83, 92)
foreach ($grade in $grades) {
if ($grade -ge 90) {
write-output 'A'
} elseif ($grade -lt 90 -and $grade -ge 80) {
write-output 'B'
} elseif ($grade -lt 80 -and $grade -ge 70) {
write-output 'C'
} elseif ($grade -lt 70 -and $grade -ge 60) {
write-output 'D'
} elseif ($grade -lt 60) {
write-output 'F'
}
}

Finding Middle Number in PowerShell

I am practicing in PowerShell and am making a user response input where one of the options is to input 3 numbers, and the program will return the middle number. I have done this a million times and it seems I cannot get it to return the middle number consistently.
For example when my numbers are 1, 23452342 and 3, it says that 3 is the middle number.
Here is my code:
if ($response -eq 1) {
$a = Read-Host "Enter a number "
$b = Read-Host "Enter a second number "
$c = Read-Host "Enter a third number "
if (($a -gt $b -and $a -lt $c) -or ($a -lt $b -and $a -gt $c)) {
Write-Host "$a is the middle number"
}
if (($b -gt $a -and $b -lt $c) -or ($b -gt $c -and $b -lt $a)) {
Write-Host "$b is the middle number"
}
if (($c -gt $a -and $c -lt $b) -or ($c -gt $b -and $c -lt $a)) {
Write-Host "$c is the middle number"
}
}
Instead of doing a number of individual comparisons simply sorting the three values and picking the second element will give you the median right away. But I suspect what's actually messing up the results for you is that Read-Host returns strings when you need them to be numeric values. Sort order of strings ("1" < "20" < "3") is different from numeric sort order (1 < 3 < 20), because characters at corresponding positions are compared rather than the whole number.
Casting the entered values to integers (or doubles if you expect floating point numbers) should resolve the issue:
if ($response -eq 1) {
[int]$a = Read-Host 'Enter a number'
[int]$b = Read-Host 'Enter a second number'
[int]$c = Read-Host 'Enter a third number'
$n = ($a, $b, $c | Sort-Object)[1]
Write-Host "$n is the median."
}
As an additional solution that would work on any array where u need the middle item you could just solve it like this:
$arr = 1..50
($arr | Sort-Object)[[int](($arr.count -1) /2)]
If your array comes in a format that does not need the sorting, just leave this part out.
edit: Obviously you would have to insert the data into an array on the first step.
Best regards

PowerShell limit entries in text boxes to integer values only [duplicate]

I have a small program which accepts an integer and converts it to DateTime. However, I try to use KeyCode to only allow numbers from both keyboard and numpad, and eliminate the special characters and letters. My code is allowing Shift+Num to enter those special characters. How do eliminate them from being entered?
$FromDateText.Add_KeyDown({KeyDown})
$ToDateText.Add_KeyDown({KeyDown}) #TextBox
Function KeyDown()
{
if ($FromDateText.Focused -eq $true -or $ToDateText.Focused -eq $true)
{
if ($_.KeyCode -gt 47 -And $_.KeyCode -lt 58 -or $_.KeyCode -gt 95 -and
$_.KeyCode -lt 106 -or $_.KeyCode -eq 8)
{
$_.SuppressKeyPress = $false
}
else
{
$_.SuppressKeyPress = $true
}
}
}
Instead of intercepting the KeyDown event, I'd simply just remove any non-digit character from the TextBox every time the TextChanged event is raised:
$ToDateText.add_TextChanged({
# Check if Text contains any non-Digits
if($tbox.Text -match '\D'){
# If so, remove them
$tbox.Text = $tbox.Text -replace '\D'
# If Text still has a value, move the cursor to the end of the number
if($tbox.Text.Length -gt 0){
$tbox.Focus()
$tbox.SelectionStart = $tbox.Text.Length
}
}
})
Way easier than trying to infer the input value from Key event args

Limiting text box entry to numbers or numpad only - no special characters

I have a small program which accepts an integer and converts it to DateTime. However, I try to use KeyCode to only allow numbers from both keyboard and numpad, and eliminate the special characters and letters. My code is allowing Shift+Num to enter those special characters. How do eliminate them from being entered?
$FromDateText.Add_KeyDown({KeyDown})
$ToDateText.Add_KeyDown({KeyDown}) #TextBox
Function KeyDown()
{
if ($FromDateText.Focused -eq $true -or $ToDateText.Focused -eq $true)
{
if ($_.KeyCode -gt 47 -And $_.KeyCode -lt 58 -or $_.KeyCode -gt 95 -and
$_.KeyCode -lt 106 -or $_.KeyCode -eq 8)
{
$_.SuppressKeyPress = $false
}
else
{
$_.SuppressKeyPress = $true
}
}
}
Instead of intercepting the KeyDown event, I'd simply just remove any non-digit character from the TextBox every time the TextChanged event is raised:
$ToDateText.add_TextChanged({
# Check if Text contains any non-Digits
if($tbox.Text -match '\D'){
# If so, remove them
$tbox.Text = $tbox.Text -replace '\D'
# If Text still has a value, move the cursor to the end of the number
if($tbox.Text.Length -gt 0){
$tbox.Focus()
$tbox.SelectionStart = $tbox.Text.Length
}
}
})
Way easier than trying to infer the input value from Key event args