Friday, August 1, 2014

Creating a Menu with Powershell

So today we are going to talk about how you can create a menu in Powershell.  Menus can be useful for creating simple interfaces to perform everyday tasks.  You might create a menu for a user who has no knowledge of scripting whatsoever so that they can easily perform a task they otherwise couldn't.  This article is intended for those with little scripting experience and the topics I will cover include:

1. Creating a function
2. If/Then logic
3. Using Read-Host to accept user input
4. Using Write-Host to display output
5. Putting your script to sleep for an interval of time

Creating a Function

A function can be just about anything you want it to be.  I am going to be using a function to group several lines of my script into one command called "MainMenu".  I can call this group of lines in my script by simply typing the name of the function.  So let's create our menu:


 function mainmenu{  
 cls  
 echo "---------------------------------------------------------"  
 echo ""  
 echo ""  
 echo "    1. Open Notepad"  
 echo "    2. Open Calculator"  
 echo "    3. Exit"  
 echo ""  
 echo ""  
 echo "---------------------------------------------------------"  
 $answer = read-host "Please Make a Selection"  
                 }  

In the code block above, I've created a simple menu.  I am storing the read-host command in a variable called "$answer".  For now, everything else is just for looks, so lets add some if statements to handle the user input requested by read-host.


If Statements

We can use If statements to filter user input in our menu.  If a user presses 1, we want notepad to open.  If you user presses 2, we want them to see a calculator show up on their screen.  Here how it works:


 if ($answer -eq 1){notepad}  
 if ($answer -eq 2){calc}  

This syntax is fairly simple.  We start our statement with the word "if".  Next we take our user input which is now stored in the variable "$answer" and test it against something.  In this case, we are explicitly saying if $answer is equal to 1, open notepad.  If answer is equal to 2, open calculator.  In this example, we are only using the -eq (equals) comparison operator.  Other comparison operators you can use are:

-ne (not equal to)
-gt (greater than)
-lt (less than)
-ge (greater than or equal to)
-le (less than or equal to)

I'm going to do something a little different for option 3, exit.  I'm going to create another function with if statements that will ask the user if they are sure they want to exit and allows them to answer yes or no.  I will call this function "areyousure".  Also, I will want to place this function ahead of where I will be using it in my script.  Can't call the function if it doesn't know about it right?  For convenience, I will just go ahead and place it at the top of my script (see full script code at end of page for example).


 function areyousure {$areyousure = read-host "Are you sure you want to exit? (y/n)"  
           if ($areyousure -eq "y"){exit}  
           if ($areyousure -eq "n"){mainmenu}  
                     }  
            


So now if a user presses 3 in our menu to exit, they'll be prompted with the question (using read-host again) "Are you sure you want to exit? (y/n).  As you can see in my if statements, if they press "y", powershell will exit.  If they press "n", it calls my "mainmenu" function and returns them to the main menu to start all over.  But what if they type something else?  Any other input will break the script.  Lets add something else to handle that.


 function areyousure {$areyousure = read-host "Are you sure you want to exit? (y/n)"  
           if ($areyousure -eq "y"){exit}  
           if ($areyousure -eq "n"){mainmenu}  
           else {write-host -foregroundcolor red "Invalid Selection"   
                 areyousure  
                }  
                     }  

Notice the line starting with the word "else".  Else says we are going to take any user input besides what was used in our if statements and do something with it.

My else statement has 2 lines.  The first line will do a write-host and display the text on screen saying "Invalid Selection".  It will also color that text red so the user knows something isn't right.  The second line will re-run the "areyousure" function, giving the user the opportunity to decide once again whether or not they wish to exit.


Sleep Command

I'm going to add one more thing to our "mainmenu" function.  I want to create an else statement to handle other input besides the options offered.  This time, I will use "sleep" to display a message for 5 seconds, then return to requesting input.


 else {write-host -ForegroundColor red "Invalid Selection"  
       sleep 5  
       mainmenu  
      }  

So basically, just the word "sleep", and the time interval in seconds.  The menu will not accept input until this timer expires.

Finishing Up

