Powershell -or on multiple checks - powershell

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

Related

PowerShell "DO...Until" Try and Catch for valid data not working

I'm trying to use PowerShell to check if a user-provided position number exists. I want to loop this until the user provides a valid position. I am fairly new to PowerShell and I don't understand why it's not working...
#Start Store and Check Budget Position Number User Template#
Clear-Host
Do{
Try{
# Find the user template
$budgetpositionnumber = Read-Host "
What budget position number is the user filling?
"
Write-Host "
You entered budget position number: $budgetpositionnumber
"
# Find the position on Your.Domain
Get-ADuser $budgetpositionnumber
}
Catch{
Write-Host ("Failed to find position number " + $budgetpositionnumber) -ForegroundColor Red -ErrorAction Stop
}
} Until ($budgetpositionnumber -ne $Null)
#End Store and Check Budget Position Number Template#
Even if I enter invalid data, it still continues with the rest of the script. I want it to stop or loop until its' a vaild position number.
##Edited for clarity
"Even if I enter invalid data, it still continues with the rest of the script"
The do loop always ends because it's until condition always evaluates to $true no matter what the input is, this is because any string, even if Empty, is not equal to $null.
The condition:
Until ($budgetpositionnumber -ne $Null)
Should be testing if Get-ADuser found any object instead of testing if there was an input provided in Read-Host.
As for how you can approach the code:
do {
$userinput = Read-Host "something here..."
Write-Host "You entered budget position number: $userinput"
try {
$found = Get-ADuser $userinput
}
catch {
Write-Warning "No account with Name '$userinput' exists..."
}
} until ($found)

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...

Loop Foreach only repeat offline computers

