SimpleMenu.psm1
class SimpleMenu { [System.Collections.Generic.List[PSObject]]$Items [String]$Title [ConsoleColor]$TitleForeGround = [ConsoleColor]::Cyan SimpleMenu() { $This.Items = New-Object System.Collections.Generic.List[PSObject] } [PSObject]GetItem($id) { $out = ($this.Items | Where-Object {$_.ID -eq $ID} | Select -First 1) return $out } Print() { $TitleParams = @{} $TitleParams.Add('ForegroundColor', $this.TitleForeGround) Write-Host " $($this.Title)" @TitleParams $NumberIndex = 0 Foreach ($Item in $this.Items) { if (-not [String]::IsNullOrWhiteSpace($Item.Key)) { $item.runtimeKey = $item.Key } else { $NumberIndex++ $item.runtimeKey = $NumberIndex } Write-host "$($item.runtimeKey). $($Item.Title)" } } } enum WarningMessages{ Undefined None InvalidChoice NoActionDefined } function New-SimpleMenu($Title, $Items, [ConsoleColor]$TitleForegroundColor, $Id) { $Menu = New-Object -TypeName SimpleMenu $Menu.Title = $Title if ($PSBoundParameters.ContainsKey('TitleForegroundColor')) { $Menu.TitleForeGround = $TitleForegroundColor } $AllKeys = New-Object System.Collections.ArrayList Foreach ($Item in $Items) { if (-not [String]::IsNullOrWhiteSpace($item.Key)){ if ($AllKeys.Contains($Item.Key)) { Write-Error "The key $($item.key) is already assigned to another element of this menu and cannot be assigned to item $($item.Title)." } else { $AllKeys.Add($Item.Key) | Out-Null } } $Menu.Items.Add($Item) } return $Menu } function New-SimpleMenuItem { [cmdletbinding()] param( [Parameter(Position = 0, ValueFromPipeline = $true)] [ValidateNotNullorEmpty()] #No value [String]$Title, [System.ConsoleColor]$ForegroundColor, $Id, [ValidatePattern('^[a-zA-Z]$')]$Key = $null, [ScriptBlock]$Action = $null, [Switch]$Quit, [Switch]$NoPause, $Submenu ) Begin { $MenuItem = New-Object PSObject -Property @{ 'Title' = '' 'Id' = '' 'Key' = '' 'runtimeKey' = '' Action = '' IsExit = $false Submenu = $Null NoPause = $NoPause } $WriteHostParams = @{} if ($PSBoundParameters.ContainsKey('ForegroundColor')) { $WriteHostParams.add('ForegroundColor', $ForegroundColor) } $MenuItem.Id = $Id $MenuItem.Key = $Key $MenuItem.Action = $Action $MenuItem.IsExit = $Quit $MenuItem.Submenu = $Submenu } Process { if ($_ -eq $null) { $_ = $Title } $MenuItem.Title = $_ } End { return $MenuItem } } function Invoke-SimpleMenu { [cmdletbinding()] param( [SimpleMenu]$Menu ) $Debug = ($psboundparameters.debug.ispresent -eq $true) [WarningMessages]$InvalidChoice = [WarningMessages]::None while ($true) { if (-not $Debug ){Clear-Host} $Menu.Print() if (-not ($InvalidChoice -eq [WarningMessages]::None) ) { Switch($InvalidChoice) { ([WarningMessages]::NoActionDefined) { Write-Warning 'No actions have been defined for this menu item.'} ([WarningMessages]::InvalidChoice) { Write-Warning "'$Line' is not a valid choice" $IDs = ($menu.Items | Select-Object -ExpandProperty runtimeKey) -join ',' Write-Host "Valid choices are: $IDs" } } $InvalidChoice = [WarningMessages]::Undefined } if ([console]::IsInputRedirected) { $Line = Read-Host } else { [System.ConsoleKeyInfo]$LineRaw = [Console]::ReadKey($true) $Line = $LineRaw.KeyChar.ToString() } $Result = @($Menu.Items | Where runtimeKey -eq $Line ) if ($Result.Count -gt 0) { $ShouldNotPause = $Result.NoPause if ($InvalidChoice -eq [WarningMessages]::Undefined) { if (-not $Debug ){Clear-Host} $Menu.Print() $InvalidChoice = [WarningMessages]::None } if ($Result.Action -ne $null) { try { ($Result.Action).invoke() } catch { Write-Error $_ $ShouldNotPause = $false } if ($ShouldNotPause -eq $false) {Pause} } else { if (-not ($Result.IsExit) -and ($Result.Submenu -eq $null)) { $InvalidChoice = [WarningMessages]::NoActionDefined } } } else { $InvalidChoice = [WarningMessages]::InvalidChoice } if ($Result.Submenu -ne $Null) { Invoke-SimpleMenu $Result.Submenu -debug:$Debug } if ($Result.IsExit -eq $true) { return } } } |