So now our script is done!  I'm going to add one last line to the end of it that calls our "mainmenu" function so that the menu launches as soon as you open the script.



 #source ps1scripting.blogspot.com  

 #Areyousure function. Alows user to select y or n when asked to exit. Y exits and N returns to main menu.  
 function areyousure {$areyousure = read-host "Are you sure you want to exit? (y/n)"  
           if ($areyousure -eq "y"){exit}  
           if ($areyousure -eq "n"){mainmenu}  
           else {write-host -foregroundcolor red "Invalid Selection"   
                 areyousure  
                }  
                     }  
 #Mainmenu function. Contains the screen output for the menu and waits for and handles user input.  
 function mainmenu{  
 cls  
 echo "---------------------------------------------------------"  
 echo ""  
 echo ""  
 echo "    1. Open Notepad"  
 echo "    2. Open Calculator"  
 echo "    3. Exit"  
 echo ""  
 echo ""  
 echo "---------------------------------------------------------"  
 $answer = read-host "Please Make a Selection"  
 if ($answer -eq 1){notepad}  
 if ($answer -eq 2){calc}  
 if ($answer -eq 3){areyousure}  
 else {write-host -ForegroundColor red "Invalid Selection"  
       sleep 5  
       mainmenu  
      }  
                }  
 mainmenu  

The full script is above if you'd like to test it out, or modify it for your own purpose.  I've used menus like these for things like automating active directory account creation and deletion.  I also have Active directory queries setup to pull account specific info such as is the account locked, is the user's password expired, etc.

I have also created on for managing Office 365 accounts in the cloud using the MSOL powershell extensions.  With a little imagination, you can make everyday tasks much simpler to perform.

Also, for those just starting out... Try to adopt a formatting technique for you code early on that is easy to read.  Sure your script will still function with sloppy formatting, but it make troubleshooting issues so much easier.  It also makes it easier for others who may be working on a version of your script to tell what you are trying to do!

Thanks for stopping by!

Disclaimer: All scripts and other powershell references on this blog are offered "as is" with no warranty.  While these scripts are tested and working in my environment, it is recommended that you test these scripts in a test environment before using in your production environment.

5 comments:

  1. Thanks for this writeup. I've looked around at several different powershell menu setups and this one seems the most straightforward, and makes the most sense to someone coming from a background writing batch scripts. I missed using "goto" but functions seem to work pretty much the same way.

    Question: Can you put your functions anywhere, or do they need to be defined at the beginning of the script?

    ReplyDelete
  2. Thanks for the script.
    You could replace the if else statements in the mainmenu function with the following switch statement:
    switch ($answer) {
    1 {write-host "selection 1"}
    2 {write-host "selection 2"}
    3 {areyousure}
    default {
    write-host -ForegroundColor red "Invalid Selection"
    sleep 1
    mainmenu
    }
    }
    Thanks

    ReplyDelete
  3. Can you help with modifying your script and menu if I want to give user 4 choices 3 items and a quit. So when the user selects 1 I want it to prompt and ask user for input of a computer name that it's going to pull information from a mac address for the sake of my script. I want to have a default value at the end which Is the domain information and the user will input just the first part of computer name and then return mac. I want option 2 to do the same but with an input of ip address is that possible

    ReplyDelete
  4. Thanks, this menu worked great for me. One annoyance though (it's silly). I hated that even with a valid selection it wrote Invalid Selection. I replaced the else with if ($answer -gt 3) {write-host -ForegroundColor red "Invalid Selection"}. It's not perfect, but I couldn't get -ne 1..3 to work either.

    ReplyDelete
  5. Hello:

    Why do you use "echo" of MS-DOS?

    Use only PowerShell to create menus.
    An example with this instruction:

    Write-Host Show texts on screen '

    Example of menu.
    function mostrarMenu
    {
    param (
    [string]$Titulo = 'Opciones del Menu'
    )
    cls
    Write-Host "================ $Titulo================"


    Write-Host "1) Primera Opción"
    Write-Host "2) Segunda Opción"
    Write-Host "3) Tercera Opción"
    Write-Host "S) Presiona 'S' para salir"
    }

    do
    {
    mostrarMenu
    $input = Read-Host "Elegir una Opción"
    switch ($input)
    {
    '1' {
    cls
    'Primera Opción'
    } '2' {
    cls
    'Segunda Opción'
    } '3' {
    cls
    'Tercera Opción'
    } 's' {
    return
    }
    }
    pause
    }
    until ($input -eq 's')

    Greetings.

    ReplyDelete