├── BoxyPrompt ├── Animation.gif ├── BoxyPrompt.ps1 ├── README.md └── WrapText.ps1 ├── CompareJson ├── CompareJson.ps1 ├── ConvertToHashtable.ps1 ├── README.md └── WriteLine.ps1 ├── Mini-u ├── Animation.gif ├── BoxyPrompt │ ├── BoxyPrompt.ps1 │ └── WrapText.ps1 ├── DrawMenu.ps1 ├── Mini-u.ps1 ├── README.md └── menus │ ├── AdministrativeTasks.json │ ├── GeneralTasks.json │ └── InfrastructureTasks.json └── SillyScripts └── MockThem ├── Animation.gif ├── MockThem.ps1 ├── MockThemButBadCode.ps1 └── README.md /BoxyPrompt/Animation.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/L-McG/PowerShell/70c3abef8650b1753cf9ac4ad33f073de3d00482/BoxyPrompt/Animation.gif -------------------------------------------------------------------------------- /BoxyPrompt/BoxyPrompt.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Draw a cool box around a prompt! 4 | .DESCRIPTION 5 | Draw a cool box around a prompt! Boxy-Prompt can do it all! Like draw a box! 6 | Well, perhaps that's about all it can do... but it leverages Wrap-Text to 7 | keep your really cool messages within a prescribed width. Oh! Padding! It 8 | can adjust for prescribed padding. 9 | .NOTES 10 | Author: Lucas McGlamery 11 | Version: 12 | 1.0 1/12/23 Initial release 13 | TODO: 14 | - Make the character which the box is drawn customizable 15 | - Account for really long character strings 16 | - Perform better parameter input validation 17 | .PARAMETER Prompt 18 | An array object to hold text or multiple elements of text. 19 | .PARAMETER BoxWidth 20 | Specified width integer. Default is width of the terminal. 21 | .PARAMETER SidePadding 22 | Specified padding integer for space with text and sides of box. Default is 5. 23 | .PARAMETER BorderCharacter 24 | Character to be repeated as the border. 25 | .EXAMPLE 26 | Boxy-Prompt 27 | .EXAMPLE 28 | Boxy-Prompt $string 29 | .EXAMPLE 30 | $string | Boxy-Prompt 31 | .EXAMPLE 32 | $string | Boxy-Prompt -BoxWidth 420 -SidePadding 69 -BorderCharacter '!' 33 | #> 34 | . .\WrapText.ps1 35 | function Boxy-Prompt { 36 | param ( 37 | [Parameter(Mandatory,ValueFromPipeline)] 38 | [Object[]]$Prompt, 39 | [Parameter()] 40 | [int]$BoxWidth = $Host.UI.RawUI.BufferSize.Width, 41 | [Parameter()] 42 | [int]$SidePadding = 5, 43 | [Parameter()] 44 | [string]$BorderCharacter = "#" 45 | ) 46 | if ($BoxWidth -gt $Host.UI.RawUI.BufferSize.Width) { 47 | $BoxWidth = $Host.UI.RawUI.BufferSize.Width 48 | } 49 | if ($BoxWidth -lt 35) { 50 | $BoxWidth = 35 51 | } 52 | if ($SidePadding -lt 5) { 53 | $SidePadding = 5 54 | } 55 | $Prompt = Wrap-Text $Prompt $($BoxWidth - $SidePadding) 56 | [bool]$PromptWritten = $false 57 | 58 | $LongestLength = 0 59 | $Prompt | ForEach-Object { 60 | if ($_.Length -gt $LongestLength) { 61 | $LongestLength = $_.Length 62 | } 63 | } 64 | $BoxHeight = $($Prompt.Count + 4) 65 | 66 | $PromptStart = ([math]::round($BoxWidth / 2) - [math]::round((($LongestLength) / 2) - 1)) 67 | $PromptEnd = $PromptStart + $LongestLength - 1 68 | 69 | 1..$BoxHeight | ForEach-Object { 70 | if ($_ -eq 1 -or $_ -eq $BoxHeight) { 71 | Write-Host ($BorderCharacter * $BoxWidth -join '') 72 | } 73 | elseif ($_ -eq 2 -or $_ -eq ($BoxHeight - 1)) { 74 | 1..$BoxWidth | ForEach-Object { 75 | if ($_ -eq 1) { 76 | Write-Host -NoNewline $BorderCharacter 77 | } elseif ($_ -ne 1 -and $_ -ne $BoxWidth) { 78 | Write-Host -NoNewline " " 79 | } else { 80 | Write-Host $BorderCharacter 81 | } 82 | } 83 | } 84 | elseif (!$PromptWritten) { 85 | $Prompt | ForEach-Object { 86 | $LeftPadding = 0 87 | [bool]$break = $false 88 | Write-Host -NoNewline $BorderCharacter 89 | 1..$($PromptStart - 1) | ForEach-Object { 90 | $LeftPadding++ 91 | Write-Host -NoNewline " " 92 | } 93 | Write-Host -NoNewline $_ 94 | if ($BoxWidth -eq ($_.Length + ([math]::round($SidePadding/2)+3))) { 95 | Write-Host $BorderCharacter 96 | $break = $true 97 | } 98 | if(!$break){ 99 | 1..($BoxWidth - (($_.Length + $LeftPadding)+2)) | ForEach-Object { 100 | Write-Host -NoNewline " " 101 | } 102 | Write-Host $BorderCharacter 103 | } 104 | $PromptWritten = $true 105 | } 106 | } 107 | } 108 | } -------------------------------------------------------------------------------- /BoxyPrompt/README.md: -------------------------------------------------------------------------------- 1 | ![](https://github.com/L-McG/PowerShell/blob/master/BoxyPrompt/Animation.gif) 2 | 3 | # Usage 4 | ``` 5 | Import-Module .\BoxyPrompt.ps1 6 | Boxy-Prompt 7 | ``` -------------------------------------------------------------------------------- /BoxyPrompt/WrapText.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Wraps text within a given constraint. 4 | .DESCRIPTION 5 | Wraps text within a given constraint. If no constraint is given, default is the width of the terminal. 6 | Since the WordBlock parameter is an array object, either a single string or an array of strings can be 7 | passed in. 8 | .NOTES 9 | Author: Lucas McGlamery 10 | Version: 11 | 1.0 1/12/23 Initial release 12 | .PARAMETER WordBlock 13 | An array object to hold text or multiple elements of text. 14 | .PARAMETER Width 15 | Specified width integer. Default is width of the terminal. 16 | .EXAMPLE 17 | Wrap-Text -WordBlock $string -Width 60 18 | .EXAMPLE 19 | $string | Wrap-Text 20 | .EXAMPLE 21 | $string | Wrap-Text -Width 60 22 | #> 23 | function Wrap-Text { 24 | [CmdletBinding()] 25 | param ( 26 | [Parameter(Mandatory,ValueFromPipeline)] 27 | [Object[]]$WordBlock, 28 | [Parameter()] 29 | [int]$Width = $Host.UI.RawUI.BufferSize.Width 30 | ) 31 | if ($Width -gt $Host.UI.RawUI.BufferSize.Width) { 32 | $Width = $Host.UI.RawUI.BufferSize.Width 33 | } 34 | $WrappedText = @() 35 | foreach ($Line in $WordBlock) { 36 | $String = '' 37 | $Count = 0 38 | $Line -split '\s+' | ForEach-Object{ 39 | $Count += $_.Length + 1 40 | if ($Count -gt $Width) { 41 | $WrappedText += $String 42 | $String = '' 43 | $Count = $_.Length + 1 44 | } 45 | $String = "$($String)$($_) " 46 | } 47 | $WrappedText += $String 48 | } 49 | return $WrappedText 50 | } -------------------------------------------------------------------------------- /CompareJson/CompareJson.ps1: -------------------------------------------------------------------------------- 1 | ###### Dependencies ######### 2 | . .\ConvertToHashtable.ps1 3 | . .\WriteLine.ps1 4 | ############################### 5 | 6 | Function Compare-Json() { 7 | <# 8 | .SYNOPSIS 9 | Compare two JSON files and return a difference file. 10 | 11 | .DESCRIPTION 12 | Given a reference and comparison file, this function will recursively compare the objects 13 | within two JSON files by a specified ID. ConvertToHashtable.ps1 is required to ensure that 14 | the incoming objects during recursion are in the correct format. WriteLine.ps1 is used 15 | to improve readability during debugging. 16 | 17 | .NOTES 18 | Author: Lucas McGlamery 19 | 20 | Version: v1.0 -- 18 Jan 2023 21 | - Initial release 22 | 23 | v1.1 -- 23 Jun 2023 24 | - Added key exclusion 25 | - Added WriteLine.ps1 26 | .PARAMETER Table1 27 | Reference object derived from the reference file used for recursion. 28 | 29 | .PARAMETER Table2 30 | Comparison object derived from the comparison file used for recursion. 31 | 32 | .PARAMETER ReferenceFile 33 | File to be used as reference. Must by a valid JSON file. 34 | 35 | .PARAMETER ComparisonFile 36 | File to be compared against the reference. Must by a valid JSON file. 37 | 38 | .PARAMETER ID 39 | Specified object ID. Default is 'Name'. 40 | 41 | .PARAMETER DifferenceFound 42 | Boolean placeholder for future implementation. 43 | 44 | .PARAMETER ParentTable 45 | Table used to assign reference root objects with key/value of Parent: true. 46 | 47 | .PARAMETER KeyExclusions 48 | A string array of keys to exclude should they need to be omitted during comparison. 49 | 50 | .EXAMPLE 51 | Compare-Json -ReferenceFile .\Reference.json -ComparisonFile .\Deployment.json 52 | #> 53 | Param( 54 | [Parameter()] 55 | [Object[]]$Table1, 56 | [Parameter()] 57 | [Object[]]$Table2, 58 | [Parameter()] 59 | [string]$ReferenceFile, 60 | [Parameter()] 61 | [string]$ComparisonFile, 62 | [Parameter()] 63 | [string]$ID = 'Name', 64 | [Parameter()] 65 | [bool]$DifferenceFound = $false, 66 | [Parameter()] 67 | [array]$ParentTable = @(), 68 | [Parameter()] 69 | [string[]]$KeyExclusions 70 | ) 71 | 72 | if ($ReferenceFile -and $ComparisonFile) { 73 | $Table1 = Get-Content $ReferenceFile | ConvertFrom-Json -AsHashtable -Depth 10 74 | $Table2 = Get-Content $ComparisonFile | ConvertFrom-Json -AsHashtable -Depth 10 75 | $Table1 | ForEach-Object { 76 | if ($_.Name -notcontains 'Parent') { 77 | $_.Add('Parent', $true) 78 | } 79 | } 80 | $Table2 | ForEach-Object { 81 | if ($_.Name -notcontains 'Parent') { 82 | $_.Add('Parent', $true) 83 | } 84 | } 85 | } 86 | if (!$Global:ParentTable) { 87 | $Global:ParentTable = @() 88 | } 89 | Write-Host $ParentTable.GetType() 90 | Write-Host "Table1 keys are $($Table1.Keys)" 91 | Write-Host "Table2 keys are $($Table2.Keys)" 92 | 93 | 94 | # set the current key name 95 | # if count is one, set the table key to be the only available key 96 | if ($Table1.Keys.Count -gt 1) { 97 | $Table1Key = $ID 98 | } 99 | elseif ($Table1.Values.Count -gt 1) { 100 | $Table1Key = "$($Table1.Keys)" 101 | } 102 | else { 103 | $Table1Key = $Table1.Keys 104 | } 105 | if ($Table2.Keys.Count -gt 1) { 106 | $Table2Key = $ID 107 | } 108 | elseif ($Table2.Values.Count -gt 1) { 109 | $Table2Key = "$($Table2.Keys)" 110 | } 111 | else { 112 | $Table2Key = $Table2.Keys 113 | } 114 | Write-Host "Table1Key is $($Table1Key)" -ForegroundColor DarkYellow 115 | Write-Host "Table2Key is $($Table2Key)" -ForegroundColor DarkYellow 116 | 117 | 118 | if ($Table1Key -notin $KeyExclusions) { 119 | foreach ($Item in $Table1.$Table1Key) { 120 | Write-Host "Current item in table is " $Item -ForegroundColor DarkGreen 121 | Write-Host "Current list of names: " $Item.$ID 122 | 123 | if ($Item.GetType() -ne [System.String]) { 124 | Write-Host "Type is not a System.String" -ForegroundColor Red 125 | $CurrentTable = $Table1.$Table1Key | Where-Object { 126 | $_.$ID -eq $Item.$ID 127 | } 128 | $SecondTable = $Table2.$Table2Key | Where-Object { 129 | $_.$ID -eq $Item.$ID 130 | } 131 | } else { 132 | $CurrentTable = $Table1 | Where-Object { 133 | $_.$Table1Key -eq $Item 134 | $SecondTable = $Table2 | Where-Object { 135 | $_.$Table2Key -eq $Item 136 | } 137 | } 138 | } 139 | if ($null -eq $CurrentTable) { 140 | Write-Host "Current table is null. Continuing with next object..." -BackgroundColor DarkYellow 141 | continue 142 | } 143 | if($CurrentTable.Parent){ 144 | Write-Host "Adding table to ParentTable..." 145 | $Global:ParentTable += $CurrentTable 146 | } 147 | if ($null -eq $SecondTable) { 148 | Write-Host "Current second table is null. Adding last parent to difference table. Continuing..." -BackgroundColor DarkYellow 149 | if(!$Global:DifferenceTable) { 150 | $Global:DifferenceTable = @() 151 | } 152 | if($Global:DifferenceTable.Name -notcontains $Global:ParentTable[-1].Name) { 153 | $Global:DifferenceTable += $Global:ParentTable[-1] 154 | } 155 | continue 156 | } 157 | Write-Host "The current tables are as follows: `n" -BackgroundColor Green 158 | Write-Line 159 | Write-Host "Current table" 160 | $CurrentTable 161 | Write-Host "Second table" 162 | $SecondTable 163 | 164 | $CurrentTable.GetEnumerator() | Where-Object { 165 | $_.$ID -notin $KeyExclusions 166 | } | ForEach-Object { 167 | $CurrentKey = $_ 168 | $CurrentKeyName = $_.$ID 169 | Write-Host "CurrentKeyName is $($CurrentKeyName)" -ForegroundColor DarkGreen 170 | $CurrentSecondTable = $SecondTable.GetEnumerator() | Where-Object { 171 | $_.$ID -eq $CurrentKeyName 172 | } 173 | Write-Host "CurrentFirstTable is: $($CurrentKey)" -ForegroundColor DarkGreen 174 | Write-Host "CurrentSecondTable is: $($CurrentSecondTable)" -ForegroundColor DarkBlue 175 | 176 | if ($CurrentKey.Value.GetType() -ne [System.String]) { 177 | Write-Host "CurrentKey is $($CurrentKey.GetType())" 178 | Write-Host "SecondTable current key is $($CurrentSecondTable.GetType())" 179 | 180 | if ($CurrentKey.GetType().Name -ne 'Hashtable') { 181 | $CurrentKey = ConvertTo-Hashtable $CurrentKey 182 | Write-Host "CurrentKey is now $($CurrentKey.GetType())" 183 | } 184 | if ($CurrentSecondTable.GetType().Name -ne 'Hashtable') { 185 | $CurrentSecondTable = ConvertTo-Hashtable $CurrentSecondTable 186 | Write-Host "SecondTable current key is now $($CurrentSecondTable.GetType())" 187 | } 188 | if ($_.Value.$ID) { 189 | Write-Host "Value found containing key $ID. Recuring function...`n" -BackgroundColor DarkMagenta 190 | Write-Line 191 | Compare-Json $CurrentKey $CurrentSecondTable -ParentTable $Global:ParentTable 192 | } 193 | } elseif ($CurrentKey.Count -eq 1) { 194 | Write-Host "Current key: $CurrentKey" -ForegroundColor DarkGreen 195 | Write-Host "Current second table: $CurrentSecondTable" -ForegroundColor DarkGreen 196 | if (!$CurrentKey.Equals($CurrentSecondTable)) { 197 | if(!$Global:DifferenceTable) { 198 | $Global:DifferenceTable = @() 199 | } 200 | if($Global:DifferenceTable.Name -notcontains $($Global:ParentTable[-1].Name)) { 201 | Write-host "Difference found. Adding $($Global:ParentTable[-1].Name) to difference table..." -BackgroundColor DarkYellow 202 | $Global:DifferenceTable += $Global:ParentTable[-1] 203 | } 204 | } elseif ($CurrentKey.Equals($CurrentSecondTable)) { 205 | Write-host "No difference found." 206 | } 207 | } 208 | } 209 | } 210 | } 211 | $DifferenceTable | ConvertTo-Json -Depth 10 | Out-File .\DifferenceReport.json 212 | } -------------------------------------------------------------------------------- /CompareJson/ConvertToHashtable.ps1: -------------------------------------------------------------------------------- 1 | function ConvertTo-Hashtable { 2 | [CmdletBinding()] 3 | param ( 4 | [Parameter()] 5 | [System.Object] 6 | $InputObject 7 | ) 8 | 9 | begin { 10 | $OutputHash = @{} 11 | } 12 | 13 | process { 14 | $OutputHash.Add($InputObject.Name, $InputObject.Value) 15 | } 16 | 17 | end { 18 | return $OutputHash 19 | } 20 | } -------------------------------------------------------------------------------- /CompareJson/README.md: -------------------------------------------------------------------------------- 1 | ## Synopsis 2 | Compare two JSON files and return a difference file. 3 | 4 | ## Description 5 | Given a reference and comparison file, this function will recursively compare the objects 6 | within two JSON files by a specified ID. ConvertToHashtable.ps1 is required to ensure that 7 | the incoming objects during recursion are in the correct format. WriteLine.ps1 is used 8 | to improve readability during debugging. 9 | 10 | ## Usage 11 | ```powershell 12 | Import-Module .\CompareJson.ps1 13 | Compare-Json -ReferenceFile .\ReferenceFile.json -ComparisonFile .\ComparisonFile.json 14 | ``` -------------------------------------------------------------------------------- /CompareJson/WriteLine.ps1: -------------------------------------------------------------------------------- 1 | function Write-Line { 2 | '-' * $host.ui.RawUI.WindowSize.Width -join '' 3 | } -------------------------------------------------------------------------------- /Mini-u/Animation.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/L-McG/PowerShell/70c3abef8650b1753cf9ac4ad33f073de3d00482/Mini-u/Animation.gif -------------------------------------------------------------------------------- /Mini-u/BoxyPrompt/BoxyPrompt.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Draw a cool box around a prompt! 4 | .DESCRIPTION 5 | Draw a cool box around a prompt! Boxy-Prompt can do it all! Like draw a box! 6 | Well, perhaps that's about all it can do... but it leverages Wrap-Text to 7 | keep your really cool messages within a prescribed width. Oh! Padding! It 8 | can adjust for prescribed padding. 9 | .NOTES 10 | Author: Lucas McGlamery 11 | Version: 12 | 1.0 1/12/23 Initial release 13 | TODO: 14 | - Make the character which the box is drawn customizable 15 | - Account for really long character strings 16 | - Perform better parameter input validation 17 | .PARAMETER Prompt 18 | An array object to hold text or multiple elements of text. 19 | .PARAMETER BoxWidth 20 | Specified width integer. Default is width of the terminal. 21 | .PARAMETER SidePadding 22 | Specified padding integer for space with text and sides of box. Default is 5. 23 | .EXAMPLE 24 | Boxy-Prompt 25 | .EXAMPLE 26 | Boxy-Prompt $string 27 | .EXAMPLE 28 | $string | Boxy-Prompt 29 | .EXAMPLE 30 | $string | Boxy-Prompt -BoxWidth 420 -SidePadding 69 31 | #> 32 | if (!(Get-Module -Name BoxyPrompt)) { 33 | Import-Module $PSScriptRoot\WrapText.ps1 34 | } 35 | function Boxy-Prompt { 36 | param ( 37 | [Parameter(Mandatory,ValueFromPipeline)] 38 | [Object[]]$Prompt, 39 | [Parameter()] 40 | [int]$BoxWidth = $Host.UI.RawUI.BufferSize.Width, 41 | [Parameter()] 42 | [int]$SidePadding = 5 43 | ) 44 | if ($BoxWidth -gt $Host.UI.RawUI.BufferSize.Width) { 45 | $BoxWidth = $Host.UI.RawUI.BufferSize.Width 46 | } 47 | if ($BoxWidth -lt 35) { 48 | $BoxWidth = 35 49 | } 50 | if ($SidePadding -lt 5) { 51 | $SidePadding = 5 52 | } 53 | $Prompt = Wrap-Text $Prompt $($BoxWidth - $SidePadding) 54 | [bool]$PromptWritten = $false 55 | 56 | $LongestLength = 0 57 | $Prompt | ForEach-Object { 58 | if ($_.Length -gt $LongestLength) { 59 | $LongestLength = $_.Length 60 | } 61 | } 62 | $BoxHeight = $($Prompt.Count + 4) 63 | 64 | $PromptStart = ([math]::round($BoxWidth / 2) - [math]::round((($LongestLength) / 2) - 1)) 65 | $PromptEnd = $PromptStart + $LongestLength - 1 66 | 67 | 1..$BoxHeight | ForEach-Object { 68 | if ($_ -eq 1 -or $_ -eq $BoxHeight) { 69 | Write-Host ('#' * $BoxWidth -join '') 70 | } 71 | elseif ($_ -eq 2 -or $_ -eq ($BoxHeight - 1)) { 72 | 1..$BoxWidth | ForEach-Object { 73 | if ($_ -eq 1) { 74 | Write-Host -NoNewline "#" 75 | } elseif ($_ -ne 1 -and $_ -ne $BoxWidth) { 76 | Write-Host -NoNewline " " 77 | } else { 78 | Write-Host "#" 79 | } 80 | } 81 | } 82 | elseif (!$PromptWritten) { 83 | $Prompt | ForEach-Object { 84 | $LeftPadding = 0 85 | [bool]$break = $false 86 | Write-Host -NoNewline "#" 87 | 1..$($PromptStart - 1) | ForEach-Object { 88 | $LeftPadding++ 89 | Write-Host -NoNewline " " 90 | } 91 | Write-Host -NoNewline $_ 92 | if ($BoxWidth -eq ($_.Length + ([math]::round($SidePadding/2)+3))) { 93 | Write-Host "#" 94 | $break = $true 95 | } 96 | if(!$break){ 97 | 1..($BoxWidth - (($_.Length + $LeftPadding)+2)) | ForEach-Object { 98 | Write-Host -NoNewline " " 99 | } 100 | Write-Host "#" 101 | } 102 | $PromptWritten = $true 103 | } 104 | } 105 | } 106 | } -------------------------------------------------------------------------------- /Mini-u/BoxyPrompt/WrapText.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Wraps text within a given constraint. 4 | .DESCRIPTION 5 | Wraps text within a given constraint. If no constraint is given, default is the width of the terminal. 6 | Since the WordBlock parameter is an array object, either a single string or an array of strings can be 7 | passed in. 8 | .NOTES 9 | Author: Lucas McGlamery 10 | Version: 11 | 1.0 1/12/23 Initial release 12 | .PARAMETER WordBlock 13 | An array object to hold text or multiple elements of text. 14 | .PARAMETER Width 15 | Specified width integer. Default is width of the terminal. 16 | .EXAMPLE 17 | Wrap-Text -WordBlock $string -Width 60 18 | .EXAMPLE 19 | $string | Wrap-Text 20 | .EXAMPLE 21 | $string | Wrap-Text -Width 60 22 | #> 23 | function Wrap-Text { 24 | [CmdletBinding()] 25 | param ( 26 | [Parameter(Mandatory,ValueFromPipeline)] 27 | [Object[]]$WordBlock, 28 | [Parameter()] 29 | [int]$Width = $Host.UI.RawUI.BufferSize.Width 30 | ) 31 | if ($Width -gt $Host.UI.RawUI.BufferSize.Width) { 32 | $Width = $Host.UI.RawUI.BufferSize.Width 33 | } 34 | $WrappedText = @() 35 | foreach ($Line in $WordBlock) { 36 | $String = '' 37 | $Count = 0 38 | $Line -split '\s+' | ForEach-Object{ 39 | $Count += $_.Length + 1 40 | if ($Count -gt $Width) { 41 | $WrappedText += $String 42 | $String = '' 43 | $Count = $_.Length + 1 44 | } 45 | $String = "$($String)$($_) " 46 | } 47 | $WrappedText += $String 48 | } 49 | return $WrappedText 50 | } -------------------------------------------------------------------------------- /Mini-u/DrawMenu.ps1: -------------------------------------------------------------------------------- 1 | function Draw-Menu { 2 | [CmdletBinding()] 3 | param ( 4 | [Parameter()] 5 | [String[]] 6 | $menuItems, 7 | [Parameter()] 8 | [int32] 9 | $menuPosition, 10 | [Parameter()] 11 | [String] 12 | $menuTitle 13 | ) 14 | $foregroundColor = $host.UI.RawUI.ForegroundColor 15 | $backgroundColor = $host.UI.RawUI.BackgroundColor 16 | $l = $menuItems.length 17 | Clear-Host 18 | $menuTitle | Boxy-Prompt -BoxWidth 40 19 | 20 | for ($i = 0; $i -le $l; $i++) { 21 | Write-Host "`t" -NoNewLine 22 | if ($i -eq $menuPosition) { 23 | Write-Host "$($menuItems[$i])" -ForegroundColor $backgroundColor -BackgroundColor $foregroundColor 24 | } else { 25 | Write-Host "$($menuItems[$i])" -ForegroundColor $foregroundColor -BackgroundColor $backgroundColor 26 | } 27 | } 28 | } 29 | 30 | function Menu { 31 | #param ([array]$menuItems, $menuTitle = "MENU") 32 | [CmdletBinding()] 33 | param ( 34 | [Parameter()] 35 | [String[]] 36 | $menuItems, 37 | [Parameter()] 38 | [String] 39 | $menuTitle = "Menu" 40 | ) 41 | $keycode = 0 42 | $pos = 0 43 | Draw-Menu $menuItems $pos $menuTitle 44 | while ($keycode -ne 13) { 45 | $press = $host.ui.rawui.readkey("NoEcho,IncludeKeyDown") 46 | $keycode = $press.virtualkeycode 47 | Write-host "$($press.character)" -NoNewLine 48 | if ($keycode -eq 38) {$pos--} 49 | if ($keycode -eq 40) {$pos++} 50 | if ($pos -lt 0) {$pos = ($menuItems.length - 1)} 51 | if ($pos -ge $menuItems.length) {$pos = 0} 52 | Draw-Menu $menuItems $pos $menuTitle 53 | } 54 | return $($menuItems[$pos]) 55 | } -------------------------------------------------------------------------------- /Mini-u/Mini-u.ps1: -------------------------------------------------------------------------------- 1 | # Dependencies 2 | if (!(Get-Module -Name BoxyPrompt)) { 3 | Import-Module $PSScriptRoot\BoxyPrompt\BoxyPrompt.ps1 4 | } 5 | if (!(Get-Module -Name DrawMenu)) { 6 | Import-Module $PSScriptRoot\DrawMenu.ps1 7 | } 8 | 9 | function mini-u { 10 | <# 11 | .SYNOPSIS 12 | This function serves as an example of how I implement dynamic 13 | command line interface menus in PowerShell. To use this, run 14 | 'Import-Module .\Mini-u.ps1' from within this project's directory. 15 | .DESCRIPTION 16 | The main menu is a representation of the names of JSON files within 17 | the 'menus' directory with numbers respective to the amount of JSON 18 | files in this directory i.e., an array is dynamically created based 19 | on the .Count of the the items in 'menus'. When a selection is made 20 | from the main menu, a new menu is presented. This submenu is the 21 | contents of the selected JSON file, which is another menu. The logic 22 | is repeated for the submenu choice selection. 23 | 24 | BoxyPrompt.ps1 draws a box around a string to simply make it 25 | prettier. 26 | 27 | DrawMenu.ps1 allows the user to select menu options with the Up/Down 28 | arrow keys and make a selection with 'Enter'. 29 | .NOTES 30 | Version: v1.0 -- 07 Dec 2022 31 | v1.1 -- 23 Jun 2023 32 | Author: Lucas McGlamery 33 | .EXAMPLE 34 | PS> mini-u 35 | #> 36 | $MainMenu = (Get-Item $PSScriptRoot\menus\*).BaseName 37 | $SubMenuSelection = Menu $MainMenu "Main Menu" ; Clear-Host 38 | $MenuOptions = Get-Content -Path $PSScriptRoot\menus\$($SubMenuSelection)".json" | ConvertFrom-Json 39 | $MenuOptionSelection = Menu $MenuOptions.Name "Select a menu option" 40 | Write-Host $MenuOptionSelection 41 | } -------------------------------------------------------------------------------- /Mini-u/README.md: -------------------------------------------------------------------------------- 1 | [This directory now has a dedicated repository here](https://github.com/L-McG/mini-u) 2 | 3 | ![](https://github.com/L-McG/PowerShell/blob/master/Mini-u/Animation.gif) 4 | -------------------------------------------------------------------------------- /Mini-u/menus/AdministrativeTasks.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "Name": "Cleanup Hamburger", 4 | "BogusStuff": "Potato" 5 | }, 6 | { 7 | "Name": "Double-Double Yum Yum", 8 | "SomethingElse": "Whatever" 9 | }, 10 | { 11 | "Name": "CHEZBRGR", 12 | "NumberThree": 3 13 | } 14 | ] -------------------------------------------------------------------------------- /Mini-u/menus/GeneralTasks.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "Name": "Cleanup Garbage", 4 | "BogusStuff": "This is whatever you want", 5 | "ScriptText": "SomeFunctionInSomeModule", 6 | "Params": { 7 | "AccountName": "Maybe that function needs parameters", 8 | "InTheWeeds": "You can do a lot with JSON objects as menus" 9 | } 10 | }, 11 | { 12 | "Name": "Create The Garbage", 13 | "SomethingElse": "Whatever" 14 | }, 15 | { 16 | "Name": "Sell The Garbage", 17 | "Stuff": "One computer's trash is another computer's un-trash." 18 | } 19 | ] -------------------------------------------------------------------------------- /Mini-u/menus/InfrastructureTasks.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "Name": "Cleanup Potatoes", 4 | "BogusStuff": "Potato" 5 | }, 6 | { 7 | "Name": "Create Potatoes", 8 | "SomethingElse": "Fries" 9 | }, 10 | { 11 | "Name": "Sell Potatoes", 12 | "NumberThree": 3 13 | } 14 | ] -------------------------------------------------------------------------------- /SillyScripts/MockThem/Animation.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/L-McG/PowerShell/70c3abef8650b1753cf9ac4ad33f073de3d00482/SillyScripts/MockThem/Animation.gif -------------------------------------------------------------------------------- /SillyScripts/MockThem/MockThem.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Mock them! 4 | .DESCRIPTION 5 | This function iterates through the characters of a string and performs 6 | mock casing for letters. The output is piped to the clipboard for ease 7 | of delivery and returned to the console. 8 | .NOTES 9 | Version: v1.0 -- 5 Jan 2023 10 | Author: Lucas McGlamery 11 | .EXAMPLE 12 | PS> Mock-Them "That's not very nice of you" 13 | #> 14 | function Mock-Them { 15 | [CmdletBinding()] 16 | param ( 17 | [Parameter(Mandatory,ValueFromPipeline)] 18 | [string]$string 19 | ) 20 | 21 | begin { 22 | $i = 0 23 | $output = $null 24 | } 25 | 26 | process { 27 | foreach($character in $string.ToCharArray()) { 28 | if ($character -notmatch '^[a-zA-Z]') { 29 | $output += $character 30 | $i++ 31 | continue 32 | } 33 | if (++$i % 2) { 34 | $output += $character.ToString().ToUpper() 35 | } else { 36 | $output += $character.ToString().ToLower() 37 | } 38 | } 39 | } 40 | 41 | end { 42 | $output | clip 43 | return $output 44 | } 45 | } -------------------------------------------------------------------------------- /SillyScripts/MockThem/MockThemButBadCode.ps1: -------------------------------------------------------------------------------- 1 | function Mock-Them($str) { 2 | $out = $null 3 | $str.ToCharArray() | %{$out += if((Get-Random) % 2){$_.ToString().ToUpper()}else{$_.ToString().ToLower()}} 4 | return $out 5 | } -------------------------------------------------------------------------------- /SillyScripts/MockThem/README.md: -------------------------------------------------------------------------------- 1 | ![](https://github.com/L-McG/PowerShell/blob/master/SillyScripts/MockThem/Animation.gif) --------------------------------------------------------------------------------