How to create interactive dynamic Menu in PowerShell


Why do we need an interactive Menu in the scripts at all, really is not enough that there are Parameters?
No, not enough, sometimes we want to give the user a choice at the script runtime, but not before it starts.


  • Present to you the function Write-Menu, which does all the «dirty» work. Namely, create within PowerShell console window, beautiful, editable, interactive, and most importantly, dynamic menus.

  • I have included this function in my PowerShell MS-Module module. You can take the whole module completely or just copy-paste only the function itself to any other module or script.

Beautiful Menu

Let’s in the order. What does it mean the beautiful ?

  • The function automatically numbers menu items and adds the right amount of leading zeros to the item number in case we have more than nine items or entries.



Editable Menu

What does it mean the editable?

  • This means that you control how your Menu will look like.

  • To control the appearance, you can use following parameters:

Parameter Description Default
-PropertyToShow Object property to show as menu entry Name
-Prompt User prompt Pick a choice
-Header Menu title (optional)
-Shift Number of TABs to shift menu entries 0
-TextColor Menu text color White
-HeaderColor Menu title color Yellow
-AddExit Add Exit entry False
  • All function’s parameters except -AddExit or its alias -Exit are positional and can be omitted. The -TextColor and -HeaderColor support Intellisense (Ctrl+Space or TAB completion).

Write-Menu -Menu (Get-Service) -PropertyToShow DisplayName -Prompt 'Select a service' -Header "$env:COMPUTERNAME Services" -Shift 1 -TextColor Green -HeaderColor Cyan
Write-Menu (Get-Service) DisplayName 'Select a service' "$env:COMPUTERNAME Services" 1 Green Cyan
Write-Menu (Get-Service) DisplayName 'Select a service' "$env:COMPUTERNAME Services" 1 Green Cyan -Exit

Interactive Menu

What does it mean the interactive?

  • The function asks you to select only the item number, and returns you the item itself. Moreover, the function will make sure that you have entered existing one.


Dynamic Menu

What does it mean the dynamic?

  • You do not need to know in advance how many items your Menu will have. This is especially useful when the menu items are objects, such as files/services/processes/user accounts/disks or even virtual machines.

  • All what you need to take care of is to pass to the function your menu items in the -Menu parameter, moreover it can be as regular words or sentences of [string[]] data type, as well as ANY OBJECTS!!!

Write-Menu -Menu (gci C:\Windows\)
Write-Menu -Menu (Get-Process)
Write-Menu -Menu (Get-Service)
Write-Menu -Menu (Get-VM)

-PropertyToShow parameter

  • In the case of objects by default the Name property is used. If your objects do not have Name property or you want to display in your Menu alternative property, use -PropertyToShow parameter.
Write-Menu -Menu (gci C:\Windows\) -PropertyToShow FullName
Write-Menu -Menu (Get-Process | ? {$_.MainWindowTitle}) -PropertyToShow MainWindowTitle
Write-Menu -Menu (Get-Process) -PropertyToShow Description
Write-Menu -Menu (Get-Service) -PropertyToShow DisplayName


  • If you specified a property that does not exist, the function will throw an error.
  • Objects for which a representation property is empty will be excluded from the menu.

What the Write-Menu returns?

  • It does not matter what property you choose to display your objects in the Menu, this is only representation. The objects itself do not change.
  • The Write-Menu will still return you the same object type, that you passed to the -Menu parameter.
Get-Process | Get-Member
TypeName: System.Diagnostics.Process

Write-Menu -Menu (Get-Process) | Get-Member
TypeName: System.Diagnostics.Process


  • Please note, no matter by which property the objects are represented in the Menu (in the above example, these properties are Name or FullName). When we select 99, the function returns us the same object (the file winhlp32.exe). Moreover, if the item number contains leading zero(s), you can, but must not specify it (in my case, 99 and 099 are the same).

Write-Menu and Get-Service

  • Let’s look at case study to make sure that the function really returns true and full-featured objects.
  • We will add to our menu a dynamic list of the local services. Why is the dynamic? Because you do not know in advance, how many these services would you get.

  • We choose the very first service from the Menu and save the result in a variable:

$svc = Write-Menu -Menu (Get-Service | ? {$_.DisplayName -match 'adobe'}) -Prompt 'Select any service'
  • Let’s use the Get-Member cmdlet to see what exactly is the $svc variable.
$svc | Get-Member
TypeName: System.ServiceProcess.ServiceController
  • This is the same type, returned by Get-Service cmdlet.
