Home > Back-end >  How do I validate user input in a loop?
How do I validate user input in a loop?

Time:12-07

I'm a student and I need to write a script in Powershell ISE that will provide the user with a menu and then display OS information based on their selection or quit if they enter 'q'

I've got the menu input/output loop working but I'm also required to make sure they selected a valid option and reprompt them if not.

It outputs the invalid message no matter what the user input value is.

So if the user enters 1 it will return:

Invalid input, please select an option from the menu @{OsName=Microsoft Windows Server 2016 Standard} Press Enter to continue...:

I have no background in programming so my understanding of powershell and coding is very basic and most search results have provided examples that are beyond the scope of my knowledge!

function sysInfoMenu {

    param (
    [string] $Title = 'System Information'
    )

    Clear-Host

    Write-Host "=============== $Title ==============="
    "`n`n"
    Write-Host "Please select from the following options:"
    "`n"
    Write-Host "Press 1 for: OS System"
    Write-Host "Press 2 for: OS Type"
    Write-Host "Press 3 for: OS Architecture (32 or 64 bit)"
    Write-Host "Press 4 for: OS Version"
    Write-Host "Press 5 for: OS Bios Version"
    Write-Host "Press 6 for: Computer Brand"
    Write-Host "Press 7 for: Computer Name"
    Write-Host "Press 8 for: Current Domain"
    Write-Host "Press 9 for: Computer Model"
    Write-Host "Press 10 for: Current User"
    Write-Host "Press 11 for: Timezone"
    Write-Host "Press 'q' to quit."
}

do {
    sysInfoMenu
    $info = $null
    $UserInput = Read-Host "Please select an option from the menu"

        
    switch ($UserInput)
    {
      '1' {$info = Get-ComputerInfo -Property OSName}
      '2' {$info = Get-ComputerInfo -Property OSType}
      '3' {$info = Get-ComputerInfo -Property OSArchitecture}
      '4' {$info = Get-ComputerInfo -Property OSVersion}
      '5' {$info = Get-ComputerInfo -Property BiosVersion}
      '6' {$info = Get-ComputerInfo -Property CsManufacturer}
      '7' {$info = Get-ComputerInfo -Property CsName}
      '8' {$info = Get-ComputerInfo -Property CsDomain}
      '9' {$info = Get-ComputerInfo -Property CsModel}
      '10' {$info = Get-ComputerInfo -Property CsUserName}
      '11' {$info = Get-ComputerInfo -Property TimeZone}
    } 
          
          
       if ($UserInput -lt 1 -gt 11 -ne 'q'){
       Write-Host "Invalid input, please select an option from the menu"
       } 
      
  Write-Host $info
  pause
       
        
}
until ($UserInput -eq 'q') 

CodePudding user response:

You have a couple of structural problems.

  • You didn't terminate your function.
  • You didn't call your function.
  • You keep calling Get-ComputerInfo which is slow and only needs to be done once.
  • Your menu needs to be in your loop so you can clear the screen and get rid of the previous answers and/or error messages.

Here's some alternative code which I've commented to help you learn.

function SysInfoMenu {

    param (
     [Parameter(Mandatory=$False)]
      [string] $Title = 'System Information'
    )

#Setup:

   $ByeBye   = $False           #Set initial value.
   #Hide the Progress Bar. Remove line if not wanted.
   $ProgressPreference = "SilentlyContinue"
   $CompInfo = Get-ComputerInfo #You only need to call once.

#Main Function Code:

do {
    Clear-Host

    Write-Host "=============== $Title ==============="
    "`n`n"
    Write-Host "Please select from the following options:"
    "`n"
    Write-Host "Press  1 for: OS System"
    Write-Host "Press  2 for: OS Type"
    Write-Host "Press  3 for: OS Architecture (32 or 64 bit)"
    Write-Host "Press  4 for: OS Version"
    Write-Host "Press  5 for: OS Bios Version"
    Write-Host "Press  6 for: Computer Brand"
    Write-Host "Press  7 for: Computer Name"
    Write-Host "Press  8 for: Current Domain"
    Write-Host "Press  9 for: Computer Model"
    Write-Host "Press 10 for: Current User"
    Write-Host "Press 11 for: Timezone"
    Write-Host "Press 'q' to quit."

    $UserInput = Read-Host "Please select an option from the menu"
        
 #Note: use of Break to leave switch once match is found.
       
    switch ($UserInput) {
       '1' {$CompInfo.OSName         ;Break}
       '2' {$CompInfo.OSType         ;Break}
       '3' {$CompInfo.OSArchitecture ;Break}
       '4' {$CompInfo.OSVersion      ;Break}
       '5' {$CompInfo.BiosVersion    ;Break}
       '6' {$CompInfo.CsManufacturer ;Break}
       '7' {$CompInfo.CsName         ;Break}
       '8' {$CompInfo.CsDomain       ;Break}
       '9' {$CompInfo.CsModel        ;Break}
      '10' {$CompInfo.CsUserName     ;Break}
      '11' {$CompInfo.TimeZone       ;Break}
      'q'  {$ByeBye = $True          ;Break}
      default {"Invalid input, please select an option from the menu"}
    } #End Switch      
          
    if (-not $ByeBye) { pause }
        
  } until ($ByeBye) #Exit via $ByeBye value!

} #End Function SysInfoMenu

SysInfoMenu #Call your function

CodePudding user response:

Your script is almost fine, you're just having some trouble with your if condition:

$UserInput -lt 1 -gt 11 -ne 'q'

This is how PowerShell is evaluating the statement, and why it is always entering the if condition. Using the word test as $userInput:

'test' -lt 1   # => $false
$false -gt 11  # => $false
$false -ne 'q' # => $true

This is how it should look, note the use of -and:

'test' -lt 1 -and 'test' -gt 11 -and 'test' -ne 'q'

There is an alternative you can use with the -notmatch operator which allows the use of Regular Expressions.

In the example below, $UserInput -notmatch $regex will return $true at any user input that is not the ones we see on the $validoptions array (from 1 to 11 q).

$validoptions = 1..11   'q'
$regex = '^{0}$' -f ($validoptions -join '$|^')
# Regex: ^1$|^2$|^3$|^4$|^5$|^6$|^7$|^8$|^9$|^10$|^11$|^q$

$waitForUSer = {
    'Press ENTER to Continue...'
    Read-Host
}

do
{
    sysInfoMenu
    $UserInput = Read-Host "Please select an option from the menu"
    
    if ($UserInput -notmatch $regex){
        Write-Warning "Invalid input, please select an option from the menu"
        & $waitForUSer
        continue # => Go to Until, skip next lines
    }

    if($UserInput -eq 'q'){
        continue # => Go to Until and end the loop
    }
   
    $info = switch ($UserInput)
    {
      '1'  { 'Option 1' }
      '2'  { 'Option 2' }
      '3'  { 'Option 3' }
      '4'  { 'Option 4' }
      '5'  { 'Option 5' }
      '6'  { 'Option 6' }
      '7'  { 'Option 7' }
      '8'  { 'Option 8' }
      '9'  { 'Option 9' }
      '10' { 'Option 10' }
      '11' { 'Option 11' }
    }
      
    $info # => Show selection
    & $waitForUSer
}
until ($UserInput -eq 'q')
  • Related