Not sure where I am going wrong I want to skip the computers which are coming back online but it keeps checking both online and online computers.
1st update is fine that its coming online and it should skip and only ping the offline one's a screenhot of output
g-10 Is coming online...Skipping to offline one's
192.168.0.1 Is coming online...Skipping to offline one's
Testing to see if Hero is coming online...
Hero is Offline. Pausing for 2 seconds. Remaining attempts: 1
Testing to see if zero is coming online...
zero is Offline. Pausing for 2 seconds. Remaining attempts: 1
Its fine upto here but online computers again repeated...
g-10 Is coming online...Skipping to offline one's
192.168.0.1 Is coming online...Skipping to offline one's
Testing to see if Hero is coming online...
Hero is Offline.
here is my code
$Comps = GC c:\restarted.txt
[int]$SleepTimer = "1" #minutes to attempt after
[int]$SleepSeconds = $SleepTimer * 2
[int]$Attempts = "2"
[int]$AttemptsCounter = 0
Do
{
$AttemptsCounter++
$RemainingAttempts = ([int]$Attempts - [int]$AttemptsCounter)
Foreach($comp in $comps){
$Online = Test-Connection -ComputerName $Comp -Quiet
IF($online -eq "True"){
Write-Host "$comp" -BackgroundColor Green -NoNewline
Write-Host " Is coming online...Skipping to offline one's"
}
elseIf ($Online -NE "True")
{
Write-Host "Testing to see if $Comp is coming online..."
Write-Host "$comp" -BackgroundColor Red -NoNewline
Write-Host " is Offline" -BackgroundColor Red -ForegroundColor Black -NoNewline
If ($AttemptsCounter -eq $Attempts) {
Write-Host "."
}
Else {
Write-Host ". Pausing for $SleepSeconds seconds. Remaining attempts: $RemainingAttempts"
}
}
}
#Check the number of attempts, break out if reached.
If ($AttemptsCounter -eq $Attempts) {break}
#Delay
Start-Sleep -s ($SleepTimer * 60)
}
While ($Online -NE "True")
If ($Online -NE "True") {
Write-Host "Maximum number of attempts reached"
}
Else {
Write-Host
Write-Host "Computer $Comp is " -NoNewline
Write-Host "ONLINE" -BackgroundColor Green
}
try the following code.
It basically does the following for each line in c:\restarted.txt:
tests if the computer is online (Note: I added -Count 1)
if it is online: prints some green text and break
if it is offline: print red text, wait and decrements the $RemainingAttempts variable and redo until $RemainingAttempts is 0 or the computer is online
it the $RemainingAttempts variable is 0 print out some more text
$ComputerNameArray = Get-Content -Path c:\restarted.txt
[int]$SleepTimer = "1" #minutes to attempt after
[int]$Attempts = "2"
$DefaultBackgroundColor = (Get-Host).ui.rawui.BackgroundColor
foreach($ComputerName in $ComputerNameArray) {
$AttemptsCounter = 0
$RemainingAttempts = $Attempts - $AttemptsCounter
Write-Host "Testing to see if ""$ComputerName"" is coming online..." -BackgroundColor $DefaultBackgroundColor
while($RemainingAttempts -gt 0) {
if(Test-Connection -ComputerName $ComputerName -Quiet -Count 1) {
Write-Host """$ComputerName""" -BackgroundColor Green -NoNewline
Write-Host " Is coming online...Skipping to offline one's"
break
} else {
Write-Host """$ComputerName""" -BackgroundColor Red -NoNewline
Write-Host " is Offline" -BackgroundColor Red -ForegroundColor Black -NoNewline
Write-Host ". Pausing for $SleepTimer minutes. Remaining attempts: $($RemainingAttempts - 1)"
Start-Sleep -Seconds ($SleepTimer * 60)
$RemainingAttempts--
}
}
if($RemainingAttempts -eq 0) {
Write-Host "Maximum number of attempts reached" -BackgroundColor $DefaultBackgroundColor
}
}
hope this helps!
Let me know if you have any question concerning the code.
KR
Guenther
Test-Connection returns an array of objects or a $null depending if the ip or hostname is live.
so its enough if you do this:
IF($online){
// if its alive
}
else
{
// if its not responding
}
another thing to point out is you dont have to
if(condition) {
}
elseif(condition) {
}
if you are testing "bool question-answer" you don't need the elseif. In your case, if you are checking the state of computer then you can't have more answers than 2 (yes/no). So the elseif is in this case redundant.
if(condition) {
// if the condition is true
}
else {
// if the condition is not true. you can't have the third option
}
Also your if condition If ($Online -NE "True") is checking if the variable $Online is not equal the exact string "true" or "True" since -ne is case insensitive condition operator.
You should check if the variable holds anything or holds $Null
While I know Guenther Schmitz has already got the green check, I wanted to follow up with some additional details and pointers.
Test-Connection with the -Quiet switch returns a [Boolean] type. This is a simple true/false. I like to be extra careful with comparing string values to Boolean values because you can get some odd results depending on how you frame your tests. For example:
'false' -eq $true
$true -eq 'false'
Top one equals false, bottom one equals true because PowerShell is converting the second object into the same type as the first, and a non-empty string is true. So my strong recommendation is to stick to typed comparisons. So the first code change I'd start with is:
if ($Online -eq $true) {
As #pandemic already mentioned, you're doing a simple comparison, so no need for elseif, just else.
The second issue you have is that there is nothing removing computers from your testing list. The way your code is written, if the last computer in your testing list is "down" then it'd go through all the computers again. If the last computer in the list is "up" then it'd quit the do|while loop, irregardless of how many computers you are testing and how many are down. You can verify this with a simple test of putting 1 known hosts, and 1 fake host in the test file. If the known good host is first, it'll keep looping until $AttemptsCounter reaches the maximum allowed. If you flip the list around, it'll bail out immediately after testing the known good host.
Your initial code looped through all the computers once then went back and started again. In Guenther's example, they loop one computer at a time, and check until it comes up, or bail out after exceeding the test count. I think Guenther's example was probably what you were after, but if you wanted to make it cycle through all the computers, and then test only those that had failed, I'd write something like this:
$comps = Get-Content -path 'c:\restarted.txt'
[int]$SleepTimer = 1
[int]$Attempts = 2
[int]$AttemptsCounter = 0
do {
Write-Host "Testing Network, attempt $($AttemptsCount + 1)"
$newComps = #()
foreach($comp in $comps) {
$online = Test-Connection -Quiet -Count 1 -ComputerName $comp
if ($online) {
Write-Host "$comp" -BackgroundColor Green -NoNewline
Write-Host " Is coming online...Skipping to offline one's"
} else {
$newComps += $comp
Write-Host "$comp" -BackgroundColor Red -NoNewline
Write-Host " is Offline" -BackgroundColor Red -ForegroundColor Black
}
}
$comps = $newComps
$AttemptsCounter++
Start-Sleep -Seconds ($SleepTimer * 60)
}
while (($comps.count -gt 0) -and ($AttemptsCounter -lt $Attempts))
if ($comps.Count -gt 0) {
Write-Host "Exceeded Attempts Counter" -BackgroundColor Red
}
In this code, it is taking the list of computers, and when it fails on a computer, it stuffs it into a temporary list for reuse.

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

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

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>