Return to menu after the input result - powershell

I'm working on a Show-Menu PS script. After the user gives in his input and he gets the result. He should see again the Menu and not "Enter the user ID: "
I know this is possible by removing the Show-Menu but than my user input is not selected for my commands.
Thanks in advance!
function Show-Menu {
param (
[string]$Title = 'UserInfo V3.1'
)
Write-Host "Enter the user ID: " -ForegroundColor Cyan -NoNewline
Read-Host
Write-Host ""
Write-Host "================ $Title ================"
Write-Host "Press 'U' for general user info."
Write-Host "Press 'P' for account and password information."
Write-Host "Press 'C' for computer info."
Write-Host "Press 'G' for Virtual Applications (AVC)."
write-Host "Press 'S' for SNOW info details"
Write-Host "Press 'Q' to Quit."
write-Host "=============================================="
}
do {
$userName = Show-Menu
$Selection = Read-Host "Please make a selection"
switch ($Selection) {
'U' { Get-ADUser -Identity $Username; pause }
}
} until ($Selection -eq 'q')

If Show-Menu is only supposed to show a menu, then prompting a user for input with Read-Host is clearly not appropriate. Move that part out of the Show-Menu function:
function Show-Menu {
param (
[string]$Title = 'UserInfo V3.1'
)
Write-Host ""
Write-Host "================ $Title ================"
Write-Host "Press 'U' for general user info."
Write-Host "Press 'P' for account and password information."
Write-Host "Press 'C' for computer info."
Write-Host "Press 'G' for Virtual Applications (AVC)."
write-Host "Press 'S' for SNOW info details"
Write-Host "Press 'Q' to Quit."
write-Host "=============================================="
}
Write-Host "Enter the user ID: " -ForegroundColor Cyan -NoNewline
$userName = Read-Host
do {
Show-Menu
$Selection = Read-Host "Please make a selection"
switch ($Selection) {
'U' { Get-ADUser -Identity $Username; pause }
}
} until ($Selection -eq 'q')

[you may find it simpler to just use the Out-Gridview cmdlet. there is a text-only console version available if you can install such.]
the following is a slightly different approach. it accepts a list of possible menu choices and ONLY accepts those items OR x as valid choices.
i think the code is fairly obvious, so i will just show it ... and the onscreen output. [grin]
function Get-MenuChoice
{
[CmdletBinding ()]
Param
(
[Parameter (
Mandatory,
Position = 0
)]
[string[]]
$MenuList,
[Parameter (
Position = 1
)]
[string]
$Title,
[Parameter (
Position = 2
)]
[string]
$Prompt = 'Please enter a number from the above list or "x" to exit '
)
$ValidChoices = 0..$MenuList.GetUpperBound(0) + 'x'
$Choice = ''
while ([string]::IsNullOrEmpty($Choice))
{
Write-Host $Title
foreach ($Index in 0..$MenuList.GetUpperBound(0))
{
Write-Host ('{0} - {1}' -f $Index, $MenuList[$Index])
}
$Choice = Read-Host -Prompt $Prompt
Write-Host ''
if ($Choice -notin $ValidChoices)
{
[System.Console]::Beep(1000, 300)
Write-Warning ''
Write-Warning (' [ {0} ] is not a valid selection.' -f $Choice)
Write-Warning ' Please try again.'
Write-Warning ''
$Choice = ''
pause
}
}
# send it out to the caller
if ($Choice -eq 'x')
{
'Exit'
}
else
{
$Choice
}
} # end >>> function Get-MenuChoice
'***** demo usage below *****'
$MenuList = #(
'An Item'
'Some Other Item'
'Middle Menu Item'
'Yet Another Item'
'The Last Choice'
)
$Choice = Get-MenuChoice -MenuList $MenuList
'You chose [ {0} ] giving you [ {1} ].' -f $Choice, $MenuList[$Choice]
output for one invalid & one valid input ...
0 - An Item
1 - Some Other Item
2 - Middle Menu Item
3 - Yet Another Item
4 - The Last Choice
Please enter a number from the above list or "x" to exit : 66
WARNING:
WARNING: [ 66 ] is not a valid selection.
WARNING: Please try again.
WARNING:
Press Enter to continue...:
0 - An Item
1 - Some Other Item
2 - Middle Menu Item
3 - Yet Another Item
4 - The Last Choice
Please enter a number from the above list or "x" to exit : 1
You chose [ 1 ] giving you [ Some Other Item ].