Get-Service | Get-Member
TypeName: System.ServiceProcess.ServiceController
  • And if so, then we can pass or pipe this variable to any cmdlets, that work with services, for example, Stop-Service or Start-Service.
$svc | Stop-Service
$svc | Start-Service


  • Now the same, but with no the intermediate variable:
Write-Menu -Menu (Get-Service | ? {$_.Status -eq 'stopped'}) -Prompt 'Select service to start' | Start-Service
Write-Menu -Menu (Get-Service | ? {$_.Status -eq 'started'}) -Prompt 'Select service to stop' | Stop-Service


Write-Menu and Get-ChildItem

  • Another example, let’s take the files instead of the services.

  • The Get-ChildItem cmdlet can return objects of type [System.IO.DirectoryInfo] or [System.IO.FileInfo], i.e. directories or files, if you are in FileSystem PSDrive.

Get-Alias -Definition Get-ChildItem
cd c:
gci | gm
  • The Remove-Item can destroy/delete these and many other types of objects. So, the following command will delete your selected item (file or folder).
Write-Menu -Menu (dir 'C:\temp\') | Remove-Item -Confirm:$true


Write-Menu and … any cmdlet

  • In general, the Write-Menu can be used with absolutely ANY OTHER cmdlet. Let see some examples with VMware PowerCLi.

  • Power on VM.

Connect-VIServer VC65 –wa SilentlyContinue
menu -Menu (Get-VM | ? {$_.PowerState -ne 'poweredon'}) -Prompt 'Select VM to start' | Start-VM -Confirm:$true
  • Select VMFS Datastore and get its Used%.
$ds = menu (Get-Datastore | ? {$_.Type -eq 'vmfs'} | sort Name) -Prompt 'Select VMFS datastore'
[pscustomobject]@{Datastore=$ds.Name; 'Used%'=[int](($ds.CapacityGB-$ds.FreeSpaceGB)/$ds.CapacityGB*100)} |fl
  • And last example Write-Menu within another Write-Menu. Select Cluster, then select ESXi host from that Cluster and then enter this host to Maintenance mode!!!
menu (Get-VMHost -Location (menu (Get-Cluster | sort Name) -Prompt 'Select Cluster' -Header 'Clusters:')  | sort Name) -Prompt 'Select ESXi host' -Header 'ESXi hosts:' | Set-VMHost -State Maintenance -Confirm:$true
  • Your imagination is the only limitation Emoj.


  • Despite its modest name, the Write-Menu function returns reference to a REAL object. Be careful passing or piping its output to the functions whose names begin with the Set- or Remove- verbs.

  • For more details about the function, please take a look at the content based help and examples.

Get-Alias –Definition Write-Menu
Get-Help Write-Menu -Full
Get-Help Write-Menu -Examples
Get-Help Write-Menu -Parameter PropertyToShow

You may also like:

New-PercentageBar – Create colored and adjustable Percentage Bar in the PowerShell
Start-SleepProgress – Put PowerShell scripts to sleep with Progress Bar

23 thoughts on “How to create interactive dynamic Menu in PowerShell

  1. This is great. I want to use this to allow my users to connect multiple vcenters. It works great with one but I’m not sure how to get it to work with multiple.


  2. If you hit enter instead of an option it errors out. Can you change it so that instead, it does the same thing as when an incorrect option is chosen?


      1. Here’s the error I get:
        Write-Menu : Exception calling “ContainsKey” with “1” argument(s): “Key cannot be null.
        Parameter name: key”
        At line:1 char:1
        + Write-Menu “One”,”Two”
        + ~~~~~~~~~~~~~~~~~~~~~~~
        + CategoryInfo : NotSpecified: (:) [Write-Menu], MethodInvocationException
        + FullyQualifiedErrorId : ArgumentNullException,Write-Menu

        I found that if I change
        ELSE {$Choice}
        If ($Choice -eq $Null) {“-“} Else {$Choice}

        Then it works


      2. Very strangely, I can’t reproduce your error. What do you load to your menu (what do you pass to the -List parameter)? Are there objects, strings or numbers?


      3. I run Write-Menu from your MS-Module using this:
        Write-Menu -List “One”,”Two”
        After some more research, it seems this error only happens in Visual Studio Code. Works fine in Powershell ISE.


  3. How would you change this function to allow a user to make multiple selections from the menu (say they want to choose more than one file)?


Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s