CliMenu.psm1
function Add-MenuItem { <# .Synopsis Add a Menu Item to a menu. .DESCRIPTION Add a Menu Item to a menu. This cmdlet support input (Menu Items) from the pipeline. .EXAMPLE C:> $items = Get-MenuItem -MenuName main C:> $items | Add-MenuItem -Menu subMenu This will copy Menu Items from the main Menu and add them to the Menu subMenu. .EXAMPLE C:> $newMenuItem = @{ Name = "UnlockUser" DisplayName = "Unlock a user" Action = { Show-Command -Name Unlock-UserObject } DisableConfirm = $true } C:> $item = New-MenuItem @newMenuItem C:> $item | Add-MenuItem -Menu main This will create a new Menu Item and add it to the main Menu using the pipeline. .EXAMPLE C:> $newMenuItem = @{ Name = "UnlockUser" DisplayName = "Unlock a user" Action = { Show-Command -Name Unlock-UserObject } DisableConfirm = $true } C:> $item = New-MenuItem @newMenuItem C:> Add-MenuItem -Menu main -MenuItem $item This will create a new Menu Item and add it to the main Menu. .NOTES NAME: Add-MenuItem AUTHOR: Tore Groneng tore@firstpoint.no @toregroneng tore.groneng@gmail.com LASTEDIT: Aug 2016 KEYWORDS: General scripting Controller Menu #> [cmdletbinding()] Param ( [Parameter(Mandatory)] [string] $Menu , [Parameter(Mandatory, ValueFromPipeline)] [PSCustomObject] $MenuItem ) BEGIN { $f = $MyInvocation.InvocationName Write-Verbose -Message "$f - START" } PROCESS { Write-Verbose "getting menu" $menuObject = Get-Menu -Name "$Menu" if ($menuObject) { write-verbose "found menu" foreach ($Item in $menuObject.MenuItems) { if ($Item.Name -eq $MenuItem.Name) { Write-Error -Message "$f - Duplicate MenuItem name detected in menu [$($menuObject.Name)]" break } } $menuIndex = $script:Menus.IndexOf($menuObject) write-verbose "menuindex [$menuIndex]" if ($menuIndex -ge 0) { $null = $script:Menus[$menuIndex].MenuItems.Add($MenuItem) } } else { Write-Verbose "no menuobject" } } END { Write-Verbose -Message "$f - END" } } $script:Menus = New-Object -TypeName System.Collections.ArrayList $script:MenuOptions = [pscustomobject]@{ MenuFillChar = "*" MenuFillColor = [consolecolor]::White Heading = "" HeadingColor = [consolecolor]::White SubHeading = "" SubHeadingColor = [consolecolor]::White FooterText = "" FooterTextColor = [consolecolor]::White MenuItemColor = [consolecolor]::White MenuNameColor = [consolecolor]::White MaxWith = 80 } function Get-Menu { <# .Synopsis Get a list of menus .DESCRIPTION Returns a list of menus by name, id or just the main menu .EXAMPLE C:> Get-Menu Returns all menus .EXAMPLE C:> Get-Menu -MainMenu Returns the Main Menu only .EXAMPLE C:> Get-Menu -MenuID 1 Returns the menu of the specified index .EXAMPLE C:> Get-Menu -Name main* Returns all the menus which has a name that starts with main .NOTES NAME: Get-Menu AUTHOR: Tore Groneng tore@firstpoint.no @toregroneng tore.groneng@gmail.com LASTEDIT: Aug 2016 KEYWORDS: General scripting Controller Menu #> [cmdletbinding(DefaultParameterSetName='none')] [OutputType([PSCustomObject])] Param ( [Parameter(ParameterSetName="MainMenu")] [switch] $MainMenu , [Parameter(ParameterSetName='ByID')] [int] $MenuID , [Parameter(ParameterSetName="ByName")] [string] $Name ) BEGIN { $f = $MyInvocation.InvocationName Write-Verbose -Message "$f - START" } PROCESS { if ($PSBoundParameters.ContainsKey("MainMenu")) { $script:Menus.Where({$_.IsMainMenu -eq $true}) } if ($PSBoundParameters.ContainsKey("MenuID")) { $script:Menus[$MenuID] } if ($PSBoundParameters.ContainsKey("Name")) { $script:Menus.Where({$_.Name -like "$Name"}) } if($PSCmdLet.ParameterSetName -eq "none") { $script:Menus } } END { Write-Verbose -Message "$f - END" } } function Get-MenuItem { <# .Synopsis Get a list of menu-items .DESCRIPTION Returns a list of menus by Menu-name, Menu-ID or the menu object .EXAMPLE C:> Get-MenuItem Returns all menu-items for all menus .EXAMPLE C:> Get-MenuItem -MenuName MainMenu Returns the menu-items for the menu with name MainMenu .EXAMPLE C:> Get-MenuItem -MenuId 1 Returns the menu-items for the menu with id 1 .EXAMPLE C:> $Menu = Get-Menu -Name SubMenuSkype C:> Get-MenuItem -MenuObject $Menu Returns all the menu-items for the menu with name SubMenuSkype .EXAMPLE C:> Get-Menu -Name SubMenuSkype | Get-MenuItem Returns all the menu-items for the menu with name SubMenuSkype .NOTES NAME: Get-MenuItem AUTHOR: Tore Groneng tore@firstpoint.no @toregroneng tore.groneng@gmail.com LASTEDIT: Aug 2016 KEYWORDS: General scripting Controller Menu #> [cmdletbinding(DefaultParameterSetName='none')] [OutputType([PSCustomObject])] Param ( [Parameter(ParameterSetName="ByName")] [string[]] $MenuName , [Parameter(ParameterSetName="ById")] [int] $MenuId , [Parameter(ValueFromPipeline, ParameterSetName="ByObject")] [PSCustomObject] $MenuObject ) BEGIN { $f = $MyInvocation.InvocationName Write-Verbose -Message "$f - START" } PROCESS { if ($PSCmdlet.ParameterSetName -eq "none") { $script:Menus.MenuItems } if ($PSBoundParameters.ContainsKey("MenuName")) { write-verbose -message "$f - Getting by MenuName" $script:Menus.Where({$_.Name -eq "$MenuName"}) | Select-Object -ExpandProperty MenuItems } if ($PSBoundParameters.Containskey("MenuId")) { $script:Menus[$MenuId].MenuItems } if ($PSCmdlet.ParameterSetName -eq "ByObject") { $MenuObject.MenuItems } } END { Write-Verbose -Message "$f - END" } } function Get-MenuOption { <# .Synopsis Get a list menu options .DESCRIPTION Returns a PSCustomObject with all menu options. This CmdLet has no parameters .EXAMPLE C:> Get-MenuOption Returns all menu-items for all menus .NOTES NAME: Get-MenuItem AUTHOR: Tore Groneng tore@firstpoint.no @toregroneng tore.groneng@gmail.com LASTEDIT: Aug 2016 KEYWORDS: General scripting Controller Menu #> [cmdletbinding()] [OutputType([PSCustomObject])] Param () $script:MenuOptions } function New-Menu { <# .Synopsis Create a new Menu .DESCRIPTION You can create as many menus you like, however you may only have one main Menu. The Menu must have a name, hence the Name parameter is Mandatory. The first Menu you create will become the main Menu even if you do not specify the IsMainMenu switch. .PARAMETER Name Normally you would like to specify a name without space and Camel-case the name. .EXAMPLE C:> New-Menu -Name "MainMenu" This will create a new Menu with name MainMenu. If this is the first Menu, it will be created as a main Menu .EXAMPLE C:> New-Menu -Name "MainMenu" -IsMainMenu This will create a new Menu with name MainMenu and set is as a main Menu .EXAMPLE C:> New-Menu -Name "sub1" -DisplayName "Sub-Menu for Skype" This will create a new Menu with name sub1 and DisplayName Sub-Menu for Skype .NOTES NAME: New-Menu AUTHOR: Tore Groneng tore@firstpoint.no @toregroneng tore.groneng@gmail.com LASTEDIT: Aug 2016 KEYWORDS: General scripting Controller Menu #> [cmdletbinding()] [OutputType([PSCustomObject])] Param ( [Parameter(Mandatory)] [string] $Name , [string] $DisplayName , [switch] $IsMainMenu ) BEGIN { $f = $MyInvocation.InvocationName Write-Verbose -Message "$f - START" } PROCESS { $newMenu = [PSCustomObject]@{ Name = "$Name" DisplayName = "$DisplayName" IsMainMenu = $IsMainMenu MenuItems = New-Object -TypeName System.Collections.ArrayList } $currentMainMenu = Get-Menu -MainMenu if ($PSBoundParameters.ContainsKey("IsMainMenu")) { if ($currentMainMenu) { Write-Error -Message "$f - You can only have one Main Menu. Currently [$($currentMainMenu.Name)] is your main menu" break } } if (-not $currentMainMenu) { $newMenu.IsMainMenu = $true } write-Verbose -Message "Creating menu [$Name]" $null = $script:Menus.Add($newMenu) $newMenu } END { } } function New-MenuItem { <# .Synopsis Create a new Menu-Item for a Menu. .DESCRIPTION Menu-Items are the action elements of the Menu. You add Menu-Items to a Menu. .EXAMPLE C:> New-MenuItem -Name "PasswordReset" -DisplayName "Reset a user password" -Action { Set-UserPassword } This will create a new Menu-Item. Since no MenuId is specified, it return the new object to the console. The switch parameter DisableConfirm is not specified and the user will have to confirm the invokation after it has been selected. .EXAMPLE C:> $menu = Get-Menu -Name sub1 C:> $newMenuItem = @{ Name = "UnlockUser" DisplayName = "Unlock a user" Action = { Unlock-UserObject } DisableConfirm = $true } C:> $menu | New-MenuItem @newMenuItem This will create a new Menu-Item for the menu named sub1. The Menu-object is piped into the New-MenuItem cmdlet. It will invoke a custom cmdlet Unlock-UserObject and it will not confirm with the user before invokation. .EXAMPLE C:> $newMenuItem = @{ Name = "UnlockUser" DisplayName = "Unlock a user" Action = { Unlock-UserObject } DisableConfirm = $true } C:> New-Menu -Name "sub1" -DisplayName "Sub-Menu for Skype" | New-MenuItem @newMenuItem This will create a new Sub-Menu and add the UnlockUser Menu-Item to it using the pipeline. It will invoke a custom cmdlet Unlock-UserObject and it will not confirm with the user before invokation. .EXAMPLE C:> $newMenuItem = @{ Name = "UnlockUser" DisplayName = "Unlock a user" Action = { Show-Command -Name Unlock-UserObject } DisableConfirm = $true } C:> New-Menu -Name "sub1" -DisplayName "Sub-Menu for Skype" | New-MenuItem @newMenuItem This will create a new Sub-Menu and add the UnlockUser Menu-Item to it using the pipeline. It will invoke the Show-Command cmdlet which will show a windows form with the parameters of the custom cmdlet Unlock-UserObject. It will not confirm with the user before invokation. The user may cancel the windows form without executing the cmdlet. .EXAMPLE C:> $mainMenu = New-Menu -Name Main -DisplayName "Main Menu" -IsMainMenu C:> $newMenuItem = @{ Name = "UnlockUser" DisplayName = "Unlock a user" Action = { Show-Command -Name Unlock-UserObject } DisableConfirm = $true } C:> $item = New-MenuItem $newMenuItem C:> $item | Add-MenuItem -Menu Main This will create a new Sub-Menu and add the UnlockUser Menu-Item to it using the pipeline. .NOTES NAME: New-MenuItem AUTHOR: Tore Groneng tore@firstpoint.no @toregroneng tore.groneng@gmail.com LASTEDIT: Aug 2016 KEYWORDS: General scripting Controller Menu #> [cmdletbinding(DefaultParameterSetName="none")] [OutputType([PSCustomObject])] Param ( [string] $Name , [string] $DisplayName , [string] $Description , [scriptblock] $Action , [switch] $DisableConfirm , [Parameter(ParameterSetName="ByName")] [string] $MenuName , [Parameter(ValueFromPipeline, ParameterSetName="ByObject")] [PSCustomObject] $MenuObject ) BEGIN { $f = $MyInvocation.InvocationName Write-Verbose -Message "$f - START" } PROCESS { $menuItem = [PSCustomObject]@{ Name = "$Name" DisplayName = "$DisplayName" Description = "$Description" Action = $Action ConfirmBeforeInvoke = -not $DisableConfirm } if ($PSBoundParameters.ContainsKey("MenuName")) { $MenuObject = Get-Menu -Name $MenuName } else { #$menu = Get-Menu -MainMenu } foreach ($Item in $menu.MenuItems) { if ($Item.Name -eq "$Name") { Write-Error -Message "$f - Duplicate MenuItem name detected in menu [$($menu.Name)]" break } } if ($PSBoundParameters.ContainsKey("MenuObject") -or $MenuObject) { $menuIndex = $script:Menus.IndexOf($MenuObject) $null = $script:Menus[$menuIndex].MenuItems.Add($menuItem) } # #if ($menuIndex -eq -1) #{ # throw "$f - Error, unable to find menu" #} # $menuItem } END { Write-Verbose -Message "$f - END" } } function Set-MenuOption { [cmdletbinding()] Param ( [string] $MenuFillChar = "*" , [ConsoleColor] $MenuFillColor = [consolecolor]::white , [string] $Heading = "[Heading not set]" , [ConsoleColor] $HeadingColor = [consolecolor]::white , [string] $SubHeading = "[SubHeading not set]" , [ConsoleColor] $SubHeadingColor = [consolecolor]::white , [string] $FooterText , [ConsoleColor] $FooterTextColor = [consolecolor]::white , [consolecolor] $MenuItemColor = [consolecolor]::white , [consolecolor] $MenuNameColor = [consolecolor]::white , [int] $MaxWith = 80 ) BEGIN { $f = $MyInvocation.InvocationName Write-Verbose -Message "$f - START" foreach ($key in $PSBoundParameters.Keys) { Write-Verbose -Message "$f - Setting [$key] to value $($PSBoundParameters.$key)" $script:MenuOptions.$key = $PSBoundParameters.$key } if ([string]::IsNullOrEmpty($script:MenuOptions.FooterText)) { $script:MenuOptions.FooterText = "$(Get-date) - Running as $([System.Security.Principal.WindowsIdentity]::GetCurrent().Name)" } } END { Write-Verbose -Message "$f - END" } } function Show-Menu { <# .Synopsis Show a Menu. .DESCRIPTION If executed without parameters, it will build and show the main Menu. If the MenuID parameter is specified, it will show the menu with that ID. You may also use the cmdlet to invoke a specific Menu-Item on a specific menu. .EXAMPLE C:> Show-Menu This will show the main Menu if defined. .EXAMPLE C:> Show-Menu -MenuId 1 This will show the menu at index 1. Use Get-Menu to find the index (zero-based array) .EXAMPLE C:> Show-Menu -InvokeItem 2 -MenuId 0 This will invoke the Menu-Item at index 2 on the form at index 0. If the Menu-Item requires confirmation before invoking it, the user will be prompted before invokation. .EXAMPLE C:> Show-Menu -InvokeItem 2 -MenuId 0 -force This will invoke the Menu-Item at index 2 on the form at index 0. If the Menu-Item requires confirmation before invoking it, the user will not be prompted before invokation since the force flag has been specified. .NOTES NAME: Show-Menu AUTHOR: Tore Groneng tore@firstpoint.no @toregroneng tore.groneng@gmail.com LASTEDIT: Aug 2016 KEYWORDS: General scripting Controller Menu #> [cmdletbinding()] Param ( [int] $InvokeItem , [switch] $Force , [string] $MenuName ) BEGIN { $f = $MyInvocation.InvocationName Write-Verbose -Message "$f - START" $mainMenu = Get-Menu -MainMenu if (-not $mainMenu) { Write-Warning -Message "Please add a menu first using the New-Menu cmdlet" break } } PROCESS { if ($PSBoundParameters.ContainsKey("InvokeItem")) { $menuSelected = (Get-Menu -Name $MenuName).MenuItems[$InvokeItem] #$script:Menus[$MenuID].MenuItems[$InvokeItem] if($menuSelected) { if ($menuSelected.ConfirmBeforeInvoke) { if (-not $Force) { $Continue = Read-Host -Prompt "Are you sure you want to execute [$($menuSelected.Name)] Y/N?" If ($Continue -ne "y") { Write-Host -Object "Execution aborted" -ForegroundColor DarkYellow break } } } if ($menuSelected.Action) { Write-Host -Object "Invoking [$($menuSelected.Name)]" -ForegroundColor DarkYellow $menuSelected.Action.Invoke() Write-Host -Object "Invoke DONE!" -ForegroundColor DarkYellow break } } } } END { $menuLines = New-Object -TypeName System.Collections.ArrayList $maxWith = $script:MenuOptions.MaxWith function Get-MenuLine { Param ( [string] $Text , [consolecolor] $Color = [System.ConsoleColor]::White , [bool] $IsMenuItem = $false ) if ($IsMenuItem) { $textLine = " " + "$Text" $textLine += " " * (($maxWith - 1) - $textLine.length - 1) } else { $maxWith = $script:MenuOptions.MaxWith $textLength = $Text.Length $textBlanks = (($maxWith - 2) - $textLength) / 2 $textLine = " " * $textBlanks + $Text $textLine += " " * (($maxWith - 1) - $textLine.Length - 1) } [pscustomobject]@{ Text = "$textLine" Color = $color } } if ($PSBoundParameters.ContainsKey("MenuName")) { $menu = Get-Menu -Name $MenuName } else { $menu = Get-Menu -MainMenu } if (-not $menu) { Write-Error -Exception "$f - Could not find menu" } $menuIndex = $script:Menus.IndexOf($menu) $menuFrame = $script:MenuOptions.MenuFillChar * ($maxWith - 2) $null = $menuLines.Add((Get-MenuLine -Text $menuFrame -color $script:MenuOptions.MenuFillColor)) $null = $menuLines.Add((Get-MenuLine -Text $menu.DisplayName -Color $script:MenuOptions.MenuNameColor)) $menuEmptyLine = " " * ($maxWith - 2) $null = $menuLines.Add((Get-MenuLine -Text $menuEmptyLine -color $script:MenuOptions.MenuFillColor)) $null = $menuLines.Add((Get-MenuLine -Text $menuEmptyLine -color $script:MenuOptions.MenuFillColor)) $null = $menuLines.Add((Get-MenuLine -Text $script:MenuOptions.Heading -color $script:MenuOptions.HeadingColor)) $null = $menuLines.Add((Get-MenuLine -Text $menuEmptyLine -color $script:MenuOptions.MenuFillColor)) $null = $menuLines.Add((Get-MenuLine -Text $script:MenuOptions.SubHeading -color $script:MenuOptions.SubHeadingColor)) $null = $menuLines.Add((Get-MenuLine -Text $menuEmptyLine -color $script:MenuOptions.MenuFillColor)) $null = $menuLines.Add((Get-MenuLine -Text $menuEmptyLine -color $script:MenuOptions.MenuFillColor)) $null = $menuLines.Add((Get-MenuLine -Text $menuFrame -color $script:MenuOptions.MenuFillColor)) $null = $menuLines.Add((Get-MenuLine -Text $menuEmptyLine -color $script:MenuOptions.MenuFillColor)) foreach ($item in $menu.MenuItems) { $menuColor = $script:MenuOptions.MenuItemColor $menuItemIndex = $script:menus[$menuIndex].MenuItems.IndexOf($item) $null = $menuLines.Add((Get-MenuLine -Text "$menuItemIndex. $($item.DisplayName)" -IsMenuItem $true -Color $menuColor)) } $null = $menuLines.Add((Get-MenuLine -Text $menuEmptyLine -color $script:MenuOptions.MenuFillColor)) $null = $menuLines.Add((Get-MenuLine -Text $menuEmptyLine -color $script:MenuOptions.MenuFillColor)) $null = $menuLines.Add((Get-MenuLine -Text $script:MenuOptions.FooterText -color $script:MenuOptions.FooterTextColor)) $null = $menuLines.Add((Get-MenuLine -Text $menuEmptyLine -color $script:MenuOptions.MenuFillColor)) $null = $menuLines.Add((Get-MenuLine -Text $menuFrame -color $script:MenuOptions.MenuFillColor)) foreach ($line in $menuLines) { Write-Host -Object $script:MenuOptions.MenuFillChar -ForegroundColor $script:MenuOptions.MenuFillColor -NoNewline Write-Host -Object $line.Text -ForegroundColor $line.Color -NoNewline Write-Host -Object $script:MenuOptions.MenuFillChar -ForegroundColor $script:MenuOptions.MenuFillColor } $userSelection = (Read-Host -Prompt "Please enter number to execute action") try { $actionItemSelectionIndex = [int]($userSelection) } catch { Write-Error -Message $_.Exception.Message Write-Host -Object "Menuitem not found [$userSelection]" -ForegroundColor DarkYellow break } $menuSelected = $menu.MenuItems[$actionItemSelectionIndex] if ($menuSelected) { if ($menuSelected.ConfirmBeforeInvoke) { $Continue = Read-Host -Prompt "Are you sure you want to execute [$($menuSelected.Name)] Y/N?" If ($Continue -ne "y") { Write-Host -Object "Execution aborted" -ForegroundColor DarkYellow break } } if ($menuSelected.Action) { Write-Host -Object "Invoking [$($menuSelected.Name)]" -ForegroundColor DarkYellow $menuSelected.Action.Invoke() Write-Host -Object "Invoke DONE!" -ForegroundColor DarkYellow } } else { Write-Host -Object "Menuitem not found [$userSelection]" -ForegroundColor DarkYellow } Write-Verbose -Message "$f- END" } } |