WinMole.ps1
|
#Requires -Version 7.0 <# .SYNOPSIS WinMole - Deep clean and optimize your Windows PC. .DESCRIPTION WinMole is a PowerShell-based system maintenance toolkit for Windows, inspired by the macOS Mole tool. It provides deep cleaning, smart uninstalling, disk analysis, system optimization, live status monitoring, and project artifact cleanup — all from a single command. .PARAMETER Command The subcommand to run: clean, uninstall, optimize, analyze, status, purge, update, remove, or help. Omit to show the interactive menu. .PARAMETER DryRun Preview what would be done without making any changes. .PARAMETER Debug Show detailed operation logs. .PARAMETER Json Output results as JSON (supported by: analyze, status). .PARAMETER Path Path for the analyze command. .PARAMETER Whitelist Manage the protection whitelist (supported by: clean). .PARAMETER Paths Configure scan paths (supported by: purge). .PARAMETER Version Show the installed version and exit. .PARAMETER Help Show this help message and exit. .EXAMPLE mo # Interactive menu mo clean # Deep system cleanup mo clean --dry-run # Preview cleanup mo uninstall # Remove apps + leftovers mo optimize # Refresh caches & services mo analyze # Visual disk explorer mo analyze C:\Users # Analyze specific path mo status # Live system dashboard mo status --json # Machine-readable output mo purge # Clean project build artifacts mo purge --paths # Configure scan directories .NOTES Version : 1.0.0 Author : WinMole contributors License : MIT #> param( [Parameter(Position = 0)] [string]$Command = '', [Parameter(Position = 1)] [string]$Arg1 = '', [Alias('dry-run')] [switch]$DryRun, [switch]$DebugMode, [switch]$Json, [string]$Path = '', [switch]$Whitelist, [switch]$Paths, [switch]$Version, [Alias('h')] [switch]$Help, # status options [double]$ProcCpuThreshold = 50.0, [int]$ProcCpuWindow = 10, [switch]$NoProcCpuAlerts ) $ErrorActionPreference = 'SilentlyContinue' Set-StrictMode -Off # relax for interactive use # ── Locate WinMole root ─────────────────────────────────────────────────────── $script:WINMOLE_ROOT = $PSScriptRoot # ── Load core library ───────────────────────────────────────────────────────── $corePath = Join-Path $script:WINMOLE_ROOT 'lib\core.ps1' if (-not (Test-Path $corePath)) { Write-Error "WinMole core library not found at: $corePath" exit 1 } . $corePath # ── Map 'analyse' alias ─────────────────────────────────────────────────────── if ($Command -eq 'analyse') { $Command = 'analyze' } # ── Dispatch table ──────────────────────────────────────────────────────────── function Invoke-Command { param([string]$Cmd) $binDir = Join-Path $script:WINMOLE_ROOT 'bin' switch ($Cmd.ToLower()) { 'clean' { & "$binDir\clean.ps1" ` -DryRun:$DryRun ` -Debug:$DebugMode ` -Whitelist:$Whitelist } 'uninstall' { & "$binDir\uninstall.ps1" ` -DryRun:$DryRun } 'optimize' { & "$binDir\optimize.ps1" ` -DryRun:$DryRun ` -Debug:$DebugMode } 'analyze' { $analyzePath = if ($Arg1) { $Arg1 } elseif ($Path) { $Path } else { '' } & "$binDir\analyze.ps1" ` -Path $analyzePath ` -Json:$Json } 'status' { & "$binDir\status.ps1" ` -Json:$Json ` -ProcCpuThreshold $ProcCpuThreshold ` -ProcCpuWindow $ProcCpuWindow ` -NoProcCpuAlerts:$NoProcCpuAlerts } 'purge' { & "$binDir\purge.ps1" ` -DryRun:$DryRun ` -Paths:$Paths } 'update' { Invoke-Update } 'remove' { Invoke-Remove -DryRun:$DryRun } default { Write-Err "Unknown command: $Cmd" Write-SpectreHost " Run [deepskyblue1]mo --help[/] to see available commands." exit 1 } } } # ── Interactive main menu ───────────────────────────────────────────────────── function Show-MainMenu { . (Join-Path $script:WINMOLE_ROOT 'lib\ui.ps1') $info = Get-SysInfoSummary Write-Host "" Write-SpectreHost " [bold deepskyblue1]WinMole[/] [grey]v$script:WINMOLE_VERSION — $(Esc $info.MachineName) · $(Esc ($info.OSCaption -replace 'Microsoft ',''))[/]" Write-SpectreHost " [grey]RAM: $($info.RamUsedGB)/$($info.RamTotalGB)GB | Disk: $($info.DiskUsedGB)/$($info.DiskTotalGB)GB | Uptime: $($info.Uptime)[/]" Write-Host "" $options = @( 'clean — Deep system cleanup', 'uninstall — Remove apps + leftovers', 'optimize — Refresh caches & services', 'analyze — Visual disk explorer', 'status — Live system dashboard', 'purge — Clean project artifacts', '──────────────────────────────────', 'update — Update WinMole', 'remove — Uninstall WinMole', 'help — Show all commands' ) $selected = Show-SelectMenu -Title 'Choose a command' -Options $options if ($selected -lt 0) { return } # Map selection index to command, skipping separator $cmdMap = @('clean','uninstall','optimize','analyze','status','purge',$null,'update','remove','help') $cmd = $cmdMap[$selected] if (-not $cmd) { Show-MainMenu; return } if ($cmd -eq 'help') { Show-Help; return } Write-Host "" Invoke-Command -Cmd $cmd } # ── Help text ───────────────────────────────────────────────────────────────── function Show-Help { Write-Host "" Write-SpectreHost " [bold deepskyblue1]WinMole[/] v$script:WINMOLE_VERSION — Deep clean and optimize your Windows PC" Write-Host "" Write-SpectreHost " [bold]USAGE[/]" Write-SpectreHost " mo [grey][[command]] [[options]][/]" Write-Host "" Write-SpectreHost " [bold]COMMANDS[/]" $cmds = @( @('mo ', 'Interactive menu'), @('mo clean ', 'Deep system cleanup (temp, browser, dev caches, Recycle Bin)'), @('mo uninstall ', 'Smart app uninstaller with leftover cleanup'), @('mo optimize ', 'System optimization (DNS, WU cache, event logs, etc.)'), @('mo analyze [[path]] ', 'Interactive disk space explorer'), @('mo status ', 'Live system health dashboard'), @('mo purge ', 'Clean project build artifacts'), @('mo update ', 'Update WinMole to latest version'), @('mo remove ', 'Remove WinMole from system') ) foreach ($c in $cmds) { Write-SpectreHost " [deepskyblue1]$($c[0])[/][grey]$($c[1])[/]" } Write-Host "" Write-SpectreHost " [bold]OPTIONS[/]" $opts = @( @('--dry-run ', 'Preview changes without deleting anything'), @('--debug ', 'Show detailed operation logs'), @('--json ', 'Machine-readable JSON output (analyze, status)'), @('--whitelist ', 'Manage protected paths (clean)'), @('--paths ', 'Configure scan directories (purge)'), @('--version ', 'Show installed version'), @('--help ', 'Show this help message') ) foreach ($o in $opts) { Write-SpectreHost " [yellow]$($o[0])[/][grey]$($o[1])[/]" } Write-Host "" Write-SpectreHost " [bold]EXAMPLES[/]" Write-SpectreHost " [grey]mo clean --dry-run # Preview cleanup plan[/]" Write-SpectreHost " [grey]mo clean --dry-run --debug # Preview with risk detail[/]" Write-SpectreHost " [grey]mo analyze C:\Users\me # Analyze specific path[/]" Write-SpectreHost " [grey]mo purge --paths # Configure project dirs[/]" Write-SpectreHost " [grey]mo clean --whitelist # Manage protected paths[/]" Write-Host "" Write-SpectreHost " [grey]Logs:[/] $(Esc $script:LOG_FILE)" Write-SpectreHost " [grey]Config:[/] $(Esc $script:WINMOLE_CONFIG)" Write-Host "" } # ── Self-update ─────────────────────────────────────────────────────────────── function Invoke-Update { Write-Header -Title 'WinMole Update' $currentVersion = $script:WINMOLE_VERSION Write-Info "Current version: v$currentVersion" $isGalleryInstall = $null -ne (Get-InstalledModule -Name WinMole -ErrorAction SilentlyContinue) if (-not $isGalleryInstall) { Write-Warn "WinMole was not installed from the PowerShell Gallery." Write-Info "Install from the gallery to enable updates:" Write-SpectreHost " [deepskyblue1]Install-Module -Name WinMole -Scope CurrentUser[/]" return } Write-Info "Checking PowerShell Gallery for updates..." try { $gallery = Find-Module -Name WinMole -ErrorAction Stop $latestVersion = $gallery.Version if ([version]$latestVersion -le [version]$currentVersion) { Write-Success "Already up to date (v$currentVersion)." return } Write-Info "Updating v$currentVersion → v$latestVersion..." Update-Module -Name WinMole -Force -Scope CurrentUser Write-Success "Updated to v$latestVersion." Write-SpectreHost " [grey]Restart your terminal to use the new version.[/]" } catch { Write-Err "Update failed: $_" Write-Info "Try manually: Update-Module -Name WinMole -Force" } } # ── Self-remove ─────────────────────────────────────────────────────────────── function Invoke-Remove { param([switch]$DryRun) Write-Header -Title 'WinMole Remove' $isGalleryInstall = $null -ne (Get-InstalledModule -Name WinMole -ErrorAction SilentlyContinue) if ($isGalleryInstall) { $installed = Get-InstalledModule -Name WinMole Write-SpectreHost " Installed via PowerShell Gallery: [gold1]v$($installed.Version)[/]" } else { Write-SpectreHost " Installed at: [gold1]$(Esc $script:WINMOLE_ROOT)[/]" } Write-Host "" if ($DryRun) { if ($isGalleryInstall) { Write-Info "Dry run — would run: Uninstall-Module -Name WinMole -AllVersions -Force" } else { Write-Info "Dry run — would remove: $($script:WINMOLE_ROOT)" } Write-Info "Would clean up any legacy PATH and profile entries." return } if (-not (Confirm-Action -Message 'Proceed with removal?')) { Write-SpectreHost " [grey]Cancelled.[/]" Write-Host "" return } if ($isGalleryInstall) { try { Remove-Module -Name WinMole -Force -ErrorAction SilentlyContinue Uninstall-Module -Name WinMole -AllVersions -Force Write-Success "WinMole module uninstalled." } catch { Write-Warn "Could not uninstall module: $_" Write-Info "Try manually: Uninstall-Module -Name WinMole -AllVersions -Force" } } else { try { Remove-Item -LiteralPath $script:WINMOLE_ROOT -Recurse -Force Write-Success "Removed $($script:WINMOLE_ROOT)" } catch { Write-Warn "Could not remove $($script:WINMOLE_ROOT) — $_" Write-Info "You may need to manually delete: $($script:WINMOLE_ROOT)" } } # Clean up legacy PATH and profile entries from git-based installs $currentPath = [System.Environment]::GetEnvironmentVariable('PATH', 'User') if ($currentPath -like '*WinMole*') { $newPath = ($currentPath -split ';' | Where-Object { $_ -notlike '*WinMole*' }) -join ';' [System.Environment]::SetEnvironmentVariable('PATH', $newPath, 'User') Write-Success "Removed legacy PATH entry" } foreach ($prof in @($PROFILE.CurrentUserAllHosts, $PROFILE.CurrentUserCurrentHost)) { if (Test-Path $prof) { $content = Get-Content $prof -Raw -ErrorAction SilentlyContinue if ($content -match 'WinMole BEGIN') { $newContent = $content -replace '(?ms)# WinMole BEGIN.*?# WinMole END\r?\n?', '' Set-Content -Path $prof -Value $newContent.TrimEnd() Write-Success "Removed legacy profile entry" } } } Write-Host "" Write-Success "WinMole removed successfully." Write-SpectreHost " [grey]Restart your terminal to complete removal.[/]" Write-Host "" } # ── Entry point ─────────────────────────────────────────────────────────────── if ($Version) { Write-Host "WinMole $script:WINMOLE_VERSION" exit 0 } if ($Help -or $Command -eq '--help' -or $Command -eq 'help') { Show-Help exit 0 } if (-not $Command) { Show-MainMenu } else { Invoke-Command -Cmd $Command } |