diff --git a/bin/repair.ps1 b/bin/repair.ps1 new file mode 100644 index 0000000..61adc0c --- /dev/null +++ b/bin/repair.ps1 @@ -0,0 +1,487 @@ +# Mole - Repair Command +# System repair utilities for Windows (cache rebuilds, resets) + +#Requires -Version 5.1 +[CmdletBinding()] +param( + [switch]$DryRun, + [switch]$DebugMode, + [switch]$ShowHelp, + [switch]$All, + [switch]$DNS, + [switch]$Font, + [switch]$Icon, + [switch]$Search, + [switch]$Store +) + +Set-StrictMode -Version Latest +$ErrorActionPreference = "Stop" + +# Script location +$scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path +$libDir = Join-Path (Split-Path -Parent $scriptDir) "lib" + +# Import core modules +. "$libDir\core\base.ps1" +. "$libDir\core\log.ps1" +. "$libDir\core\ui.ps1" + +# ============================================================================ +# Configuration +# ============================================================================ + +$script:RepairsApplied = 0 +$script:IsDryRun = $DryRun -or ($env:MOLE_DRY_RUN -eq "1") + +# ============================================================================ +# Help +# ============================================================================ + +function Show-RepairHelp { + $esc = [char]27 + Write-Host "" + Write-Host "$esc[1;35mMole Repair$esc[0m - System repair utilities" + Write-Host "" + Write-Host "$esc[33mUsage:$esc[0m mole repair [options]" + Write-Host "" + Write-Host "$esc[33mOptions:$esc[0m" + Write-Host " -All Run all repairs" + Write-Host " -DNS Flush DNS cache" + Write-Host " -Font Rebuild font cache" + Write-Host " -Icon Rebuild icon cache" + Write-Host " -Search Reset Windows Search index" + Write-Host " -Store Reset Windows Store cache" + Write-Host "" + Write-Host " -DryRun Preview repairs without applying" + Write-Host " -DebugMode Enable debug logging" + Write-Host " -ShowHelp Show this help message" + Write-Host "" + Write-Host "$esc[33mExamples:$esc[0m" + Write-Host " mole repair -DNS Flush DNS cache" + Write-Host " mole repair -Icon -Font Rebuild icon and font caches" + Write-Host " mole repair -All Run all repairs" + Write-Host "" +} + +# ============================================================================ +# Repair Functions +# ============================================================================ + +function Repair-DnsCache { + <# + .SYNOPSIS + Flush DNS resolver cache + .DESCRIPTION + Clears the DNS client cache, forcing fresh DNS lookups. + Useful when DNS records have changed or you're having connectivity issues. + #> + + $esc = [char]27 + + Write-Host "" + Write-Host "$esc[34m$($script:Icons.Arrow) DNS Cache Flush$esc[0m" + + if ($script:IsDryRun) { + Write-Host " $esc[33m$($script:Icons.DryRun)$esc[0m Would flush DNS cache" + $script:RepairsApplied++ + return + } + + try { + Clear-DnsClientCache -ErrorAction Stop + Write-Host " $esc[32m$($script:Icons.Success)$esc[0m DNS cache flushed successfully" + $script:RepairsApplied++ + } + catch { + Write-Host " $esc[31m$($script:Icons.Error)$esc[0m Could not flush DNS cache: $_" + } +} + +function Repair-FontCache { + <# + .SYNOPSIS + Rebuild Windows font cache + .DESCRIPTION + Stops the font cache service, clears the cache files, and restarts. + Fixes issues with fonts not displaying correctly or missing fonts. + #> + + $esc = [char]27 + + Write-Host "" + Write-Host "$esc[34m$($script:Icons.Arrow) Font Cache Rebuild$esc[0m" + + if (-not (Test-IsAdmin)) { + Write-Host " $esc[33m$($script:Icons.Warning)$esc[0m Requires administrator privileges" + return + } + + # Font cache locations + $fontCachePaths = @( + "$env:LOCALAPPDATA\Microsoft\Windows\Fonts" + "$env:WINDIR\ServiceProfiles\LocalService\AppData\Local\FontCache" + "$env:WINDIR\System32\FNTCACHE.DAT" + ) + + if ($script:IsDryRun) { + Write-Host " $esc[33m$($script:Icons.DryRun)$esc[0m Would stop Windows Font Cache Service" + Write-Host " $esc[33m$($script:Icons.DryRun)$esc[0m Would delete font cache files" + Write-Host " $esc[33m$($script:Icons.DryRun)$esc[0m Would restart Windows Font Cache Service" + $script:RepairsApplied++ + return + } + + try { + # Stop font cache service + Write-Host " $esc[90mStopping Font Cache Service...$esc[0m" + Stop-Service -Name "FontCache" -Force -ErrorAction SilentlyContinue + Stop-Service -Name "FontCache3.0.0.0" -Force -ErrorAction SilentlyContinue + + # Wait a moment for service to stop + Start-Sleep -Seconds 2 + + # Delete font cache files + foreach ($path in $fontCachePaths) { + if (Test-Path $path) { + if (Test-Path $path -PathType Container) { + # Directory - clear contents + Get-ChildItem -Path $path -Recurse -Force -ErrorAction SilentlyContinue | + Remove-Item -Force -Recurse -ErrorAction SilentlyContinue + } + else { + # File - delete it + Remove-Item -Path $path -Force -ErrorAction SilentlyContinue + } + } + } + + # Restart font cache service + Write-Host " $esc[90mRestarting Font Cache Service...$esc[0m" + Start-Service -Name "FontCache" -ErrorAction SilentlyContinue + Start-Service -Name "FontCache3.0.0.0" -ErrorAction SilentlyContinue + + Write-Host " $esc[32m$($script:Icons.Success)$esc[0m Font cache rebuilt successfully" + Write-Host " $esc[90mNote: Some apps may need restart to see changes$esc[0m" + $script:RepairsApplied++ + } + catch { + Write-Host " $esc[31m$($script:Icons.Error)$esc[0m Could not rebuild font cache: $_" + # Try to restart services even if we failed + Start-Service -Name "FontCache" -ErrorAction SilentlyContinue + } +} + +function Repair-IconCache { + <# + .SYNOPSIS + Rebuild Windows icon cache + .DESCRIPTION + Clears the icon cache database files, forcing Windows to rebuild them. + Fixes issues with missing, corrupted, or outdated icons. + #> + + $esc = [char]27 + + Write-Host "" + Write-Host "$esc[34m$($script:Icons.Arrow) Icon Cache Rebuild$esc[0m" + + # Icon cache locations + $iconCachePath = "$env:LOCALAPPDATA\Microsoft\Windows\Explorer" + $thumbCachePath = "$env:LOCALAPPDATA\Microsoft\Windows\Explorer" + + if ($script:IsDryRun) { + Write-Host " $esc[33m$($script:Icons.DryRun)$esc[0m Would stop Explorer" + Write-Host " $esc[33m$($script:Icons.DryRun)$esc[0m Would delete icon cache files (iconcache_*.db)" + Write-Host " $esc[33m$($script:Icons.DryRun)$esc[0m Would restart Explorer" + $script:RepairsApplied++ + return + } + + try { + Write-Host " $esc[90mStopping Explorer...$esc[0m" + + # Kill explorer (will restart automatically, or we restart it) + Stop-Process -Name "explorer" -Force -ErrorAction SilentlyContinue + + # Wait for explorer to fully stop + Start-Sleep -Seconds 2 + + # Delete icon cache files + $iconCacheFiles = Get-ChildItem -Path $iconCachePath -Filter "iconcache_*.db" -Force -ErrorAction SilentlyContinue + $thumbCacheFiles = Get-ChildItem -Path $thumbCachePath -Filter "thumbcache_*.db" -Force -ErrorAction SilentlyContinue + + $deletedCount = 0 + foreach ($file in $iconCacheFiles) { + Remove-Item -Path $file.FullName -Force -ErrorAction SilentlyContinue + $deletedCount++ + } + + # Also clear thumbcache for good measure + foreach ($file in $thumbCacheFiles) { + Remove-Item -Path $file.FullName -Force -ErrorAction SilentlyContinue + $deletedCount++ + } + + # Also clear the system-wide icon cache + $systemIconCache = "$env:LOCALAPPDATA\IconCache.db" + if (Test-Path $systemIconCache) { + Remove-Item -Path $systemIconCache -Force -ErrorAction SilentlyContinue + $deletedCount++ + } + + Write-Host " $esc[90mRestarting Explorer...$esc[0m" + + # Restart explorer + Start-Process "explorer.exe" + + Write-Host " $esc[32m$($script:Icons.Success)$esc[0m Icon cache rebuilt ($deletedCount files cleared)" + Write-Host " $esc[90mNote: Icons will rebuild gradually as you browse$esc[0m" + $script:RepairsApplied++ + } + catch { + Write-Host " $esc[31m$($script:Icons.Error)$esc[0m Could not rebuild icon cache: $_" + # Make sure explorer is running + Start-Process "explorer.exe" -ErrorAction SilentlyContinue + } +} + +function Repair-SearchIndex { + <# + .SYNOPSIS + Reset Windows Search index + .DESCRIPTION + Stops the Windows Search service, deletes the search index, and restarts. + Fixes issues with search not finding files or returning incorrect results. + Note: Rebuilding the index can take hours depending on file count. + #> + + $esc = [char]27 + + Write-Host "" + Write-Host "$esc[34m$($script:Icons.Arrow) Windows Search Index Reset$esc[0m" + + if (-not (Test-IsAdmin)) { + Write-Host " $esc[33m$($script:Icons.Warning)$esc[0m Requires administrator privileges" + return + } + + $searchIndexPath = "$env:ProgramData\Microsoft\Search\Data\Applications\Windows" + + if ($script:IsDryRun) { + Write-Host " $esc[33m$($script:Icons.DryRun)$esc[0m Would stop Windows Search service" + Write-Host " $esc[33m$($script:Icons.DryRun)$esc[0m Would delete search index database" + Write-Host " $esc[33m$($script:Icons.DryRun)$esc[0m Would restart Windows Search service" + $script:RepairsApplied++ + return + } + + try { + Write-Host " $esc[90mStopping Windows Search service...$esc[0m" + Stop-Service -Name "WSearch" -Force -ErrorAction Stop + + # Wait for service to fully stop + Start-Sleep -Seconds 3 + + # Delete search index + if (Test-Path $searchIndexPath) { + Write-Host " $esc[90mDeleting search index...$esc[0m" + Remove-Item -Path "$searchIndexPath\*" -Recurse -Force -ErrorAction SilentlyContinue + } + + Write-Host " $esc[90mRestarting Windows Search service...$esc[0m" + Start-Service -Name "WSearch" -ErrorAction Stop + + Write-Host " $esc[32m$($script:Icons.Success)$esc[0m Search index reset successfully" + Write-Host " $esc[33m$($script:Icons.Warning)$esc[0m Indexing will rebuild in the background (may take hours)" + $script:RepairsApplied++ + } + catch { + Write-Host " $esc[31m$($script:Icons.Error)$esc[0m Could not reset search index: $_" + # Try to restart service + Start-Service -Name "WSearch" -ErrorAction SilentlyContinue + } +} + +function Repair-StoreCache { + <# + .SYNOPSIS + Reset Windows Store cache + .DESCRIPTION + Runs wsreset.exe to clear the Windows Store cache. + Fixes issues with Store apps not installing, updating, or launching. + #> + + $esc = [char]27 + + Write-Host "" + Write-Host "$esc[34m$($script:Icons.Arrow) Windows Store Cache Reset$esc[0m" + + if ($script:IsDryRun) { + Write-Host " $esc[33m$($script:Icons.DryRun)$esc[0m Would run wsreset.exe" + $script:RepairsApplied++ + return + } + + try { + Write-Host " $esc[90mResetting Windows Store cache...$esc[0m" + + # wsreset.exe clears the store cache and reopens the Store + $wsreset = Start-Process -FilePath "wsreset.exe" -PassThru -WindowStyle Hidden + + # Wait for it to complete (usually quick) + $wsreset.WaitForExit(30000) # 30 second timeout + + if ($wsreset.ExitCode -eq 0) { + Write-Host " $esc[32m$($script:Icons.Success)$esc[0m Windows Store cache reset successfully" + $script:RepairsApplied++ + } + else { + Write-Host " $esc[33m$($script:Icons.Warning)$esc[0m wsreset completed with code $($wsreset.ExitCode)" + $script:RepairsApplied++ + } + } + catch { + Write-Host " $esc[31m$($script:Icons.Error)$esc[0m Could not reset Store cache: $_" + } +} + +# ============================================================================ +# Interactive Menu +# ============================================================================ + +function Show-RepairMenu { + $esc = [char]27 + + $menuItems = @( + @{ Key = "1"; Label = "DNS Cache"; Desc = "Flush DNS resolver cache"; Action = { Repair-DnsCache } } + @{ Key = "2"; Label = "Font Cache"; Desc = "Rebuild font cache (Admin)"; Action = { Repair-FontCache } } + @{ Key = "3"; Label = "Icon Cache"; Desc = "Rebuild icon cache"; Action = { Repair-IconCache } } + @{ Key = "4"; Label = "Search Index"; Desc = "Reset Windows Search (Admin)"; Action = { Repair-SearchIndex } } + @{ Key = "5"; Label = "Store Cache"; Desc = "Reset Windows Store cache"; Action = { Repair-StoreCache } } + @{ Key = "A"; Label = "All Repairs"; Desc = "Run all of the above"; Action = { + Repair-DnsCache + Repair-FontCache + Repair-IconCache + Repair-SearchIndex + Repair-StoreCache + } } + @{ Key = "Q"; Label = "Quit"; Desc = "Exit"; Action = $null } + ) + + Write-Host "" + Write-Host "$esc[1;35m$($script:Icons.Mole) Mole Repair$esc[0m" + Write-Host "" + + if ($script:IsDryRun) { + Write-Host "$esc[33m$($script:Icons.DryRun) DRY RUN MODE$esc[0m - No changes will be made" + Write-Host "" + } + + Write-Host "$esc[90mSelect a repair to run:$esc[0m" + Write-Host "" + + foreach ($item in $menuItems) { + Write-Host " $esc[36m[$($item.Key)]$esc[0m $($item.Label) - $esc[90m$($item.Desc)$esc[0m" + } + + Write-Host "" + $choice = Read-Host "Choice" + + $selected = $menuItems | Where-Object { $_.Key -eq $choice.ToUpper() } + + if ($selected -and $selected.Action) { + & $selected.Action + + # Show summary + Write-Host "" + if ($script:RepairsApplied -gt 0) { + Write-Host "$esc[32m$($script:Icons.Success)$esc[0m $($script:RepairsApplied) repair(s) applied" + } + else { + Write-Host "$esc[90mNo repairs applied$esc[0m" + } + } + elseif ($choice.ToUpper() -eq "Q") { + return + } + else { + Write-Host "$esc[31mInvalid choice$esc[0m" + } +} + +# ============================================================================ +# Main Entry Point +# ============================================================================ + +function Main { + $esc = [char]27 + + # Enable debug if requested + if ($DebugMode) { + $env:MOLE_DEBUG = "1" + $DebugPreference = "Continue" + } + + # Show help + if ($ShowHelp) { + Show-RepairHelp + return + } + + # Check if any specific repair was requested + $specificRepair = $DNS -or $Font -or $Icon -or $Search -or $Store -or $All + + if (-not $specificRepair) { + # No specific repair requested - show interactive menu + Show-RepairMenu + return + } + + # Run specific repairs + Write-Host "" + Write-Host "$esc[1;35m$($script:Icons.Mole) Mole Repair$esc[0m" + + if ($script:IsDryRun) { + Write-Host "" + Write-Host "$esc[33m$($script:Icons.DryRun) DRY RUN MODE$esc[0m - No changes will be made" + } + + if ($All -or $DNS) { + Repair-DnsCache + } + + if ($All -or $Font) { + Repair-FontCache + } + + if ($All -or $Icon) { + Repair-IconCache + } + + if ($All -or $Search) { + Repair-SearchIndex + } + + if ($All -or $Store) { + Repair-StoreCache + } + + # Show summary + Write-Host "" + if ($script:RepairsApplied -gt 0) { + if ($script:IsDryRun) { + Write-Host "$esc[33m$($script:Icons.DryRun)$esc[0m $($script:RepairsApplied) repair(s) would be applied" + } + else { + Write-Host "$esc[32m$($script:Icons.Success)$esc[0m $($script:RepairsApplied) repair(s) applied successfully" + } + } + else { + Write-Host "$esc[90mNo repairs applied$esc[0m" + } + Write-Host "" +} + +# Run main +Main diff --git a/mole.ps1 b/mole.ps1 index f5c5eab..ad904d4 100644 --- a/mole.ps1 +++ b/mole.ps1 @@ -62,6 +62,7 @@ function Show-MainHelp { Write-Host " ${cyan}analyze${nc} Visual disk space analyzer" Write-Host " ${cyan}status${nc} Real-time system monitor" Write-Host " ${cyan}optimize${nc} System optimization tasks" + Write-Host " ${cyan}repair${nc} Cache rebuilds and system fixes" Write-Host " ${cyan}purge${nc} Clean project build artifacts" Write-Host "" Write-Host " ${green}OPTIONS:${nc}" @@ -78,6 +79,8 @@ function Show-MainHelp { Write-Host " ${gray}mole analyze${nc} ${gray}# Disk analyzer${nc}" Write-Host " ${gray}mole status${nc} ${gray}# System monitor${nc}" Write-Host " ${gray}mole optimize${nc} ${gray}# Optimize system${nc}" + Write-Host " ${gray}mole repair -DNS${nc} ${gray}# Flush DNS cache${nc}" + Write-Host " ${gray}mole repair -All${nc} ${gray}# Run all repairs${nc}" Write-Host " ${gray}mole purge${nc} ${gray}# Clean dev artifacts${nc}" Write-Host "" Write-Host " ${green}ENVIRONMENT:${nc}" @@ -125,6 +128,12 @@ function Show-MainMenu { Command = "optimize" Icon = $script:Icons.Arrow } + @{ + Name = "Repair" + Description = "Cache rebuilds & fixes" + Command = "repair" + Icon = $script:Icons.Admin + } @{ Name = "Purge" Description = "Clean dev artifacts"