Using a directory array for a choice menu inside a function

By | 2016-04-02

Usage of [System.Management.Automation.Host.ChoiceDescription[]] and $host.ui.PromptForChoice() with an array of data for choices.
Default behavior when using functions is that the return value is every output, so when you want to return a value, using Write-Host inside the function will mess the return value up.
The scenario is I wanted the user to provide a name, which should match a directory with configuration, when the name is not provided I want to provide all directories as options.

To provide a simple and familiar choice menu, I use the PromptForChoice function. A choice is defined in this way: New-Object System.Management.Automation.Host.ChoiceDescription "&No", "Do not carry out this action". All choices must be declared with an array inside [System.Management.Automation.Host.ChoiceDescription[]].

First I determine my script directory in this way:
$InstallerLiteralPath = ([System.IO.Path]::GetDirectoryName($myInvocation.MyCommand.Definition))
This works both for local and network UNC paths.

Next I determine the subdirectories, we need this as an array because we need the count attribute, so enclose it with @(…):
$ApplicationDirs = @(Get-ChildItem "$InstallerLiteralPath\configuration" | ?{ $_.PSIsContainer } | Select-Object Name)

Considering I want the choices to be subdirectories of a predefined directory, this proved to be a little bit tougher.
The PromptForChoice function is build up of a Title, Description, the choices, and the default choice.
We need a Cancel option also, which we want to be the default choice, so the choice array needs a cancel option and the default choice needs to be the number of directories, because the default choice count starts at zero and the cancel option is an extra choice.

Set up the Title and Description:
$caption = "Application Selection"
$message = "$($message)The following application configuration directories were found.rnWhich application would you like to configure/install?"

Set up the choices with the directory name as choice option for each directory plus the Cancel option:
$choices = [System.Management.Automation.Host.ChoiceDescription[]]@(($ApplicationDirs | %{$_.Name});"&Cancel")

Set up the default choice:
[int]$defaultChoice = $ApplicationDirs.Count

Display the Choice Menu with the variables defined above, $choiceRTN is the returned choice number the user has entered:
$choiceRTN = $host.ui.PromptForChoice($caption,$message, $choices,$defaultChoice)

Exit with a throw when the default choice (cancel) is chosen.
If ($choiceRTN -eq $defaultChoice){
Throw "[$($myInvocation.MyCommand)] : Application selection cancelled by user."
}

The directoryname of the chosen folder can be determined by the choice number in the array of directories:
$SelectedApplicationFolder = $ApplicationDirs[$choiceRTN].Name

The whole function would look like this:

 

Leave a Reply

Your email address will not be published. Required fields are marked *