Related

How to create interactive PowerShell script from existing script

I've created a PS script in the past and I would like it to be more interactive.
This is the script I've created.
$csv = Import-CSV 'C:\Users\w0vlnd\Desktop\Powershells\Computers in a specific workgroup or domain.csv'
$ADprops = #(
'DisplayName'
'Mail'
'LastBadPasswordAttempt'
'AccountExpirationDate'
'PasswordLastSet'
'Enabled'
)
$filter = #(
$ADprops
#{
Name = 'Account active'
Expression = {$Account}
}, #{
Name = 'Password Changeable'
Expression = { $changeable }
}, #{
Name = 'Password Expires'
Expression = { $expires }
}, #{
Name = 'Last logon'
Expression = { $lastlogon }
}, #{
Name = 'PC Name'
Expression = { $pcName }
}, #{
Name = 'System Boot Time'
Expression = { $Boot }
}
)
Clear-Host
do
{
Write-Host "Enter the user ID: " -ForegroundColor Cyan -NoNewline
$UserName = Read-Host
Write-Host ""
#Computer Info#
$pcName = $csv.Where({ $_."User ID" -match $Username })."PC Name"
$boot = SystemInfo /s $pcName | Select-String -Pattern 'System Boot Time'|
ForEach-Object { ($_ -split '\s{2,}')[1] }
#Account and passowrd information#
$Account, $expires, $changeable, $lastlogon = net user $Username /domain |
Select-String -Pattern 'Account active|Password Changeable|Password Expires|Last logon'|
ForEach-Object { ($_ -split '\s{2,}')[1] }
Get-ADUser -Identity $Username -Properties $ADprops |
Select-Object $filter
} while ($Username -notcontains $Processes)
And I want to put it in to this script but I'm figuring out how. As in the first script the user must first fill in the user ID. Afterwards he get should get the options U,P,... Each option should be executing a command. An example of which command you can find in the first script like: #computer info# IF I haver already one command running I'll figure the rest out myself.
How can I do this? Also the menu should come back after the option has been chosen.
Thanks in advance!
param (
[string]$Title = 'UserInfo V3.1'
)
Clear-Host
Write-Host "================ $Title ================"
Write-Host "Press 'U' for general user info."
Write-Host "Press 'P' for account and password information."
Write-Host "Press 'C' computer information."
Write-Host "Press 'G' group memberships."
Write-Host "Press 'R' search for other user ID."
Write-Host "Press 'Q' to Quit."
}
Show-Menu –Title 'UserInfo V3.1'
$selection = Read-Host "Please make a selection"
switch ($selection)
{
'U' {
'You chose option #U'
} 'P' {
'You chose option #P'
} 'C' {
'You chose option #C'
} 'G' {
'You chose option #G'
} 'Q' {
'You chose option #Q'
return
}
I would use a PromptForChoice method, if a user select a wrong option, question will be asked again :
$repeat = $true
while ($repeat)
{
[System.Management.Automation.Host.ChoiceDescription[]]$choicelist =
"&User infos",
"&Account and password infos",
"&Computer infos",
"&Group membership",
"&Search for another user",
"&Quit"
switch ($Host.UI.PromptForChoice("Please select", "What do you want ?", $choicelist, 0))
{
0 {
"User infos here"
break
}
1 {
"Account & password infos here"
break
}
2 {
"Computer infos here"
break
}
3 {
"Group membership infos here"
break
}
4 {
"Search for another user Id here"
break
}
5 {
"Exiting."
$repeat = $false
}
}
}
Notice the & sign before the letter to be used (I have not used same letters as your code). This sign could be used inside the choice text, for example "Account and &password infos" means that you need to use the letter p to select this option.
The value returned by PromptForChoice is the selected index of the choice array.

How do I validate user input in a loop?

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')
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
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')

powershell $var has value, but when in if statement - gets false

Just making a little menu for zoom usage.
The user insert it's selection, and the script automatically opens zoom to the specific session.
The problem is at if (($hashTable.$selection).Count -gt 1) where $selection does have the value 1 (if I pressed 1) but the expression always gets false - so it proceeds to the else statement.
The goal is to have in the hash table either only a session number or both session number and a password.
After checking if there's more than one value to the key, then I chose my action.
$selection does holds the number the user enters - so why $hashTable.$selection is empty?
$hashTable = #{
1 = '6108514938', 'f'
2 = 'Val2'
3 = 'Val3'
}
function Show-Menu
{
param (
[string]$Title = 'My Menu'
)
Clear-Host
Write-Host "================ $Title ================"
Write-Host "1: Press '1' for Algorithms."
Write-Host "2: Press '2' for this option."
Write-Host "3: Press '3' for this option."
Write-Host "Q: Press 'Q' to quit."
}
do
{
    Show-Menu –Title 'ZOOM Menu'
$zoomBaseLink = 'zoommtg://zoom.us/join?confno='
$selectedSession = $null
   
$selection = Read-Host "Please select session"
    switch ($selection)
    {
        '1' { $selectedSession = ($hashTable.1) }
'2' { $selectedSession = ($hashTable.2) }
'3' { 'You chose option #3' }
    }
if($selection -ne 'q') {
if (([string]::IsNullOrEmpty($selectedSession))) {
Write-Host 'session is null or empty'
}
else {
Write-Host $selection
Write-Host $selectedSession
pause
<#($hashTable.$selection) always gets false.#>
if (($hashTable.$selection).Count -gt 1) { Write-Host 'here 1'; Write-Host $hashTable.$selection[1] }
else{ Write-Host 'here 2'; Write-Host ($zoomBaseLink + $selectedSession) }
}
$selectedSession = $null
}
    pause
}
until ($selection -eq 'q')
The problem ist, that you didn't convert the variable $selection to an integer.
[int]$selection = [convert]::ToInt32($selection, 10)
If you do that first, it will work (tested):
if($selection -ne 'q') {
if (([string]::IsNullOrEmpty($selectedSession))) {
Write-Host 'session is null or empty'
}
else {
Write-Host $selection
Write-Host $selectedSession
pause
[int]$selection = [convert]::ToInt32($selection, 10)
<#($hashTable.$selection) always gets false.#>
if (($hashTable.$selection).Count -gt 1) { Write-Host 'here 1'; Write-Host $hashTable.$selection[1] }
else{ Write-Host 'here 2'; Write-Host ($zoomBaseLink + $selectedSession) }
}
$selectedSession = $null
[string]$selection = $null
}
pause
Please let me know if it worked and if it did, please mark my post as the answer :)

