Petri Newsletter Sign-up
Office 365 Insider

Here at, we get IT — and so can you. Subscribe today to stay informed and knowledgeable regarding the latest on IT.

    See All Petri Newsletters

    Building a PowerShell Console Menu Revisited, Part 2

    Posted on by Jeff Hicks in PowerShell


    In a previous article, I demonstrated how to create a text-based PowerShell menu. This is something you could wrap up in a script for a technician, end-user, or even yourself. But I wanted to do more, so let’s see how to use PowerShell tools to build new tools.

    We’ll start by initializing a counter variable.

    In my sample menu from last time, all of my entries were numbered. I’m too lazy to count, so I’ll let PowerShell do it. I’m also going to prompt for a menu title:

    Defining a menu title variable (Image Credit: Jeff Hicks)
    Defining a menu title variable (Image Credit: Jeff Hicks)

    For the sake of my demonstration, simply assign a value to $Title. At this point, I’m going to create a custom object. You’ll see why in a bit.

    Note that you can only use the [pscustomobject] type in PowerShell 3.0 and later. Now that I have two items to the menu, I think the process is easier if you enter them in the order you want them presented.

    To accomplish this, I’m going to use a do loop to prompt for a menu description and a corresponding PowerShell expression. Each time through the loop, the counter is incremented by one, and I create a nested custom object with the counter number, the menu item or description, and the action.

    The loop will continue as long as something is entered for Read-Host.

    Building a menu object (Image Credit: Jeff Hicks)
    Building a menu object (Image Credit: Jeff Hicks)

    The variable $MyMenu is now my menu object.

    My menu object (Image Credit: Jeff Hicks)
    My menu object (Image Credit: Jeff Hicks)

    As an alternative to being prompted, you could create a hashtable of menu items.

    My actions are all local, but you could invoke your own scripts or functions that could prompt for computer names or other specific information. For now, I just want to focus on the structure. In either event, I end up with a custom object that represents my menu. You’ll note that I didn’t include any options to quit, which you’ll see why in a moment. The reason I went through all of this effort is to save the results to an XML file.

    Now my menu definition is stored in a structured document. This makes it easier to create different menus, but use the same script to display them. To do that, I need to import the XML file.

    Next, I build a here string from the imported items.

    My imported menu (Image Credit: Jeff Hicks)
    My imported menu (Image Credit: Jeff Hicks)

    All that remains is to put some logic behind the menu and respond to Read-Host. I invoke the corresponding scriptblock using Invoke-Command. Although the XML format appears to store a scriptblock, it gets imported as a string so I have to take an extra step to turn it back into a scriptblock. I could have used Invoke-Expression, but that’s a bad security practice.

    The menu in action (Image Credit: Jeff Hicks)
    The menu in action (Image Credit: Jeff Hicks)

    You’ll see that I added logic to Quit separately. Here’s a more complete function for the entire process:

    With this, my script is actually quite simple:

    By separating the menu from the script, you have a bit more control. You can use a script to create the menu file, like this one to create an Active Directory related menu.

    Now, we’ll create a simple script to invoke it.

    My Active Directory console menu (Image Credit: Jeff Hicks)
    My Active Directory console menu (Image Credit: Jeff Hicks)

    If I need to modify this menu, I can manually modify the XML or revise the first script and rerun it. I don’t have to touch any script that uses it. I hope you’ll let me know what you think of this approach.


    Don't have a login but want to join the conversation? Sign up for a Petri Account