Creating an invalid variable entered prompt?

by justjon at 2013-04-16 04:33:52

Hi all,

I’m very new to PowerShell and have for a long time been scripting simple .bat files etc.

What I want to do is create a loop whereby a variable is being set, and if an incorrect answer is supplied the script will then re-ask the user to enter the variable.

$environment=Read-Host "One or two?

1. One

2. Twp
"


Above is the code I have so far with a simple prompt to set the $environment variable. I’d like it so that if a user enters anything other than 1 or 2 (the numbers), then it responds with "Invalid answer" and re-asks to set the variable.

In BAT this was quite simple to do with a GOTO command, obviously that’s not available anymore and I’m trying to conform to the new mindset of no GOTO’s in scripting!

Many thanks for any help.
by JeffH at 2013-04-16 05:03:45
Here’s one way you could try:

do {
$r = Read-Host "Enter a value [1,2]"
#validation code
if ($r -eq 1 -OR $r -eq 2) {
$ok = $true
}
else {
$ok = $false
}

} until ($ok)


The user would have to press Ctrl-C to break out if they wanted to cancel, at least as I’ve written this snippet.
by justjon at 2013-04-16 05:08:16
that’s perfect, thank you very much! :slight_smile: I could probably add another option (3) to exit if the user wanted to in any event.
by JeffH at 2013-04-16 05:17:18
Absolutely. Add whatever validation code you want. You can also use whatever expression you want in the Until () part, as long as it evaluates as True or False.
by mjolinor at 2013-04-16 05:52:04
Here’s another option:
$GetUserInput =
{
Switch (Read-Host 'Enter One or Two')
{
'One' {Write-Output 'User entered One'}
'Two' {Write-Output 'User entered Two'}
default {
Write-host "Invalid input. Please enter only 'One' or 'Two'" -ForegroundColor Yellow
.$GetUserInput
}
}
}

.$GetUserInput


or you can implement that as a function:

function GetUserInput
{
Switch (Read-Host 'Enter One or Two')
{
'One' {Write-Output 'User entered One'}
'Two' {Write-Output 'User entered Two'}
default {
Write-host "Invalid input. Please enter only 'One' or 'Two'" -ForegroundColor Yellow
. GetUserInput
}
}
}

GetUserInput
by poshoholic at 2013-04-16 07:36:49
Here’s yet another approach. This one allows you to keep your function clean, leveraging PowerShell’s native parameter validation support and automatic prompting using mandatory parameters while supporting repeated invocation of the function by leveraging try/catch blocks and watching for the exception that identifies that an invalid parameter was entered.
function Test-Something {
[CmdletBinding()]
param(
[Parameter(Position=0, Mandatory=$true, HelpMessage='Enter "One", "Two" or "Three"')]
[ValidateSet('One','Two','Three')]
[System.String]
$SomeParameter
)
"User entered ${SomeParameter}."
}

$inputValid = $false
do {
try {
Test-Something
$inputValid = $true
} catch [System.Management.Automation.ParameterBindingException] {
if ($.Exception.ErrorId -eq 'ParameterArgumentValidationError') {
Write-Host "Invalid input. Please enter 'One', 'Two', or 'Three', or press Ctrl+C to exit." -ForegroundColor Yellow
continue
}
throw
}
} until ($inputValid)
by cmcknz77 at 2013-04-16 13:58:47
That looks well complex…
This doesn’t fulfil your criteria because it’s not coming back at the user and saying ‘You’ve tried it before at least once and you got it wrong, please try it again’… But it will keep asking the question until the answer is correct. Suppose you could get around that by carefully phrasing the question - thereby morphing the problem into a ‘written language semantics’ issue instead of a ‘powershell language semantics’ issue…

While (!$Environment){
[Int32]$Environment = Read-Host "Please Enter '1' or '2'" |
Where-Object {$
-eq 1 -or $_ -eq 2}
}
by matternst at 2013-04-16 15:00:33
I was responding with something extremely similar to cmcknz77, and stopped to preview to make sure it was readable before posting my first post to these forums. Low and behold somebody had posted almost exactly what I was going to post minutes before me. This code is simplified but specific to the exact circumstances; good for a one-off when you don’t need a whole function. This just builds on cmcknz77’s code a tiny bit to allow for entry>fail message>re-entry as requested, and moved around the data verification of the do/while statement to where it makes more sense to me.
$valid="(1|2)" #Define valid responses
Read-Host "Select an option [1,2]"
if(!($YourVar -match $valid)){ #check for valid response
do{ #begin routine to cycle until valid response is given
Write-Host "I'm sorry, you must select from the options available."
$YourVar = Read-Host "Select an option [1,2]"
}
while(!($YourVar -match $valid))
}

This is fairly flexible, you can add more options as needed in case you have 6 options or what not, just add them to the "(1|2)", such as "(1|2|3|4|5|6)", or maybe "(1|2|3|4|5|6|c)" to allow an input of c to cancel. I’m sure you can see where I’m going with this. This just asks them for input and then adds a verification and re-prompt routine that runs until they enter something valid.

Hope you find that helpful.
*Edited to add $valid references for flexibility
by happysysadm at 2013-04-17 02:53:17
[quote="cmcknz77"]That looks well complex…
This doesn’t fulfil your criteria because it’s not coming back at the user and saying ‘You’ve tried it before at least once and you got it wrong, please try it again’… But it will keep asking the question until the answer is correct. Suppose you could get around that by carefully phrasing the question - thereby morphing the problem into a ‘written language semantics’ issue instead of a ‘powershell language semantics’ issue…

While (!$Environment){
[Int32]$Environment = Read-Host "Please Enter '1' or '2'" |
Where-Object {$_ -eq 1 -or $_ -eq 2}
}
[/quote]

Personally I like this alot. Great use of ‘While’.
I’ll keep it for future reference,
Carlo
by DexterPOSH at 2013-04-22 18:27:51
[quote="poshoholic"]
function Test-Something {
[CmdletBinding()]
param(
[Parameter(Position=0, Mandatory=$true, HelpMessage='Enter "One", "Two" or "Three"')]
[ValidateSet('One','Two','Three')]
[System.String]
$SomeParameter
)
"User entered ${SomeParameter}."
}

$inputValid = $false
do {
try {
Test-Something
$inputValid = $true
} catch [System.Management.Automation.ParameterBindingException] {
if ($_.Exception.ErrorId -eq 'ParameterArgumentValidationError') {
Write-Host "Invalid input. Please enter 'One', 'Two', or 'Three', or press Ctrl+C to exit." -ForegroundColor Yellow
continue
}
throw
}
} until ($inputValid)
[/quote]

I liked this one ;)…other approaches were very simple and elegant too
Recursion and clever use of try/catch caught my eye.