PowerShell User Input, Menu, Sub Menu,

I'm trying to create an interactive PowerShell script that will do the following:
Menu 1 - Prompt user for file path. Then based on file path I will cd into the directory
Menu 2 - Once user input is done I would have a second menu that would prompt user to pick which file to parse
One user selects option it will output file and then restart from Menu 2
I'm not understanding how to only show the first menu, then once user input is submitted jump to second menu, and once user selects and file is parsed - come back to second menu until "Q".
$Filepath = Read-Host -Prompt 'Please Enter File Path'
do
cd $FilePath
function Show-Menu {
Clear-Host
Write-Host "1: Press '1' for parsing test.txt"
Write-Host "2: Press '2' for parsing test2.txt"
Write-Host "3: Press '3' for parsing test3.txt"
Write-Host "Q: Press 'Q' to quit."
}
do {
Show-Menu $selection = Read-Host "Please make a selection"
switch ($selection) {
'1' {
'You chose option #1'
Clear-Host
Import-Csv txt.file -Delimiter '|' -Header '1' ,'2' | Out-GridView
}
}
pause
} until ($selection -eq 'q')
You don't have two menus in your post. You only have one. Unless you are saying you are considering that Read-Host a menu.
Is this what you are trying to accomplish?
Clear-Host
$Filepath = Read-Host -Prompt "`nPlease Enter File Path"
Push-Location -Path $Filepath
$MenuOptions = #'
"Press '1' for parsing test1.txt"
"Press '2' for parsing test2.txt"
"Press '3' for parsing test3.txt"
"Press 'Q' to quit."
'#
"`n$MenuOptions"
while(($selection = Read-Host -Prompt "`nSelect a option") -ne 'Q')
{
Clear-Host
"`n$MenuOptions"
switch( $selection )
{
1 { 'Code for doing option 1 stuff' }
2 { 'Code for doing option 2 stuff' }
3 { 'Code for doing option 3 stuff' }
Q { 'Quit' }
default {'Invalid entry'}
}
Pop-Location
}
Rather than using a loop, the other option is to have the 'menu' function call itself to show the menu again after you've completed the parsing.
You could also use Host.ChoiceDescription to build and show the menu for you.
$Filepath = Read-Host -Prompt 'Please Enter File Path'
Set-Location $FilePath
function Get-Selection {
$Title = "Please make a selection"
$Message = "Select File for parsing"
$Option1 = New-Object System.Management.Automation.Host.ChoiceDescription "test.txt"
$Option2 = New-Object System.Management.Automation.Host.ChoiceDescription "test2.txt"
$Option3 = New-Object System.Management.Automation.Host.ChoiceDescription "test3.txt"
$Option4 = New-Object System.Management.Automation.Host.ChoiceDescription "Quit"
$Options = [System.Management.Automation.Host.ChoiceDescription[]]($Option1,$Option2,$Option3,$Option4)
$host.ui.PromptForChoice($title, $message, $options, 0)
}
function Show-Menu {
switch (Get-Selection) {
0 {
Write-Host 'You chose option #1'
Clear-Host
Import-Csv txt.file -Delimiter '|' -Header '1' ,'2' | Out-GridView
Show-Menu # Show menu for next choice
}
1 {
Write-Host 'You chose option #2'
Clear-Host
# Import-Csv
Show-Menu # Show menu for next choice
}
2 {
Write-Host 'You chose option #2'
Clear-Host
# Import-Csv
Show-Menu # Show menu for next choice
}
3 {
Write-Host 'Quit'
}
}
}
Show-Menu # Load menu when script is run

