Write-ShellMenu.psm1
function Write-ShellMenu { <# .SYNOPSIS Writes an arrow-key driven menu to the console. .DESCRIPTION Writes an arrow-key driven, Command-Line Interface style Menu to the Console. Includes options for configuring Menu style and formatting. .PARAMETER MenuHeader Specifies a header to be displayed above the Menu Title and body. Intended primarily for branding purposes when Write-ShellMenu is used within the context of a Module or Script Application. Takes objects as input. .PARAMETER MenuTitle Specifies a text string to display above the Menu body, acting as a title, or short descriptor. .PARAMETER MenuItems Specifies an array of items to display as options. .PARAMETER FocusHighlightingStyle Specifies the Highlighting Style used for Menu Items when they are in focus. Valid Styles: HighlightForeground, HighlightBackground, NoHighlighting .PARAMETER FocusHighlightingColor Specifies the Highlighting Color used for Menu Items when they are in focus. Uses ANSI Escape Sequence Color Codes. Valid Colors: 0-255 .PARAMETER FocusBorderStyle Specifies the type of Border characters to use as an additional visual cue for Menu Items when in focus. Border characters enclose the in-focus item on either side. Valid Border Styles: Brackets, CurlyBraces, Parentheses, Lines, NoFocusBorder .PARAMETER FocusPrefixStyle Specifies how the Focus Prefix Character should be displayed. Valid Prefix Styles: PrefixOnly, EnclosedPrefix, NoPrefix .PARAMETER FocusPrefix Specifies the Focus Prefix Character used. Default = ❯ .EXAMPLE PS> Write-ShellMenu -MenuTitle 'Demo Menu' -MenuItems 'Option One', 'Option Two', 'Option Three', 'Exit' -FocusHighlightingStyle HighlightBackground -FocusHighlightingColor '122' -FocusBorderStyle 'Lines' -FocusPrefixStyle PrefixOnly -FocusPrefix '>' .NOTES #> [CmdletBinding()] param( [Parameter()] [object]$MenuHeader = $null, [Parameter()] [string]$MenuTitle = $null, [Parameter(Mandatory)] [array]$MenuItems, [Parameter()] [ValidateSet("HighlightForeground","HighlightBackground","NoHighlighting")] [string]$FocusHighlightingStyle = "HighlightForeground", [Parameter()] [string]$FocusHighlightingColor = '228', [Parameter()] [ValidateSet("Brackets","CurlyBraces","Parentheses","Lines","NoFocusBorder")] [string]$FocusBorderStyle = "Brackets", [Parameter()] [ValidateSet("PrefixOnly","EnclosedPrefix","NoPrefix")] [string]$FocusPrefixStyle = "EnclosedPrefix", [Parameter()] [string]$FocusPrefix = "❯" ) Begin{ #region Menu Style Settings and Setup Clear-Host [System.Console]::CursorVisible = $false $HighlightReset = "`e[0m" if ($FocusHighlightingStyle -eq "HighlightForeground") { $HighlightStyle = "`e[38;5;" + $FocusHighlightingColor + "m" } elseif ($FocusHighlightingStyle -eq "HighlightBackground") { $HighlightStyle = "`e[38;5;" + $FocusHighlightingColor + "m" + "`e[7m" } else { $HighlightStyle = '' } $PrefixHighlightStyle = "`e[38;5;" + $FocusHighlightingColor + "m" if ($FocusBorderStyle -eq "Brackets") { $LBorder = "[" $RBorder = "]" } elseif ($FocusBorderStyle -eq "CurlyBraces") { $LBorder = "{" $RBorder = "}" } elseif ($FocusBorderStyle -eq "Parentheses") { $LBorder = "(" $RBorder = ")" } elseif ($FocusBorderStyle -eq "Lines") { $LBorder = "|" $RBorder = "|" } elseif ($FocusBorderStyle -eq "NoFocusBorder") { $LBorder = '' $RBorder = '' } if ($FocusPrefixStyle -eq "PrefixOnly") { $InFocusPrefix = $PrefxHighlightStyle + $FocusPrefix + $HighlightReset $OutOfFocusPrefix = "_" } elseif ($FocusPrefixStyle -eq "EnclosedPrefix") { $InFocusPrefix = "[" + $PrefixHighlightStyle + $FocusPrefix + $HighlightReset + "]" $OutOfFocusPrefix = "[_]" } else { $InFocusPrefix = '' $OutOfFocusPrefix = '' } #endregion #region Display Header/Title if applicable if ($MenuHeader -ne $null) { Write-Output $MenuHeader Write-Output '' } if ($MenuTitle -ne $null) { Write-Output $MenuTitle } $SelectedIndex = 0 #endregion } Process{ #region Display Menu Body While ($True) { for ($i = 0; $i -lt $MenuItems.Length; $i++) { $InFocusItem = $HighlightStyle + $LBorder + $MenuItems[$i] + $RBorder + $HighlightReset $OutOfFocusItem = $MenuItems[$i] if ($i -eq $SelectedIndex) { Write-Host "$InFocusPrefix" -NoNewline Write-Host " " -NoNewline Write-Host "$InFocusItem" } else { Write-Host "$OutOfFocusPrefix" -NoNewline Write-Host " " -NoNewline Write-Host "$OutOfFocusItem" } } #endregion #region Read Keyboard Input via Host.UI.RawUI.ReadKey $VKey = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown") Switch($VKey.VirtualKeyCode) { 38{ # Key: UP Arrow $SelectedIndex = ($SelectedIndex - 1 + $MenuItems.Length) % $MenuItems.Length } 40{ # Key: DOWN Arrow $SelectedIndex = ($SelectedIndex + 1) % $MenuItems.Length } 13{ # Key: ENTER return $SelectedIndex } } #endregion #region Re-Draw Menu Clear-Host if ($MenuHeader -ne $null) { Write-Output $MenuHeader Write-Output '' } if ($MenuTitle -ne $null) { Write-Output $MenuTitle } #endregion } } } |