Monday, February 09, 2009

CLI Menu in PowerShell

There are a lot of WPF-based PowerShell menu functions and demos available in various places, but for some reason I feel that PowerShell really needs a good, ol' fashion CLI menu.

So, here is a quick, sort of hack'ish CLI menu for PowerShell (dont worry, I just made up the individual menu options - can you tell I just reread BOFH recently?).

Use the up and down arrows to navigate the menu, and press ENTER to select.

function DrawMenu {
    ## supportfunction to the Menu function below
    param ($menuItems, $menuPosition, $menuTitel)
    $fcolor = $host.UI.RawUI.ForegroundColor
    $bcolor = $host.UI.RawUI.BackgroundColor
    $l = $menuItems.length + 1
    $menuwidth = $menuTitel.length + 4
    Write-Host "`t" -NoNewLine
    Write-Host ("*" * $menuwidth) -fore $fcolor -back $bcolor
    Write-Host "`t" -NoNewLine
    Write-Host "* $menuTitel *" -fore $fcolor -back $bcolor
    Write-Host "`t" -NoNewLine
    Write-Host ("*" * $menuwidth) -fore $fcolor -back $bcolor
    Write-Host ""
    Write-debug "L: $l MenuItems: $menuItems MenuPosition: $menuposition"
    for ($i = 0; $i -le $l;$i++) {
        Write-Host "`t" -NoNewLine
        if ($i -eq $menuPosition) {
            Write-Host "$($menuItems[$i])" -fore $bcolor -back $fcolor
        } else {
            Write-Host "$($menuItems[$i])" -fore $fcolor -back $bcolor

function Menu {
    ## Generate a small "DOS-like" menu.
    ## Choose a menuitem using up and down arrows, select by pressing ENTER
    param ([array]$menuItems, $menuTitel = "MENU")
    $vkeycode = 0
    $pos = 0
    DrawMenu $menuItems $pos $menuTitel
    While ($vkeycode -ne 13) {
        $press = $host.ui.rawui.readkey("NoEcho,IncludeKeyDown")
        $vkeycode = $press.virtualkeycode
        Write-host "$($press.character)" -NoNewLine
        If ($vkeycode -eq 38) {$pos--}
        If ($vkeycode -eq 40) {$pos++}
        if ($pos -lt 0) {$pos = 0}
        if ($pos -ge $menuItems.length) {$pos = $menuItems.length -1}
        DrawMenu $menuItems $pos $menuTitel
    Write-Output $($menuItems[$pos])


$bad = "Format c:","Send spam to boss","Truncate database *","Randomize user password","Download dilbert","Hack local AD"
$selection = Menu $bad "WHAT DO YOU WANNA DO?"
Write-Host "YOU SELECTED : $selection ... DONE!`n"

Another Example:

$options = "Dir","Ping", "Ipconfig"
$selection = Menu $options "CHOOSE YOUR COMMAND:"
Switch ($selection) {
    "Dir" {Invoke-Expression "Dir C:\";break}
    "Ping" {Invoke-Expression "Ping";break}
    "Ipconfig" {Invoke-Expression "Ipconfig";break}

7 comments: said...

That's cool!

Steve said...

Nice.. I like the menu options :)

Craig Smith said...

Switch the
if ($pos -lt 0) {$pos = 0}with
if ($pos -lt 0) {$pos = $menuItems.length -1}and

if ($pos -ge $menuItems.length) {$pos = $menuItems.length -1}with
if ($pos -ge $menuItems.length) {$pos = 0}to allow the menu to wrap around.

Arnaud Petitjean said...

Very cool script !!! I love it !

Retreive it here:

Danno said...

Great script, nice and adaptable.

I had to modify the following color lines to get it to work

$fcolor = $host.UI.RawUI.ForegroundColor
$bcolor = $host.UI.RawUI.BackgroundColor

$fcolor = "Black"
$bcolor = "Green"

Obviously you can go anyway you want with that though.

.:TDA:. said...

I'm real new to PS.
But I needed a script like this, but with option e.g:
But I dont know how to do it.
Can you adapat this script to do so? THaaanks :D

Jakob Bindslet said...

Hi .:TDA:.
I have added another example to my post.
Does this example solve your problem?