# encoding: ascii # api: powershell # title: Show-ConsoleMenu # description: Shows a vertical “menu” in the console and allows you to pick numeric items from it. # version: 0.1 # type: function # author: Joel Bennett # license: CC0 # function: Show-ConsoleMenu # x-poshcode-id: 2900 # x-archived: 2015-04-24T02:03:08 # x-published: 2012-08-06T13:42:00 # # function Show-ConsoleMenu { #.Synopsis # Displays a menu in the console and returns the selection #.Description # Displays a numbered list in the console, accepts a typed number from the user, and returns it. #.Example # ls | Show-ConsoleMenu -Title "Please pick a file to delete:" -Passthru | rm -whatif # # Description # ----------- # Creates a menu showing a line for every file, and outputs the selected file. #.Example # if(Test-Path $Profile) { # switch(Show-ConsoleMenu "Profile exists:" "Delete it!","Rename it with 01","Abort" -Debug) { # 0 { rm $Profile -whatif } # 1 { mv $Profile [IO.Path]::ChangeExtension($Profile,"01.ps1") } # 2 { return } # } # } # # Description # ----------- # Shows how to use the return value without the Passthru switch. # This example would check if you have a profile, and if you do, would offer you the choice of removing or renaming it. param( # The items to be chosen from [Parameter(ValueFromPipeline=$true,Position=2)] [Alias("InputObject")] [PSObject[]]$Choices, # A caption to display before the choices [Parameter(Position=1)] [Alias("Title")] [string]$Caption, # A scriptblock expression for formatting the Choices. [Parameter(Position=3)] [ScriptBlock]$Expression=({$_}), # A prompt to display after the choices [Alias("Footer")] [string]$Prompt, # How much to indent the "center" of the selection menu (Defaults to 8) [int]$indentLeft=8, # If set, Show-ConsoleMenu returns the selected value from $choices, otherwise it returns the index (which is usually easier to use in a switch statement) [Switch]$Passthru, # If set, this function works with my New-BufferBox script by using Out-Buffer ( http://poshcode.org/2899 ) [Switch]$UseBufferBox, # If set, allows multiple selection (Press Enter to stop selecting more) [Switch]$MultiSelect ) begin { $allchoices = New-Object System.Collections.Generic.List[PSObject] } process { if($choices) { $allchoices.AddRange($choices) } } end { $Format = "{0:D1}"; $Digits = 1 if($allchoices.Count -gt 10) { $Digits = $allchoices.Count.ToString().Length $Format = "{0:D${Digits}}" } # Make a hashtable with keys for($i=0; $i -lt $allchoices.Count; $i++) { $allchoices[$i] = Add-Member -Input $allchoices[$i] -Type NoteProperty -Name ConsoleMenuKey -Value $($format -f $i) -Passthru } Write-Debug "There are $($allChoices.Count) choices, so we'll use $Digits digits" # output the menu to the screen $menu = $allchoices | Format-Table -HideTableHeader @{E="ConsoleMenuKey";A="Right";W=$indentLeft}, @{E=$Expression;A="Left"} -Force | Out-String $menu = $menu.TrimEnd() + "`n" if($UseBufferBox) { Out-Buffer ("`n" + (" " * ($indentLeft/2)) + $Caption + "`n") -ForegroundColor $Host.PrivateData.VerboseForegroundColor -BackgroundColor $Host.PrivateData.VerboseBackgroundColor Out-Buffer $menu } else { Write-Host ("`n" + (" " * ($indentLeft/2)) + $Caption + "`n") -ForegroundColor $Host.PrivateData.VerboseForegroundColor -BackgroundColor $Host.PrivateData.VerboseBackgroundColor Write-Host $menu } do { if($Prompt) { if($UseBufferBox) { Out-Buffer $Prompt -ForegroundColor $Host.PrivateData.VerboseForegroundColor -BackgroundColor $Host.PrivateData.VerboseBackgroundColor } else { Write-Host $Prompt -ForegroundColor $Host.PrivateData.VerboseForegroundColor -BackgroundColor $Host.PrivateData.VerboseBackgroundColor } } # get a choice from the user [string]$PreviousKeys="" do { $Key = $Host.UI.RawUI.ReadKey("IncludeKeyDown,NoEcho").Character try { [int][string]$choice = "${PreviousKeys}${Key}" $PreviousKeys = "${PreviousKeys}${Key}" } catch { ## The "?" causes us to re-show the menu. Useful for long multi-selects, which might scroll off. if(63 -eq [int][char]$Key) { if($UseBufferBox) { Out-Buffer $menu } else { Write-Host $menu } } elseif(13,27,0 -notcontains [int][char]$Key) { $warning = "You must type only numeric characters (hit Esc to exit)" if($UseBufferBox) { Out-Buffer $warning -ForegroundColor $Host.PrivateData.WarningForegroundColor -BackgroundColor $Host.PrivateData.WarningBackgroundColor } else { Write-Warning $warning } } } } while( $PreviousKeys.Length -lt $Digits -and (13,27 -notcontains [int][char]$Key)) if($PreviousKeys.Length -and $allchoices.Count -gt ([int]$PreviousKeys)) { if($Passthru) { $allchoices[([int]$PreviousKeys)] } else { $choice } } } while($key -ne [char]13 -and $MultiSelect) }}