double loop Quit first or repeat

I would like to be able to exit the script after using option 1 and Q.
R for repeat works and any other key would bring me back to the
Menu before. Can i just use another while ($response -eq "Q") ? or is the do while loop just wrong for that? i already tried a if else version but im doing it kinda wrong. Any help please?
function Show-Menu
{
param (
[string]$Title = 'Who? '
)
cls
Write-Host "================ $Title ================"
Write-Host "1: 1"
Write-Host "2: 2"
Write-Host "3: 3"
Write-Host "4: 4"
Write-Host "5: 5"
Write-Host "6: 6"
Write-Host "7: 7"
Write-Host "8: 8"
Write-Host "Q: Q to Quit."
}
do
{
Show-Menu
$input = Read-Host "Please choose."
switch ($input)
{
'1' {
cls
'You chose option #1'
do {
$response = Read-Host "R to repeat, Q to Quit or anything else to go back" }
while ($response -eq "R")
} '2' {
cls
'You chose option #2'
} '3' {
cls
'You chose option #3'
} 'q' {
return
} '3' {
cls
'You chose option #1'
} '4' {
cls
'You chose option #2'
} '' {
cls
'You chose option #3'
} 'q' {
return
}
}
pause
}
until ($input -eq 'q')
how about:
'1'
{
cls
'You chose option #1'
do
{
$response = Read-Host "R to repeat, Q to Quit or anything else to go back"
}
while ($response -eq "R")
if ($response -eq "q")
{
exit
}
}
Just make an if statement. If response contains the Char Q then return.
function Show-Menu
{
param (
[string]$Title = 'Who? '
)
cls
Write-Host "================ $Title ================"
Write-Host "1: 1"
Write-Host "2: 2"
Write-Host "3: 3"
Write-Host "4: 4"
Write-Host "5: 5"
Write-Host "6: 6"
Write-Host "7: 7"
Write-Host "8: 8"
Write-Host "Q: Q to Quit."
}
do
{
Show-Menu
$input = Read-Host "Please choose."
switch ($input)
{
'1' {
cls
'You chose option #1'
do {
$response = Read-Host "R to repeat, Q to Quit or anything else to go back" }
while ($response -eq "R")
if($response.Contains("Q"))
{return}
} '2' {
cls
'You chose option #2'
} '3' {
cls
'You chose option #3'
} 'q' {
return
} '3' {
cls
'You chose option #1'
} '4' {
cls
'You chose option #2'
} '' {
cls
'You chose option #3'
} 'q' {
return
}
}
pause
}
until ($input -eq 'q')
One way to do it