public/Invoke-Octa.ps1
|
function Wait-OctaKeypress { <# Shared "press any key to return to the menu" step after running a category/tool - factored out so every action site (categories, tools, Quick Clean, Undo, Help) uses the exact same prompt instead of repeating it. #> param([Parameter(Mandatory)]$Strings) Write-Host '' Write-Host -NoNewline $Strings.pressKeyToContinue [Console]::ReadKey($true) | Out-Null } function Invoke-Octa { <# .SYNOPSIS Interactive entry point: language menu (first run) -> banner + main menu -> dispatch, looping back to the menu after each action so the whole session (every category, the built-in tools, undo) happens from this one running terminal - the user never needs to re-invoke bin/octa.ps1 with a different flag. FR-018, FR-022, FR-023. 009/010: categories and built-in tools are grouped (main menu -> group picker -> leaf picker) instead of one flat 32-item list, following real user feedback that a flat list got overwhelming as more categories/tools were added. Running a leaf item returns to the group screen it was picked from, not all the way back to the top-level main menu. ponytail: direct single-keypress shortcuts are guaranteed unique for items 1-9 within any one screen (main menu, a group picker, or a leaf picker never has more than 9 items at once); items 10+ are still always reachable via Up/Down + Enter, just without a guaranteed single-digit direct key. #> [CmdletBinding()] param() $strings = Get-OctaStrings # -SkipRiskScan: this menu never displays HighestRiskLevel (only DisplayName/Description), # so the ~20s it took to live-scan all 20 categories just to compute a badge nothing read # was pure waste - see Get-OctaCategory's own comment for how this was found. $categories = @(Get-OctaCategory -SkipRiskScan) $categoryGroups = @( [pscustomobject]@{ Key = '1'; Label = $strings.groupPrivacyAi; Description = $strings.groupPrivacyAiDesc; Ids = @('telemetry', 'background-activity', 'copilot', 'recall', 'ai-features') } [pscustomobject]@{ Key = '2'; Label = $strings.groupBloatware; Description = $strings.groupBloatwareDesc; Ids = @('appx', 'oem-suites', 'onedrive', 'widgets') } [pscustomobject]@{ Key = '3'; Label = $strings.groupPerformance; Description = $strings.groupPerformanceDesc; Ids = @('performance', 'power', 'gpu', 'services') } [pscustomobject]@{ Key = '4'; Label = $strings.groupDesktop; Description = $strings.groupDesktopDesc; Ids = @('explorer-start', 'desktop', 'preferences', 'user-experience', 'gaming') } [pscustomobject]@{ Key = '5'; Label = $strings.groupAdvanced; Description = $strings.groupAdvancedDesc; Ids = @('windows-features', 'registry-orphans') } ) $toolCatalog = @( [pscustomobject]@{ Id = 'disk-cleanup'; Label = $strings.menuDiskCleanup; Description = $strings.descDiskCleanup; Action = { Invoke-OctaDiskCleanup | Out-Null } } [pscustomobject]@{ Id = 'disk-usage'; Label = $strings.menuDiskUsage; Description = $strings.descDiskUsage; Action = { Show-OctaDiskUsage | Out-Null } } [pscustomobject]@{ Id = 'disk-health'; Label = $strings.menuDiskHealth; Description = $strings.descDiskHealth; Action = { Show-OctaDiskHealth | Out-Null } } [pscustomobject]@{ Id = 'uninstaller'; Label = $strings.menuUninstaller; Description = $strings.descUninstaller; Action = { Invoke-OctaUninstaller | Out-Null } } [pscustomobject]@{ Id = 'startup-manager'; Label = $strings.menuStartupManager; Description = $strings.descStartupManager; Action = { Invoke-OctaStartupManager | Out-Null } } [pscustomobject]@{ Id = 'tasks'; Label = $strings.menuTasks; Description = $strings.descTasks; Action = { Invoke-OctaTaskBrowser | Out-Null } } [pscustomobject]@{ Id = 'scheduler'; Label = $strings.menuScheduler; Description = $strings.descScheduler; Action = { Invoke-OctaScheduler | Out-Null } } [pscustomobject]@{ Id = 'software-updater'; Label = $strings.menuSoftwareUpdater; Description = $strings.descSoftwareUpdater; Action = { Invoke-OctaSoftwareUpdater | Out-Null } } [pscustomobject]@{ Id = 'dashboard'; Label = $strings.menuDashboard; Description = $strings.descDashboard; Action = { Show-OctaDashboard | Out-Null } } [pscustomobject]@{ Id = 'history'; Label = $strings.menuHistory; Description = $strings.descHistory; Action = { Show-OctaHistory | Out-Null } } [pscustomobject]@{ Id = 'network-cleanup'; Label = $strings.menuNetworkCleanup; Description = $strings.descNetworkCleanup; Action = { Invoke-OctaNetworkCleanup | Out-Null } } [pscustomobject]@{ Id = 'malware-scan'; Label = $strings.menuMalwareScan; Description = $strings.descMalwareScan; Action = { Invoke-OctaMalwareScan | Format-List } } ) $toolGroups = @( [pscustomobject]@{ Key = '1'; Label = $strings.groupDiskStorage; Description = $strings.groupDiskStorageDesc; ToolIds = @('disk-cleanup', 'disk-usage', 'disk-health', 'uninstaller') } [pscustomobject]@{ Key = '2'; Label = $strings.groupSystemMgmt; Description = $strings.groupSystemMgmtDesc; ToolIds = @('startup-manager', 'tasks', 'scheduler', 'software-updater') } [pscustomobject]@{ Key = '3'; Label = $strings.groupInfoHistory; Description = $strings.groupInfoHistoryDesc; ToolIds = @('dashboard', 'history') } [pscustomobject]@{ Key = '4'; Label = $strings.groupNetworkSecurity; Description = $strings.groupNetworkSecurityDesc; ToolIds = @('network-cleanup', 'malware-scan') } ) while ($true) { $mainItems = @( [pscustomobject]@{ Key = '1'; Label = $strings.menuCategories; Description = $strings.menuCategoriesDesc } [pscustomobject]@{ Key = '2'; Label = $strings.menuTools; Description = $strings.menuToolsDesc } [pscustomobject]@{ Key = 'q'; Label = $strings.menuQuickClean; Description = $strings.menuQuickCleanDesc } [pscustomobject]@{ Key = 'u'; Label = $strings.menuUndo; Description = $strings.menuUndoDesc } [pscustomobject]@{ Key = 'l'; Label = $strings.menuLanguage; Description = $strings.menuLanguageDesc } [pscustomobject]@{ Key = 'h'; Label = $strings.menuHelp; Description = $strings.menuHelpDesc } [pscustomobject]@{ Key = 'x'; Label = $strings.menuExit; Description = $strings.menuExitDesc } ) $choice = Show-OctaMenu -Items $mainItems -Header $strings.mainMenuHeader -NavHint $strings.menuNavHint switch ($choice) { '1' { while ($true) { $groupItems = @($categoryGroups | ForEach-Object { [pscustomobject]@{ Key = $_.Key; Label = $_.Label; Description = $_.Description } }) $groupItems += [pscustomobject]@{ Key = 'b'; Label = $strings.menuBack; Description = '' } $groupChoice = Show-OctaMenu -Items $groupItems -Header $strings.categoryGroupHeader -NavHint $strings.menuNavHint if ($groupChoice -eq 'b') { break } $group = $categoryGroups | Where-Object { $_.Key -eq $groupChoice } while ($true) { $leafCategories = @($categories | Where-Object { $_.Id -in $group.Ids }) $leafItems = @() for ($i = 0; $i -lt $leafCategories.Count; $i++) { $leafItems += [pscustomobject]@{ Key = ($i + 1).ToString(); Label = $leafCategories[$i].DisplayName; Description = $leafCategories[$i].Description } } $leafItems += [pscustomobject]@{ Key = 'b'; Label = $strings.menuBack; Description = '' } $leafChoice = Show-OctaMenu -Items $leafItems -Header $group.Label -NavHint $strings.menuNavHint if ($leafChoice -eq 'b') { break } $index = [int]$leafChoice - 1 if ($index -ge 0 -and $index -lt $leafCategories.Count) { Write-Host ($strings.runningHeader -f $leafCategories[$index].DisplayName) Invoke-OctaCategory -CategoryId $leafCategories[$index].Id -Apply | Format-List Wait-OctaKeypress -Strings $strings } } } } '2' { while ($true) { $groupItems = @($toolGroups | ForEach-Object { [pscustomobject]@{ Key = $_.Key; Label = $_.Label; Description = $_.Description } }) $groupItems += [pscustomobject]@{ Key = 'b'; Label = $strings.menuBack; Description = '' } $groupChoice = Show-OctaMenu -Items $groupItems -Header $strings.toolGroupHeader -NavHint $strings.menuNavHint if ($groupChoice -eq 'b') { break } $group = $toolGroups | Where-Object { $_.Key -eq $groupChoice } while ($true) { $leafTools = @($toolCatalog | Where-Object { $_.Id -in $group.ToolIds }) $leafItems = @() for ($i = 0; $i -lt $leafTools.Count; $i++) { $leafItems += [pscustomobject]@{ Key = ($i + 1).ToString(); Label = $leafTools[$i].Label; Description = $leafTools[$i].Description } } $leafItems += [pscustomobject]@{ Key = 'b'; Label = $strings.menuBack; Description = '' } $leafChoice = Show-OctaMenu -Items $leafItems -Header $group.Label -NavHint $strings.menuNavHint if ($leafChoice -eq 'b') { break } $index = [int]$leafChoice - 1 if ($index -ge 0 -and $index -lt $leafTools.Count) { Write-Host ($strings.runningHeader -f $leafTools[$index].Label) & $leafTools[$index].Action Wait-OctaKeypress -Strings $strings } } } } 'q' { Invoke-OctaQuickClean -Apply | Format-List Wait-OctaKeypress -Strings $strings } 'u' { Undo-OctaRun -RunId 'latest' | Format-List Wait-OctaKeypress -Strings $strings } 'l' { $culture = Show-OctaLanguageMenu Set-OctaLanguage -Culture $culture $strings = Get-OctaStrings } 'h' { Write-Host 'https://github.com/jpiribe/octa (see README for full reference)' Wait-OctaKeypress -Strings $strings } 'x' { return } } } } |