Instantly share code, notes, and snippets.
Last active
May 24, 2026 21:19
-
Star
0
(0)
You must be signed in to star a gist -
Fork
0
(0)
You must be signed in to fork a gist
-
-
Save xv/51ff8b49e96144b6e21ecd7c52a15225 to your computer and use it in GitHub Desktop.
Prompts an arrow-key navigable menu of selectable options. Compatible with Windows PowerShell 5.1.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # The very basic/barebones version | |
| function Show-Menu { | |
| param( | |
| [Parameter(Mandatory)] | |
| [string] $Title, | |
| [Parameter(Mandatory)] | |
| [string[]] $Options | |
| ) | |
| $selected = 0 | |
| $count = $Options.Count | |
| do { | |
| Clear-Host | |
| Write-Host $Title | |
| Write-Host | |
| foreach ($idx in 0..($count - 1)) { | |
| $option = $Options[$idx] | |
| if ($idx -eq $selected) { | |
| Write-Host "[ $option ]" -b Cyan -f Black | |
| } else { | |
| Write-Host " $option" | |
| } | |
| } | |
| Write-Host | |
| # https://learn.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes | |
| $key = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown").VirtualKeyCode | |
| switch ($key) { | |
| # VK_UP | |
| 0x26 { $selected = ($selected - 1 + $count) % $count } | |
| # VK_DOWN | |
| 0x28 { $selected = ($selected + 1) % $count } | |
| # VK_RETURN | |
| 0x0D { return $selected } | |
| } | |
| } while ($true) | |
| } | |
| # Usage | |
| # Returns the zero-based index of the selected option | |
| $menuResult = Show-Menu ` | |
| -Title "Select an action:" ` | |
| -Options @("Backup", "Restore", "Exit") | |
| Write-Host "You selected option $menuResult" |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # This version treats options as objects containing a Name, Description and an | |
| # Enabled/Disabled state. The function returns the selected object | |
| function Show-Menu { | |
| param( | |
| [Parameter(Mandatory)] | |
| [string] $Title, | |
| [Parameter(Mandatory)] | |
| [array] $Options | |
| ) | |
| $count = $Options.Count | |
| # Width of the Name column | |
| $nameWidth = ( | |
| ($Options | | |
| ForEach-Object { $_.Name.Length } | Measure-Object -Maximum | |
| ).Maximum | |
| ) + 2 | |
| # Total menu width | |
| $menuWidth = ($Options | | |
| ForEach-Object { | |
| if ([string]::IsNullOrWhiteSpace($_.Description)) { | |
| $_.Name.Length | |
| } else { | |
| ("{0,-$nameWidth} {1}" -f $_.Name, $_.Description).Length | |
| } | |
| } | Measure-Object -Maximum | |
| ).Maximum | |
| function Get-NextEnabledIndex { | |
| param( | |
| [int] $Start, | |
| [int] $Direction | |
| ) | |
| $idx = $Start | |
| do { | |
| $idx = ($idx + $Direction + $count) % $count | |
| } until ($Options[$idx].Enabled) | |
| return $idx | |
| } | |
| $selected = 0 | |
| # Start on first enabled item | |
| while (-not $Options[$selected].Enabled) { | |
| $selected++ | |
| } | |
| do { | |
| Clear-Host | |
| Write-Host $Title | |
| Write-Host | |
| foreach ($idx in 0..($count - 1)) { | |
| $option = $Options[$idx] | |
| if ([string]::IsNullOrWhiteSpace($option.Description)) { | |
| $line = $option.Name | |
| } else { | |
| $line = "{0,-$nameWidth} {1}" -f ` | |
| $option.Name, | |
| $option.Description | |
| } | |
| # Make all menu items have equal width | |
| $line = $line.PadRight($menuWidth) | |
| if (-not $option.Enabled) { | |
| Write-Host " $line" ` | |
| -ForegroundColor DarkGray | |
| } elseif ($idx -eq $selected) { | |
| Write-Host "[ $line ]" ` | |
| -BackgroundColor Cyan ` | |
| -ForegroundColor Black | |
| } else { | |
| Write-Host " $line" | |
| } | |
| } | |
| Write-Host | |
| # https://learn.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes | |
| $key = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown").VirtualKeyCode | |
| switch ($key) { | |
| # VK_UP | |
| 0x26 { $selected = Get-NextEnabledIndex $selected -1 } | |
| # VK_DOWN | |
| 0x28 { $selected = Get-NextEnabledIndex $selected 1 } | |
| # VK_RETURN | |
| 0x0D { return $Options[$selected] } | |
| } | |
| } while ($true) | |
| } | |
| # Usage | |
| # Returns the selected object from the $Options array | |
| $menuResult = Show-Menu ` | |
| -Title "Select an action:" ` | |
| -Options @( | |
| @{ | |
| Name = "Backup" | |
| Description = "Creates a backup of current configuration" | |
| Enabled = $true | |
| }, | |
| @{ | |
| Name = "Restore" | |
| Description = "Restores configuration from backup" | |
| Enabled = $false | |
| }, | |
| @{ | |
| Name = "Exit" | |
| Description = "Exits without making any changes" | |
| Enabled = $true | |
| } | |
| ) | |
| Write-Host "You selected option '$($menuResult.Name)'" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment