Skip to content

Instantly share code, notes, and snippets.

@M1kep
Last active August 4, 2020 04:21
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save M1kep/ef5fa0009ade4f55474b4e36c5b3d709 to your computer and use it in GitHub Desktop.
Save M1kep/ef5fa0009ade4f55474b4e36c5b3d709 to your computer and use it in GitHub Desktop.
A PowerShell example of using a stack for breadcrumb like navigation
# Initialize the Stack
$breadCrumb = [System.Collections.Stack]::new()
# Push Page "1"
$breadCrumb.Push(1)
#Initialize empty Pages object
$Pages = @{}
function New-Choice {
[CmdletBinding()]
param (
[Parameter()]
[String]
$Name,
[Parameter()]
[String]
$Description
)
New-Object -TypeName 'System.Management.Automation.Host.ChoiceDescription' -ArgumentList $Name, $Description
}
function Request-NextPageFromUser {
[CmdletBinding()]
param (
[Parameter()]
[String]
$Title,
[Parameter()]
[String]
$Message,
[Parameter()]
[Object[]]
$Options
)
$responseMap = $Options.ID
$menuOptions = @()
$Options.ForEach{
$menuOptions += New-Choice -Name "&$($_.Prompt)" -Description $_.Help
}
$menuOptions += Get-BackAndMenuOptions
$responseIndex = $host.ui.PromptForChoice($Title, $Message, $menuOptions, 0)
Update-BreadCrumb -ResponseMap $responseMap -ResponseIndex $responseIndex
}
function New-Page {
[CmdletBinding()]
param (
[Parameter()]
[String]
$Name,
[Parameter()]
[Int]
$PageID,
[Parameter()]
[scriptblock]
$Function,
[Parameter()]
[String]
$Prompt,
[Parameter()]
[String]
$Help
)
$Pages[$Name] = @{
ID = $PageID
Function = $Function
Prompt = $Prompt
Help = $Help
}
}
function Get-BackAndMenuOptions {
@(
New-Choice '&Go Back' 'Go back a page'
New-Choice '&Main Menu' 'Go back to main menu'
)
}
function Update-BreadCrumb {
[CmdletBinding()]
param (
[Parameter()]
[Int[]]
$ResponseMap,
[Parameter()]
[Int]
$ResponseIndex
)
if ($ResponseIndex -ge ($ResponseMap.Count)) {
$tmpIndex = $ResponseIndex - $ResponseMap.Count
switch ($tmpIndex) {
0 {
#Go Back Option
#Double check that we aren't at the end
if ($breadCrumb.Count -gt 1) {
$breadCrumb.Pop() | Out-Null
}
break
}
1 {
#Main Menu Option
$breadCrumb.Clear()
$breadCrumb.Push(1)
break
}
}
} else {
$mappedPageID = $ResponseMap[$responseIndex]
# If the pageID is the same, don't add it. We don't want to create a list of the same page
if (-not ($breadCrumb.Peek() -eq $mappedPageID)) {
$breadCrumb.Push($ResponseMap[$responseIndex])
}
}
}
function PeopleMenu {
$Title = "People Main Menu"
Request-NextPageFromUser -Title $Title -Options @($Pages["ListPeople"])
}
function ListPeople {
$Title = "List People Page"
$people = @(
"Vex",
"Jaykul",
"Jborean"
"Syrup"
)
Write-Host $($people -join "`n")
Request-NextPageFromUser -Title $Title -Options @($Pages["ListPeople"])
}
function CarMenu {
$Title = "Car Main Menu"
Request-NextPageFromUser -Title $Title -Options @($Pages["ListCars"])
}
function ListCars {
$Title = "List Cars Page"
$cars = @(
"SUV",
"Van",
"Sedan"
)
Write-Host $($cars -join "`n")
Request-NextPageFromUser -Title $Title -Options @($Pages["ListCars"])
}
function MainMenu {
$Title = "People and Car Main Menu"
Request-NextPageFromUser -Title $Title -Options @($Pages["CarMenu"], $Pages["PeopleMenu"])
}
#Define pages for easier reference in script
New-Page -Name 'MainMenu' -PageID 1 -Function $Function:MainMenu -Prompt 'Main Menu' -Help 'Goto the Main Menu'
New-Page -Name 'CarMenu' -PageID 2 -Function $Function:CarMenu -Prompt 'Car Menu' -Help 'Goto the Car Menu'
New-Page -Name 'PeopleMenu' -PageID 3 -Function $Function:PeopleMenu -Prompt 'People Menu' -Help 'Goto the People Menu'
New-Page -Name 'ListCars' -PageID 4 -Function $Function:ListCars -Prompt 'List Cars' -Help 'List all of the cars'
New-Page -Name 'ListPeople' -PageID 5 -Function $Function:ListPeople -Prompt 'List People' -Help 'List all of the people'
$pageFuncMap = @{}
#Map each PageID to it's respective function
$Pages.Values.ForEach{
$pageFuncMap[$_.ID] = $_.Function
}
while ($true) {
$currentBreadCrumb = $breadCrumb.ToArray()
#Reverse array because a stack is Last In First Out
[array]::Reverse($currentBreadCrumb)
# Get Function Names for this example
$currentBreadCrumbWithNames = $currentBreadCrumb.forEach{ $pageFuncMap[$_].Ast.Name }
Write-Host "Current BreadCrumb: $($currentBreadCrumbWithNames -join ' --> ')"
& $pageFuncMap[$breadCrumb.Peek()]
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment