While it’s normally best practice to not display anything on the host and to batch as much as possible with PowerShell; sometimes you need a UI. Here’s a pair of functions to display a menu on the screen, automatically number the possible responses and only return when a valid choice is made.
What I want is a function that will take a question and some options as parameters and display them to the screen. The options should be automatically numbered which should be the only valid responses to the menu.
First, a fancy banner to display the question;
function Get-HeaderFormattedArray { param ( [string]$HeaderString="" ) $TitleBar = "" #Builds a line for use in a banner for ($i = 0; $i -lt ($HeaderString.Length) + 2; $i++) { $TitleBar += $TitleChar } Return @($TitleBar, "$TitleChar$HeaderString$TitleChar", $TitleBar, "") }This returns an array of 3 lines of text; the passed string ($HeaderString) with a line before and after it. You’ll need to define $TitleChar as whatever you want the lines to be made out of.
And now the actual menu function;
<# .SYNOPSIS Writes a menu to the screen and gets a valid selection. .DESCRIPTION Writes a menu to the screen and gets a valid selection. It generates the number next to the menu item automatically and checks the input is one of the numbers used. .PARAMETER Banner The title of the menu .PARAMETER DisplayOptions An array of options to display .PARAMETER ClearScreen If this switch is specified the host is cleared whenever the menu is redisplayed .NOTES Name : Get-MenuAnswer Author : Neil Riches V1.62 Initial Version #> function Get-MenuAnswer { param ( [string]$Banner="", [string[]]$DisplayOptions=@(), [switch]$ClearScreen=$False ) If ($DisplayOptions.Count -gt 0) { $ValidSelection=$False do { if($ClearScreen) { Clear-Host } $FormattedBanner=Get-HeaderFormattedArray -HeaderString $Banner Write-Host $FormattedBanner | Write-Host Write-Host $OptionCount=0 ForEach($Option in $DisplayOptions) { $OptionCount+=1 Write-Host "$OptionCount) $Option" } Write-Host $Answer=Read-Host -Prompt "Enter an option " $IntAnswer=$Answer -as [int32] if ($IntAnswer -ne $Null) { if (($IntAnswer -gt 0) -and ($IntAnswer -le $OptionCount)) { $ValidSelection=$True } } }Until ($ValidSelection) return $Answer } }The function takes the $Banner string you want to display, an array of $DisplayOptions and whether you want the screen to be cleared.
In action, it looks like;
The function will keep looping until one of the numbered options is chosen and then return the result.
Some important parts of the function;
If ($DisplayOptions.Count -gt 0)This makes sure there are some options to choose!
$FormattedBanner=Get-HeaderFormattedArray -HeaderString $BannerThis gets a banner from the previous function.
ForEach($Option in $DisplayOptions) { $OptionCount+=1 Write-Host "$OptionCount) $Option" }Loops through the $DisplayOptions and writes a number next to each.
$IntAnswer=$Answer -as [int32] if ($IntAnswer -ne $Null) { if (($IntAnswer -gt 0) -and ($IntAnswer -le $OptionCount))This tries to convert the written choice (a String) into a number. If it’s possible the code next checks that the number picked is between 1 and the number of $DisplayOptions.
Until ($ValidSelection) return $AnswerFinally this keeps generating the menu until a valid selection has been picked!
You have a typo in your code. In the function Get-HeaderFormattedArray.
$TitleBar = “” should be $TitleChar = “”
Hi. No. $TitleChar is a global variable you’ll have defined somewhere else. It’s used to create the bar in the menu (using “*” you’d get a banner line of “******************************”).
You could define it in the function as well though if you wanted;
$TitleBar = “”
$TitleChar = “-”