1
0
mirror of https://github.com/tw93/Mole.git synced 2026-02-15 09:20:08 +00:00

feat(windows): add Windows support Phase 2 - cleanup features

Add cleanup modules and command scripts for Windows:
- lib/clean: user, caches, dev, apps, system cleanup modules
- bin/clean: deep cleanup orchestrator with dry-run and whitelist
- bin/uninstall: interactive app uninstaller
- bin/optimize: system optimization and health checks
- bin/purge: project artifact cleanup

All scripts support dry-run mode and follow safe deletion practices.
This commit is contained in:
Bhadra
2026-01-08 15:46:45 +05:30
parent a53b48ef3b
commit 6e0d850d6a
10 changed files with 4174 additions and 0 deletions

429
windows/lib/clean/apps.ps1 Normal file
View File

@@ -0,0 +1,429 @@
# Mole - Application-Specific Cleanup Module
# Cleans leftover data from uninstalled apps and app-specific caches
#Requires -Version 5.1
Set-StrictMode -Version Latest
# Prevent multiple sourcing
if ((Get-Variable -Name 'MOLE_CLEAN_APPS_LOADED' -Scope Script -ErrorAction SilentlyContinue) -and $script:MOLE_CLEAN_APPS_LOADED) { return }
$script:MOLE_CLEAN_APPS_LOADED = $true
# Import dependencies
$scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
. "$scriptDir\..\core\base.ps1"
. "$scriptDir\..\core\log.ps1"
. "$scriptDir\..\core\file_ops.ps1"
# ============================================================================
# Orphaned App Data Detection
# ============================================================================
function Get-InstalledPrograms {
<#
.SYNOPSIS
Get list of installed programs from registry
#>
$programs = @()
$registryPaths = @(
"HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*"
"HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*"
"HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*"
)
foreach ($path in $registryPaths) {
$items = Get-ItemProperty -Path $path -ErrorAction SilentlyContinue |
Where-Object { $_.DisplayName } |
Select-Object DisplayName, InstallLocation, Publisher
if ($items) {
$programs += $items
}
}
# Also check UWP apps
try {
$uwpApps = Get-AppxPackage -ErrorAction SilentlyContinue |
Select-Object @{N='DisplayName';E={$_.Name}}, @{N='InstallLocation';E={$_.InstallLocation}}, Publisher
if ($uwpApps) {
$programs += $uwpApps
}
}
catch {
Write-Debug "Could not enumerate UWP apps: $_"
}
return $programs
}
function Find-OrphanedAppData {
<#
.SYNOPSIS
Find app data folders for apps that are no longer installed
#>
param([int]$DaysOld = 60)
$installedPrograms = Get-InstalledPrograms
$installedNames = $installedPrograms | ForEach-Object { $_.DisplayName.ToLower() }
$orphanedPaths = @()
$cutoffDate = (Get-Date).AddDays(-$DaysOld)
# Check common app data locations
$appDataPaths = @(
@{ Path = $env:APPDATA; Type = "Roaming" }
@{ Path = $env:LOCALAPPDATA; Type = "Local" }
)
foreach ($location in $appDataPaths) {
if (-not (Test-Path $location.Path)) { continue }
$folders = Get-ChildItem -Path $location.Path -Directory -ErrorAction SilentlyContinue
foreach ($folder in $folders) {
# Skip system folders
$skipFolders = @('Microsoft', 'Windows', 'Packages', 'Programs', 'Temp', 'Roaming')
if ($folder.Name -in $skipFolders) { continue }
# Skip if recently modified
if ($folder.LastWriteTime -gt $cutoffDate) { continue }
# Check if app is installed
$isInstalled = $false
foreach ($name in $installedNames) {
if ($name -like "*$($folder.Name.ToLower())*" -or $folder.Name.ToLower() -like "*$name*") {
$isInstalled = $true
break
}
}
if (-not $isInstalled) {
$orphanedPaths += @{
Path = $folder.FullName
Name = $folder.Name
Type = $location.Type
Size = (Get-PathSize -Path $folder.FullName)
LastModified = $folder.LastWriteTime
}
}
}
}
return $orphanedPaths
}
function Clear-OrphanedAppData {
<#
.SYNOPSIS
Clean orphaned application data
#>
param([int]$DaysOld = 60)
Start-Section "Orphaned app data"
$orphaned = Find-OrphanedAppData -DaysOld $DaysOld
if ($orphaned.Count -eq 0) {
Write-Info "No orphaned app data found"
Stop-Section
return
}
# Filter by size (only clean if > 10MB to avoid noise)
$significantOrphans = $orphaned | Where-Object { $_.Size -gt 10MB }
if ($significantOrphans.Count -gt 0) {
$totalSize = ($significantOrphans | Measure-Object -Property Size -Sum).Sum
$sizeHuman = Format-ByteSize -Bytes $totalSize
Write-Info "Found $($significantOrphans.Count) orphaned folders ($sizeHuman)"
foreach ($orphan in $significantOrphans) {
$orphanSize = Format-ByteSize -Bytes $orphan.Size
Remove-SafeItem -Path $orphan.Path -Description "$($orphan.Name) ($orphanSize)" -Recurse
}
}
Stop-Section
}
# ============================================================================
# Specific Application Cleanup
# ============================================================================
function Clear-OfficeCache {
<#
.SYNOPSIS
Clean Microsoft Office caches and temp files
#>
$officeCachePaths = @(
# Office 365 / 2019 / 2021
"$env:LOCALAPPDATA\Microsoft\Office\16.0\OfficeFileCache"
"$env:LOCALAPPDATA\Microsoft\Office\16.0\Wef"
"$env:LOCALAPPDATA\Microsoft\Outlook\RoamCache"
"$env:LOCALAPPDATA\Microsoft\Outlook\Offline Address Books"
# Older Office versions
"$env:LOCALAPPDATA\Microsoft\Office\15.0\OfficeFileCache"
# Office temp files
"$env:APPDATA\Microsoft\Templates\*.tmp"
"$env:APPDATA\Microsoft\Word\*.tmp"
"$env:APPDATA\Microsoft\Excel\*.tmp"
"$env:APPDATA\Microsoft\PowerPoint\*.tmp"
)
foreach ($path in $officeCachePaths) {
if ($path -like "*.tmp") {
$parent = Split-Path -Parent $path
if (Test-Path $parent) {
$tmpFiles = Get-ChildItem -Path $parent -Filter "*.tmp" -File -ErrorAction SilentlyContinue
if ($tmpFiles) {
$paths = $tmpFiles | ForEach-Object { $_.FullName }
Remove-SafeItems -Paths $paths -Description "Office temp files"
}
}
}
elseif (Test-Path $path) {
Clear-DirectoryContents -Path $path -Description "Office $(Split-Path -Leaf $path)"
}
}
}
function Clear-OneDriveCache {
<#
.SYNOPSIS
Clean OneDrive cache
#>
$oneDriveCachePaths = @(
"$env:LOCALAPPDATA\Microsoft\OneDrive\logs"
"$env:LOCALAPPDATA\Microsoft\OneDrive\setup\logs"
)
foreach ($path in $oneDriveCachePaths) {
if (Test-Path $path) {
Remove-OldFiles -Path $path -DaysOld 7 -Description "OneDrive logs"
}
}
}
function Clear-DroplboxCache {
<#
.SYNOPSIS
Clean Dropbox cache
#>
# Dropbox cache is typically in the Dropbox folder itself
$dropboxInfoPath = "$env:LOCALAPPDATA\Dropbox\info.json"
if (Test-Path $dropboxInfoPath) {
try {
$dropboxInfo = Get-Content $dropboxInfoPath | ConvertFrom-Json
$dropboxPath = $dropboxInfo.personal.path
if ($dropboxPath) {
$dropboxCachePath = "$dropboxPath\.dropbox.cache"
if (Test-Path $dropboxCachePath) {
Clear-DirectoryContents -Path $dropboxCachePath -Description "Dropbox cache"
}
}
}
catch {
Write-Debug "Could not read Dropbox config: $_"
}
}
}
function Clear-GoogleDriveCache {
<#
.SYNOPSIS
Clean Google Drive cache
#>
$googleDriveCachePaths = @(
"$env:LOCALAPPDATA\Google\DriveFS\Logs"
"$env:LOCALAPPDATA\Google\DriveFS\*.tmp"
)
foreach ($path in $googleDriveCachePaths) {
if ($path -like "*.tmp") {
$parent = Split-Path -Parent $path
if (Test-Path $parent) {
$tmpFiles = Get-ChildItem -Path $parent -Filter "*.tmp" -ErrorAction SilentlyContinue
if ($tmpFiles) {
$paths = $tmpFiles | ForEach-Object { $_.FullName }
Remove-SafeItems -Paths $paths -Description "Google Drive temp"
}
}
}
elseif (Test-Path $path) {
Remove-OldFiles -Path $path -DaysOld 7 -Description "Google Drive logs"
}
}
}
function Clear-AdobeData {
<#
.SYNOPSIS
Clean Adobe application caches and temp files
#>
$adobeCachePaths = @(
"$env:APPDATA\Adobe\Common\Media Cache Files"
"$env:APPDATA\Adobe\Common\Peak Files"
"$env:APPDATA\Adobe\Common\Team Projects Cache"
"$env:LOCALAPPDATA\Adobe\*\Cache"
"$env:LOCALAPPDATA\Adobe\*\CameraRaw\Cache"
"$env:LOCALAPPDATA\Temp\Adobe"
)
foreach ($pattern in $adobeCachePaths) {
$paths = Resolve-Path $pattern -ErrorAction SilentlyContinue
foreach ($path in $paths) {
if (Test-Path $path.Path) {
Clear-DirectoryContents -Path $path.Path -Description "Adobe cache"
}
}
}
}
function Clear-AutodeskData {
<#
.SYNOPSIS
Clean Autodesk application caches
#>
$autodeskCachePaths = @(
"$env:LOCALAPPDATA\Autodesk\*\Cache"
"$env:APPDATA\Autodesk\*\cache"
)
foreach ($pattern in $autodeskCachePaths) {
$paths = Resolve-Path $pattern -ErrorAction SilentlyContinue
foreach ($path in $paths) {
if (Test-Path $path.Path) {
Clear-DirectoryContents -Path $path.Path -Description "Autodesk cache"
}
}
}
}
# ============================================================================
# Gaming Platform Cleanup
# ============================================================================
function Clear-GamingPlatformCaches {
<#
.SYNOPSIS
Clean gaming platform caches (Steam, Epic, Origin, etc.)
#>
# Steam
$steamPaths = @(
"${env:ProgramFiles(x86)}\Steam\appcache\httpcache"
"${env:ProgramFiles(x86)}\Steam\appcache\librarycache"
"${env:ProgramFiles(x86)}\Steam\logs"
)
foreach ($path in $steamPaths) {
if (Test-Path $path) {
Clear-DirectoryContents -Path $path -Description "Steam $(Split-Path -Leaf $path)"
}
}
# Epic Games Launcher
$epicPaths = @(
"$env:LOCALAPPDATA\EpicGamesLauncher\Saved\webcache"
"$env:LOCALAPPDATA\EpicGamesLauncher\Saved\Logs"
)
foreach ($path in $epicPaths) {
if (Test-Path $path) {
Clear-DirectoryContents -Path $path -Description "Epic Games $(Split-Path -Leaf $path)"
}
}
# EA App (Origin replacement)
$eaPaths = @(
"$env:LOCALAPPDATA\Electronic Arts\EA Desktop\cache"
"$env:APPDATA\Origin\*\cache"
)
foreach ($pattern in $eaPaths) {
$paths = Resolve-Path $pattern -ErrorAction SilentlyContinue
foreach ($path in $paths) {
if (Test-Path $path.Path) {
Clear-DirectoryContents -Path $path.Path -Description "EA/Origin cache"
}
}
}
# GOG Galaxy
$gogPaths = @(
"$env:LOCALAPPDATA\GOG.com\Galaxy\webcache"
"$env:PROGRAMDATA\GOG.com\Galaxy\logs"
)
foreach ($path in $gogPaths) {
if (Test-Path $path) {
Clear-DirectoryContents -Path $path -Description "GOG Galaxy $(Split-Path -Leaf $path)"
}
}
# Ubisoft Connect
$ubiPaths = @(
"$env:LOCALAPPDATA\Ubisoft Game Launcher\cache"
"$env:LOCALAPPDATA\Ubisoft Game Launcher\logs"
)
foreach ($path in $ubiPaths) {
if (Test-Path $path) {
Clear-DirectoryContents -Path $path -Description "Ubisoft $(Split-Path -Leaf $path)"
}
}
# Battle.net
$battlenetPaths = @(
"$env:APPDATA\Battle.net\Cache"
"$env:APPDATA\Battle.net\Logs"
)
foreach ($path in $battlenetPaths) {
if (Test-Path $path) {
Clear-DirectoryContents -Path $path -Description "Battle.net $(Split-Path -Leaf $path)"
}
}
}
# ============================================================================
# Main Application Cleanup Function
# ============================================================================
function Invoke-AppCleanup {
<#
.SYNOPSIS
Run all application-specific cleanup tasks
#>
param([switch]$IncludeOrphaned)
Start-Section "Applications"
# Productivity apps
Clear-OfficeCache
Clear-OneDriveCache
Clear-DroplboxCache
Clear-GoogleDriveCache
# Creative apps
Clear-AdobeData
Clear-AutodeskData
# Gaming platforms
Clear-GamingPlatformCaches
Stop-Section
# Orphaned app data (separate section)
if ($IncludeOrphaned) {
Clear-OrphanedAppData -DaysOld 60
}
}
# ============================================================================
# Exports
# ============================================================================
# Functions: Get-InstalledPrograms, Find-OrphanedAppData, Clear-OfficeCache, etc.

View File

@@ -0,0 +1,385 @@
# Mole - Cache Cleanup Module
# Cleans Windows and application caches
#Requires -Version 5.1
Set-StrictMode -Version Latest
# Prevent multiple sourcing
if ((Get-Variable -Name 'MOLE_CLEAN_CACHES_LOADED' -Scope Script -ErrorAction SilentlyContinue) -and $script:MOLE_CLEAN_CACHES_LOADED) { return }
$script:MOLE_CLEAN_CACHES_LOADED = $true
# Import dependencies
$scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
. "$scriptDir\..\core\base.ps1"
. "$scriptDir\..\core\log.ps1"
. "$scriptDir\..\core\file_ops.ps1"
# ============================================================================
# Windows System Caches
# ============================================================================
function Clear-WindowsUpdateCache {
<#
.SYNOPSIS
Clean Windows Update cache (requires admin)
#>
if (-not (Test-IsAdmin)) {
Write-Debug "Skipping Windows Update cache - requires admin"
return
}
$wuPath = "$env:WINDIR\SoftwareDistribution\Download"
if (Test-Path $wuPath) {
# Stop Windows Update service first
if (Test-DryRunMode) {
Write-DryRun "Windows Update cache"
Set-SectionActivity
return
}
try {
Stop-Service -Name wuauserv -Force -ErrorAction SilentlyContinue
Clear-DirectoryContents -Path $wuPath -Description "Windows Update cache"
Start-Service -Name wuauserv -ErrorAction SilentlyContinue
}
catch {
Write-Debug "Could not clear Windows Update cache: $_"
Start-Service -Name wuauserv -ErrorAction SilentlyContinue
}
}
}
function Clear-DeliveryOptimizationCache {
<#
.SYNOPSIS
Clean Windows Delivery Optimization cache (requires admin)
#>
if (-not (Test-IsAdmin)) {
Write-Debug "Skipping Delivery Optimization cache - requires admin"
return
}
$doPath = "$env:WINDIR\ServiceProfiles\NetworkService\AppData\Local\Microsoft\Windows\DeliveryOptimization"
if (Test-Path $doPath) {
if (Test-DryRunMode) {
Write-DryRun "Delivery Optimization cache"
Set-SectionActivity
return
}
try {
Stop-Service -Name DoSvc -Force -ErrorAction SilentlyContinue
Clear-DirectoryContents -Path "$doPath\Cache" -Description "Delivery Optimization cache"
Start-Service -Name DoSvc -ErrorAction SilentlyContinue
}
catch {
Write-Debug "Could not clear Delivery Optimization cache: $_"
Start-Service -Name DoSvc -ErrorAction SilentlyContinue
}
}
}
function Clear-FontCache {
<#
.SYNOPSIS
Clean Windows font cache (requires admin)
#>
if (-not (Test-IsAdmin)) {
return
}
$fontCachePath = "$env:LOCALAPPDATA\Microsoft\Windows\Fonts\FontCache"
if (Test-Path $fontCachePath) {
Remove-SafeItem -Path $fontCachePath -Description "Font cache"
}
}
# ============================================================================
# Browser Caches
# ============================================================================
function Clear-BrowserCaches {
<#
.SYNOPSIS
Clean browser cache directories
#>
Start-Section "Browser caches"
# Chrome
$chromeCachePaths = @(
"$env:LOCALAPPDATA\Google\Chrome\User Data\Default\Cache"
"$env:LOCALAPPDATA\Google\Chrome\User Data\Default\Code Cache"
"$env:LOCALAPPDATA\Google\Chrome\User Data\Default\GPUCache"
"$env:LOCALAPPDATA\Google\Chrome\User Data\Default\Service Worker\CacheStorage"
"$env:LOCALAPPDATA\Google\Chrome\User Data\ShaderCache"
"$env:LOCALAPPDATA\Google\Chrome\User Data\GrShaderCache"
)
foreach ($path in $chromeCachePaths) {
if (Test-Path $path) {
Clear-DirectoryContents -Path $path -Description "Chrome $(Split-Path -Leaf $path)"
}
}
# Edge
$edgeCachePaths = @(
"$env:LOCALAPPDATA\Microsoft\Edge\User Data\Default\Cache"
"$env:LOCALAPPDATA\Microsoft\Edge\User Data\Default\Code Cache"
"$env:LOCALAPPDATA\Microsoft\Edge\User Data\Default\GPUCache"
"$env:LOCALAPPDATA\Microsoft\Edge\User Data\Default\Service Worker\CacheStorage"
"$env:LOCALAPPDATA\Microsoft\Edge\User Data\ShaderCache"
)
foreach ($path in $edgeCachePaths) {
if (Test-Path $path) {
Clear-DirectoryContents -Path $path -Description "Edge $(Split-Path -Leaf $path)"
}
}
# Firefox
$firefoxProfiles = "$env:APPDATA\Mozilla\Firefox\Profiles"
if (Test-Path $firefoxProfiles) {
$profiles = Get-ChildItem -Path $firefoxProfiles -Directory -ErrorAction SilentlyContinue
foreach ($profile in $profiles) {
$firefoxCachePaths = @(
"$($profile.FullName)\cache2"
"$($profile.FullName)\startupCache"
"$($profile.FullName)\shader-cache"
)
foreach ($path in $firefoxCachePaths) {
if (Test-Path $path) {
Clear-DirectoryContents -Path $path -Description "Firefox cache"
}
}
}
}
# Brave
$braveCachePath = "$env:LOCALAPPDATA\BraveSoftware\Brave-Browser\User Data\Default\Cache"
if (Test-Path $braveCachePath) {
Clear-DirectoryContents -Path $braveCachePath -Description "Brave cache"
}
# Opera
$operaCachePath = "$env:APPDATA\Opera Software\Opera Stable\Cache"
if (Test-Path $operaCachePath) {
Clear-DirectoryContents -Path $operaCachePath -Description "Opera cache"
}
Stop-Section
}
# ============================================================================
# Application Caches
# ============================================================================
function Clear-AppCaches {
<#
.SYNOPSIS
Clean common application caches
#>
Start-Section "Application caches"
# Spotify
$spotifyCachePaths = @(
"$env:LOCALAPPDATA\Spotify\Data"
"$env:LOCALAPPDATA\Spotify\Storage"
)
foreach ($path in $spotifyCachePaths) {
if (Test-Path $path) {
Clear-DirectoryContents -Path $path -Description "Spotify cache"
}
}
# Discord
$discordCachePaths = @(
"$env:APPDATA\discord\Cache"
"$env:APPDATA\discord\Code Cache"
"$env:APPDATA\discord\GPUCache"
)
foreach ($path in $discordCachePaths) {
if (Test-Path $path) {
Clear-DirectoryContents -Path $path -Description "Discord cache"
}
}
# Slack
$slackCachePaths = @(
"$env:APPDATA\Slack\Cache"
"$env:APPDATA\Slack\Code Cache"
"$env:APPDATA\Slack\GPUCache"
"$env:APPDATA\Slack\Service Worker\CacheStorage"
)
foreach ($path in $slackCachePaths) {
if (Test-Path $path) {
Clear-DirectoryContents -Path $path -Description "Slack cache"
}
}
# Teams
$teamsCachePaths = @(
"$env:APPDATA\Microsoft\Teams\Cache"
"$env:APPDATA\Microsoft\Teams\blob_storage"
"$env:APPDATA\Microsoft\Teams\databases"
"$env:APPDATA\Microsoft\Teams\GPUCache"
"$env:APPDATA\Microsoft\Teams\IndexedDB"
"$env:APPDATA\Microsoft\Teams\Local Storage"
"$env:APPDATA\Microsoft\Teams\tmp"
)
foreach ($path in $teamsCachePaths) {
if (Test-Path $path) {
Clear-DirectoryContents -Path $path -Description "Teams cache"
}
}
# VS Code
$vscodeCachePaths = @(
"$env:APPDATA\Code\Cache"
"$env:APPDATA\Code\CachedData"
"$env:APPDATA\Code\CachedExtensions"
"$env:APPDATA\Code\CachedExtensionVSIXs"
"$env:APPDATA\Code\Code Cache"
"$env:APPDATA\Code\GPUCache"
)
foreach ($path in $vscodeCachePaths) {
if (Test-Path $path) {
Clear-DirectoryContents -Path $path -Description "VS Code cache"
}
}
# Zoom
$zoomCachePath = "$env:APPDATA\Zoom\data"
if (Test-Path $zoomCachePath) {
Clear-DirectoryContents -Path $zoomCachePath -Description "Zoom cache"
}
# Adobe Creative Cloud
$adobeCachePaths = @(
"$env:LOCALAPPDATA\Adobe\*\Cache"
"$env:APPDATA\Adobe\Common\Media Cache Files"
"$env:APPDATA\Adobe\Common\Peak Files"
)
foreach ($pattern in $adobeCachePaths) {
$paths = Resolve-Path $pattern -ErrorAction SilentlyContinue
foreach ($path in $paths) {
if (Test-Path $path) {
Clear-DirectoryContents -Path $path.Path -Description "Adobe cache"
}
}
}
# Steam (download cache, not games)
$steamCachePath = "${env:ProgramFiles(x86)}\Steam\appcache"
if (Test-Path $steamCachePath) {
Clear-DirectoryContents -Path $steamCachePath -Description "Steam app cache"
}
# Epic Games Launcher
$epicCachePath = "$env:LOCALAPPDATA\EpicGamesLauncher\Saved\webcache"
if (Test-Path $epicCachePath) {
Clear-DirectoryContents -Path $epicCachePath -Description "Epic Games cache"
}
Stop-Section
}
# ============================================================================
# Windows Store / UWP App Caches
# ============================================================================
function Clear-StoreAppCaches {
<#
.SYNOPSIS
Clean Windows Store and UWP app caches
#>
# Microsoft Store cache
$storeCache = "$env:LOCALAPPDATA\Microsoft\Windows\WCN"
if (Test-Path $storeCache) {
Clear-DirectoryContents -Path $storeCache -Description "Windows Store cache"
}
# Store app temp files
$storeTemp = "$env:LOCALAPPDATA\Packages\Microsoft.WindowsStore_*\LocalCache"
$storePaths = Resolve-Path $storeTemp -ErrorAction SilentlyContinue
foreach ($path in $storePaths) {
if (Test-Path $path.Path) {
Clear-DirectoryContents -Path $path.Path -Description "Store LocalCache"
}
}
}
# ============================================================================
# .NET / Runtime Caches
# ============================================================================
function Clear-DotNetCaches {
<#
.SYNOPSIS
Clean .NET runtime caches
#>
# .NET temp files
$dotnetTemp = "$env:LOCALAPPDATA\Temp\Microsoft.NET"
if (Test-Path $dotnetTemp) {
Clear-DirectoryContents -Path $dotnetTemp -Description ".NET temp files"
}
# NGen cache (don't touch - managed by Windows)
# Assembly cache (don't touch - managed by CLR)
}
# ============================================================================
# Main Cache Cleanup Function
# ============================================================================
function Invoke-CacheCleanup {
<#
.SYNOPSIS
Run all cache cleanup tasks
#>
param(
[switch]$IncludeWindowsUpdate,
[switch]$IncludeBrowsers,
[switch]$IncludeApps
)
Start-Section "System caches"
# Windows system caches (if admin)
if (Test-IsAdmin) {
if ($IncludeWindowsUpdate) {
Clear-WindowsUpdateCache
Clear-DeliveryOptimizationCache
}
Clear-FontCache
}
Clear-StoreAppCaches
Clear-DotNetCaches
Stop-Section
# Browser caches
if ($IncludeBrowsers) {
Clear-BrowserCaches
}
# Application caches
if ($IncludeApps) {
Clear-AppCaches
}
}
# ============================================================================
# Exports
# ============================================================================
# Functions: Clear-WindowsUpdateCache, Clear-BrowserCaches, Clear-AppCaches, etc.

537
windows/lib/clean/dev.ps1 Normal file
View File

@@ -0,0 +1,537 @@
# Mole - Developer Tools Cleanup Module
# Cleans development tool caches and build artifacts
#Requires -Version 5.1
Set-StrictMode -Version Latest
# Prevent multiple sourcing
if ((Get-Variable -Name 'MOLE_CLEAN_DEV_LOADED' -Scope Script -ErrorAction SilentlyContinue) -and $script:MOLE_CLEAN_DEV_LOADED) { return }
$script:MOLE_CLEAN_DEV_LOADED = $true
# Import dependencies
$scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
. "$scriptDir\..\core\base.ps1"
. "$scriptDir\..\core\log.ps1"
. "$scriptDir\..\core\file_ops.ps1"
# ============================================================================
# Node.js / JavaScript Ecosystem
# ============================================================================
function Clear-NpmCache {
<#
.SYNOPSIS
Clean npm, pnpm, yarn, and bun caches
#>
# npm cache
if (Get-Command npm -ErrorAction SilentlyContinue) {
if (Test-DryRunMode) {
Write-DryRun "npm cache"
}
else {
try {
$null = npm cache clean --force 2>&1
Write-Success "npm cache"
Set-SectionActivity
}
catch {
Write-Debug "npm cache clean failed: $_"
}
}
}
# npm cache directory (fallback)
$npmCachePath = "$env:APPDATA\npm-cache"
if (Test-Path $npmCachePath) {
Clear-DirectoryContents -Path $npmCachePath -Description "npm cache directory"
}
# pnpm store
$pnpmStorePath = "$env:LOCALAPPDATA\pnpm\store"
if (Test-Path $pnpmStorePath) {
if (Get-Command pnpm -ErrorAction SilentlyContinue) {
if (Test-DryRunMode) {
Write-DryRun "pnpm store"
}
else {
try {
$null = pnpm store prune 2>&1
Write-Success "pnpm store pruned"
Set-SectionActivity
}
catch {
Write-Debug "pnpm store prune failed: $_"
}
}
}
}
# Yarn cache
$yarnCachePaths = @(
"$env:LOCALAPPDATA\Yarn\Cache"
"$env:USERPROFILE\.yarn\cache"
)
foreach ($path in $yarnCachePaths) {
if (Test-Path $path) {
Clear-DirectoryContents -Path $path -Description "Yarn cache"
}
}
# Bun cache
$bunCachePath = "$env:USERPROFILE\.bun\install\cache"
if (Test-Path $bunCachePath) {
Clear-DirectoryContents -Path $bunCachePath -Description "Bun cache"
}
}
function Clear-NodeBuildCaches {
<#
.SYNOPSIS
Clean Node.js build-related caches
#>
# node-gyp
$nodeGypPath = "$env:LOCALAPPDATA\node-gyp\Cache"
if (Test-Path $nodeGypPath) {
Clear-DirectoryContents -Path $nodeGypPath -Description "node-gyp cache"
}
# Electron cache
$electronCachePath = "$env:LOCALAPPDATA\electron\Cache"
if (Test-Path $electronCachePath) {
Clear-DirectoryContents -Path $electronCachePath -Description "Electron cache"
}
# TypeScript cache
$tsCachePath = "$env:LOCALAPPDATA\TypeScript"
if (Test-Path $tsCachePath) {
Clear-DirectoryContents -Path $tsCachePath -Description "TypeScript cache"
}
}
# ============================================================================
# Python Ecosystem
# ============================================================================
function Clear-PythonCaches {
<#
.SYNOPSIS
Clean Python and pip caches
#>
# pip cache
if (Get-Command pip -ErrorAction SilentlyContinue) {
if (Test-DryRunMode) {
Write-DryRun "pip cache"
}
else {
try {
$null = pip cache purge 2>&1
Write-Success "pip cache"
Set-SectionActivity
}
catch {
Write-Debug "pip cache purge failed: $_"
}
}
}
# pip cache directory
$pipCachePath = "$env:LOCALAPPDATA\pip\Cache"
if (Test-Path $pipCachePath) {
Clear-DirectoryContents -Path $pipCachePath -Description "pip cache directory"
}
# Python bytecode caches (__pycache__)
# Note: These are typically in project directories, cleaned by purge command
# pyenv cache
$pyenvCachePath = "$env:USERPROFILE\.pyenv\cache"
if (Test-Path $pyenvCachePath) {
Clear-DirectoryContents -Path $pyenvCachePath -Description "pyenv cache"
}
# Poetry cache
$poetryCachePath = "$env:LOCALAPPDATA\pypoetry\Cache"
if (Test-Path $poetryCachePath) {
Clear-DirectoryContents -Path $poetryCachePath -Description "Poetry cache"
}
# conda packages
$condaCachePaths = @(
"$env:USERPROFILE\.conda\pkgs"
"$env:USERPROFILE\anaconda3\pkgs"
"$env:USERPROFILE\miniconda3\pkgs"
)
foreach ($path in $condaCachePaths) {
if (Test-Path $path) {
# Only clean index and temp files, not actual packages
$tempFiles = Get-ChildItem -Path $path -Filter "*.tmp" -ErrorAction SilentlyContinue
if ($tempFiles) {
$paths = $tempFiles | ForEach-Object { $_.FullName }
Remove-SafeItems -Paths $paths -Description "Conda temp files"
}
}
}
# Jupyter runtime
$jupyterRuntimePath = "$env:APPDATA\jupyter\runtime"
if (Test-Path $jupyterRuntimePath) {
Clear-DirectoryContents -Path $jupyterRuntimePath -Description "Jupyter runtime"
}
# pytest cache
$pytestCachePath = "$env:USERPROFILE\.pytest_cache"
if (Test-Path $pytestCachePath) {
Remove-SafeItem -Path $pytestCachePath -Description "pytest cache" -Recurse
}
}
# ============================================================================
# .NET / C# Ecosystem
# ============================================================================
function Clear-DotNetDevCaches {
<#
.SYNOPSIS
Clean .NET development caches
#>
# NuGet cache
$nugetCachePath = "$env:USERPROFILE\.nuget\packages"
# Don't clean packages by default - they're needed for builds
# Only clean http-cache and temp
$nugetHttpCache = "$env:LOCALAPPDATA\NuGet\v3-cache"
if (Test-Path $nugetHttpCache) {
Clear-DirectoryContents -Path $nugetHttpCache -Description "NuGet HTTP cache"
}
$nugetTempPath = "$env:LOCALAPPDATA\NuGet\plugins-cache"
if (Test-Path $nugetTempPath) {
Clear-DirectoryContents -Path $nugetTempPath -Description "NuGet plugins cache"
}
# MSBuild temp files
$msbuildTemp = "$env:LOCALAPPDATA\Microsoft\MSBuild"
if (Test-Path $msbuildTemp) {
$tempDirs = Get-ChildItem -Path $msbuildTemp -Directory -Filter "*temp*" -ErrorAction SilentlyContinue
foreach ($dir in $tempDirs) {
Clear-DirectoryContents -Path $dir.FullName -Description "MSBuild temp"
}
}
}
# ============================================================================
# Go Ecosystem
# ============================================================================
function Clear-GoCaches {
<#
.SYNOPSIS
Clean Go build and module caches
#>
if (Get-Command go -ErrorAction SilentlyContinue) {
if (Test-DryRunMode) {
Write-DryRun "Go cache"
}
else {
try {
$null = go clean -cache 2>&1
Write-Success "Go build cache"
Set-SectionActivity
}
catch {
Write-Debug "go clean -cache failed: $_"
}
}
}
# Go module cache
$goModCachePath = "$env:GOPATH\pkg\mod\cache"
if (-not $env:GOPATH) {
$goModCachePath = "$env:USERPROFILE\go\pkg\mod\cache"
}
if (Test-Path $goModCachePath) {
Clear-DirectoryContents -Path $goModCachePath -Description "Go module cache"
}
}
# ============================================================================
# Rust Ecosystem
# ============================================================================
function Clear-RustCaches {
<#
.SYNOPSIS
Clean Rust/Cargo caches
#>
# Cargo registry cache
$cargoRegistryCache = "$env:USERPROFILE\.cargo\registry\cache"
if (Test-Path $cargoRegistryCache) {
Clear-DirectoryContents -Path $cargoRegistryCache -Description "Cargo registry cache"
}
# Cargo git cache
$cargoGitCache = "$env:USERPROFILE\.cargo\git\checkouts"
if (Test-Path $cargoGitCache) {
Clear-DirectoryContents -Path $cargoGitCache -Description "Cargo git cache"
}
# Rustup downloads
$rustupDownloads = "$env:USERPROFILE\.rustup\downloads"
if (Test-Path $rustupDownloads) {
Clear-DirectoryContents -Path $rustupDownloads -Description "Rustup downloads"
}
}
# ============================================================================
# Java / JVM Ecosystem
# ============================================================================
function Clear-JvmCaches {
<#
.SYNOPSIS
Clean JVM ecosystem caches (Gradle, Maven, etc.)
#>
# Gradle caches
$gradleCachePaths = @(
"$env:USERPROFILE\.gradle\caches"
"$env:USERPROFILE\.gradle\daemon"
"$env:USERPROFILE\.gradle\wrapper\dists"
)
foreach ($path in $gradleCachePaths) {
if (Test-Path $path) {
# Only clean temp and old daemon logs
$tempFiles = Get-ChildItem -Path $path -Recurse -Filter "*.lock" -ErrorAction SilentlyContinue
if ($tempFiles) {
$paths = $tempFiles | ForEach-Object { $_.FullName }
Remove-SafeItems -Paths $paths -Description "Gradle lock files"
}
}
}
# Maven repository (only clean temp files)
$mavenRepoPath = "$env:USERPROFILE\.m2\repository"
if (Test-Path $mavenRepoPath) {
$tempFiles = Get-ChildItem -Path $mavenRepoPath -Recurse -Filter "*.lastUpdated" -ErrorAction SilentlyContinue
if ($tempFiles) {
$paths = $tempFiles | ForEach-Object { $_.FullName }
Remove-SafeItems -Paths $paths -Description "Maven update markers"
}
}
}
# ============================================================================
# Docker / Containers
# ============================================================================
function Clear-DockerCaches {
<#
.SYNOPSIS
Clean Docker build caches and unused data
#>
if (-not (Get-Command docker -ErrorAction SilentlyContinue)) {
return
}
# Check if Docker daemon is running
$dockerRunning = $false
try {
$null = docker info 2>&1
$dockerRunning = $true
}
catch {
Write-Debug "Docker daemon not running"
}
if ($dockerRunning) {
if (Test-DryRunMode) {
Write-DryRun "Docker build cache"
}
else {
try {
$null = docker builder prune -af 2>&1
Write-Success "Docker build cache"
Set-SectionActivity
}
catch {
Write-Debug "docker builder prune failed: $_"
}
}
}
# Docker Desktop cache (Windows)
$dockerDesktopCache = "$env:LOCALAPPDATA\Docker\wsl\data"
# Note: Don't clean this - it's the WSL2 virtual disk
}
# ============================================================================
# Cloud CLI Tools
# ============================================================================
function Clear-CloudCliCaches {
<#
.SYNOPSIS
Clean cloud CLI tool caches (AWS, Azure, GCP)
#>
# AWS CLI cache
$awsCachePath = "$env:USERPROFILE\.aws\cli\cache"
if (Test-Path $awsCachePath) {
Clear-DirectoryContents -Path $awsCachePath -Description "AWS CLI cache"
}
# Azure CLI logs
$azureLogsPath = "$env:USERPROFILE\.azure\logs"
if (Test-Path $azureLogsPath) {
Clear-DirectoryContents -Path $azureLogsPath -Description "Azure CLI logs"
}
# Google Cloud logs
$gcloudLogsPath = "$env:APPDATA\gcloud\logs"
if (Test-Path $gcloudLogsPath) {
Clear-DirectoryContents -Path $gcloudLogsPath -Description "gcloud logs"
}
# Kubernetes cache
$kubeCachePath = "$env:USERPROFILE\.kube\cache"
if (Test-Path $kubeCachePath) {
Clear-DirectoryContents -Path $kubeCachePath -Description "Kubernetes cache"
}
# Terraform plugin cache
$terraformCachePath = "$env:APPDATA\terraform.d\plugin-cache"
if (Test-Path $terraformCachePath) {
Clear-DirectoryContents -Path $terraformCachePath -Description "Terraform plugin cache"
}
}
# ============================================================================
# IDE Caches
# ============================================================================
function Clear-IdeCaches {
<#
.SYNOPSIS
Clean IDE caches (VS, VSCode, JetBrains, etc.)
#>
# Visual Studio cache
$vsCachePaths = @(
"$env:LOCALAPPDATA\Microsoft\VisualStudio\*\ComponentModelCache"
"$env:LOCALAPPDATA\Microsoft\VisualStudio\*\ImageCache"
)
foreach ($pattern in $vsCachePaths) {
$paths = Resolve-Path $pattern -ErrorAction SilentlyContinue
foreach ($path in $paths) {
if (Test-Path $path.Path) {
Clear-DirectoryContents -Path $path.Path -Description "Visual Studio cache"
}
}
}
# JetBrains IDEs caches
$jetbrainsBasePaths = @(
"$env:LOCALAPPDATA\JetBrains"
"$env:APPDATA\JetBrains"
)
foreach ($basePath in $jetbrainsBasePaths) {
if (Test-Path $basePath) {
$ideFolders = Get-ChildItem -Path $basePath -Directory -ErrorAction SilentlyContinue
foreach ($ideFolder in $ideFolders) {
$cacheFolders = @("caches", "index", "tmp")
foreach ($cacheFolder in $cacheFolders) {
$cachePath = Join-Path $ideFolder.FullName $cacheFolder
if (Test-Path $cachePath) {
Clear-DirectoryContents -Path $cachePath -Description "$($ideFolder.Name) $cacheFolder"
}
}
}
}
}
}
# ============================================================================
# Git Caches
# ============================================================================
function Clear-GitCaches {
<#
.SYNOPSIS
Clean Git temporary files and lock files
#>
# Git config locks (stale)
$gitConfigLock = "$env:USERPROFILE\.gitconfig.lock"
if (Test-Path $gitConfigLock) {
Remove-SafeItem -Path $gitConfigLock -Description "Git config lock"
}
# GitHub CLI cache
$ghCachePath = "$env:APPDATA\GitHub CLI"
if (Test-Path $ghCachePath) {
$cacheFiles = Get-ChildItem -Path $ghCachePath -Filter "*.json" -ErrorAction SilentlyContinue |
Where-Object { $_.LastWriteTime -lt (Get-Date).AddDays(-7) }
if ($cacheFiles) {
$paths = $cacheFiles | ForEach-Object { $_.FullName }
Remove-SafeItems -Paths $paths -Description "GitHub CLI cache"
}
}
}
# ============================================================================
# Main Developer Tools Cleanup Function
# ============================================================================
function Invoke-DevToolsCleanup {
<#
.SYNOPSIS
Run all developer tools cleanup tasks
#>
Start-Section "Developer tools"
# JavaScript ecosystem
Clear-NpmCache
Clear-NodeBuildCaches
# Python ecosystem
Clear-PythonCaches
# .NET ecosystem
Clear-DotNetDevCaches
# Go ecosystem
Clear-GoCaches
# Rust ecosystem
Clear-RustCaches
# JVM ecosystem
Clear-JvmCaches
# Containers
Clear-DockerCaches
# Cloud CLI tools
Clear-CloudCliCaches
# IDEs
Clear-IdeCaches
# Git
Clear-GitCaches
Stop-Section
}
# ============================================================================
# Exports
# ============================================================================
# Functions: Clear-NpmCache, Clear-PythonCaches, Clear-DockerCaches, etc.

View File

@@ -0,0 +1,420 @@
# Mole - System Cleanup Module
# Cleans Windows system files that require administrator access
#Requires -Version 5.1
Set-StrictMode -Version Latest
# Prevent multiple sourcing
if ((Get-Variable -Name 'MOLE_CLEAN_SYSTEM_LOADED' -Scope Script -ErrorAction SilentlyContinue) -and $script:MOLE_CLEAN_SYSTEM_LOADED) { return }
$script:MOLE_CLEAN_SYSTEM_LOADED = $true
# Import dependencies
$scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
. "$scriptDir\..\core\base.ps1"
. "$scriptDir\..\core\log.ps1"
. "$scriptDir\..\core\file_ops.ps1"
# ============================================================================
# System Temp Files
# ============================================================================
function Clear-SystemTempFiles {
<#
.SYNOPSIS
Clean system-level temporary files (requires admin)
#>
if (-not (Test-IsAdmin)) {
Write-Debug "Skipping system temp cleanup - requires admin"
return
}
# Windows Temp folder
$winTemp = "$env:WINDIR\Temp"
if (Test-Path $winTemp) {
Remove-OldFiles -Path $winTemp -DaysOld 7 -Description "Windows temp files"
}
# System temp (different from Windows temp)
$systemTemp = "$env:SYSTEMROOT\Temp"
if ((Test-Path $systemTemp) -and ($systemTemp -ne $winTemp)) {
Remove-OldFiles -Path $systemTemp -DaysOld 7 -Description "System temp files"
}
}
# ============================================================================
# Windows Logs
# ============================================================================
function Clear-WindowsLogs {
<#
.SYNOPSIS
Clean Windows log files (requires admin)
#>
param([int]$DaysOld = 7)
if (-not (Test-IsAdmin)) {
Write-Debug "Skipping Windows logs cleanup - requires admin"
return
}
# Windows Logs directory
$logPaths = @(
"$env:WINDIR\Logs\CBS"
"$env:WINDIR\Logs\DISM"
"$env:WINDIR\Logs\DPX"
"$env:WINDIR\Logs\WindowsUpdate"
"$env:WINDIR\Logs\SIH"
"$env:WINDIR\Logs\waasmedia"
"$env:WINDIR\Debug"
"$env:WINDIR\Panther"
"$env:PROGRAMDATA\Microsoft\Windows\WER\ReportQueue"
"$env:PROGRAMDATA\Microsoft\Windows\WER\ReportArchive"
)
foreach ($path in $logPaths) {
if (Test-Path $path) {
Remove-OldFiles -Path $path -DaysOld $DaysOld -Description "$(Split-Path -Leaf $path) logs"
}
}
# Setup logs (*.log files in Windows directory)
$setupLogs = Get-ChildItem -Path "$env:WINDIR\*.log" -File -ErrorAction SilentlyContinue |
Where-Object { $_.LastWriteTime -lt (Get-Date).AddDays(-$DaysOld) }
if ($setupLogs) {
$paths = $setupLogs | ForEach-Object { $_.FullName }
Remove-SafeItems -Paths $paths -Description "Windows setup logs"
}
}
# ============================================================================
# Windows Update Cleanup
# ============================================================================
function Clear-WindowsUpdateFiles {
<#
.SYNOPSIS
Clean Windows Update download cache (requires admin)
#>
if (-not (Test-IsAdmin)) {
Write-Debug "Skipping Windows Update cleanup - requires admin"
return
}
# Stop Windows Update service
$wuService = Get-Service -Name wuauserv -ErrorAction SilentlyContinue
$wasRunning = $wuService.Status -eq 'Running'
if ($wasRunning) {
if (Test-DryRunMode) {
Write-DryRun "Windows Update cache (service would be restarted)"
return
}
try {
Stop-Service -Name wuauserv -Force -ErrorAction Stop
}
catch {
Write-Debug "Could not stop Windows Update service: $_"
return
}
}
# Clean download cache
$wuDownloadPath = "$env:WINDIR\SoftwareDistribution\Download"
if (Test-Path $wuDownloadPath) {
Clear-DirectoryContents -Path $wuDownloadPath -Description "Windows Update download cache"
}
# Clean DataStore (old update history - be careful!)
# Only clean temp files, not the actual database
$wuDataStore = "$env:WINDIR\SoftwareDistribution\DataStore\Logs"
if (Test-Path $wuDataStore) {
Clear-DirectoryContents -Path $wuDataStore -Description "Windows Update logs"
}
# Restart service if it was running
if ($wasRunning) {
Start-Service -Name wuauserv -ErrorAction SilentlyContinue
}
}
# ============================================================================
# Installer Cleanup
# ============================================================================
function Clear-InstallerCache {
<#
.SYNOPSIS
Clean Windows Installer cache (orphaned patches)
#>
if (-not (Test-IsAdmin)) {
return
}
# Windows Installer patch cache
# WARNING: Be very careful here - only clean truly orphaned files
$installerPath = "$env:WINDIR\Installer"
# Only clean .tmp files and very old .msp files that are likely orphaned
if (Test-Path $installerPath) {
$tmpFiles = Get-ChildItem -Path $installerPath -Filter "*.tmp" -File -ErrorAction SilentlyContinue
if ($tmpFiles) {
$paths = $tmpFiles | ForEach-Object { $_.FullName }
Remove-SafeItems -Paths $paths -Description "Installer temp files"
}
}
# Installer logs in temp
$installerLogs = Get-ChildItem -Path $env:TEMP -Filter "MSI*.LOG" -File -ErrorAction SilentlyContinue |
Where-Object { $_.LastWriteTime -lt (Get-Date).AddDays(-30) }
if ($installerLogs) {
$paths = $installerLogs | ForEach-Object { $_.FullName }
Remove-SafeItems -Paths $paths -Description "Old MSI logs"
}
}
# ============================================================================
# Component Store Cleanup
# ============================================================================
function Invoke-ComponentStoreCleanup {
<#
.SYNOPSIS
Run Windows Component Store cleanup (DISM)
#>
if (-not (Test-IsAdmin)) {
Write-Debug "Skipping component store cleanup - requires admin"
return
}
if (Test-DryRunMode) {
Write-DryRun "Component Store cleanup (DISM)"
Set-SectionActivity
return
}
try {
Write-Info "Running Component Store cleanup (this may take a while)..."
# Run DISM cleanup
$result = Start-Process -FilePath "dism.exe" `
-ArgumentList "/Online", "/Cleanup-Image", "/StartComponentCleanup" `
-Wait -PassThru -NoNewWindow -ErrorAction Stop
if ($result.ExitCode -eq 0) {
Write-Success "Component Store cleanup"
Set-SectionActivity
}
else {
Write-Debug "DISM returned exit code: $($result.ExitCode)"
}
}
catch {
Write-Debug "Component Store cleanup failed: $_"
}
}
# ============================================================================
# Memory Dump Cleanup
# ============================================================================
function Clear-MemoryDumps {
<#
.SYNOPSIS
Clean Windows memory dumps
#>
$dumpPaths = @(
"$env:WINDIR\MEMORY.DMP"
"$env:WINDIR\Minidump"
"$env:LOCALAPPDATA\CrashDumps"
)
foreach ($path in $dumpPaths) {
if (Test-Path $path -PathType Leaf) {
# Single file (MEMORY.DMP)
Remove-SafeItem -Path $path -Description "Memory dump"
}
elseif (Test-Path $path -PathType Container) {
# Directory (Minidump, CrashDumps)
Clear-DirectoryContents -Path $path -Description "$(Split-Path -Leaf $path)"
}
}
}
# ============================================================================
# Font Cache
# ============================================================================
function Clear-SystemFontCache {
<#
.SYNOPSIS
Clear Windows font cache (requires admin and may need restart)
#>
if (-not (Test-IsAdmin)) {
return
}
$fontCacheService = Get-Service -Name "FontCache" -ErrorAction SilentlyContinue
if ($fontCacheService) {
if (Test-DryRunMode) {
Write-DryRun "System font cache"
return
}
try {
# Stop font cache service
Stop-Service -Name "FontCache" -Force -ErrorAction SilentlyContinue
# Clear font cache files
$fontCachePath = "$env:WINDIR\ServiceProfiles\LocalService\AppData\Local\FontCache"
if (Test-Path $fontCachePath) {
Clear-DirectoryContents -Path $fontCachePath -Description "System font cache"
}
# Restart font cache service
Start-Service -Name "FontCache" -ErrorAction SilentlyContinue
}
catch {
Write-Debug "Font cache cleanup failed: $_"
Start-Service -Name "FontCache" -ErrorAction SilentlyContinue
}
}
}
# ============================================================================
# Disk Cleanup Tool Integration
# ============================================================================
function Invoke-DiskCleanupTool {
<#
.SYNOPSIS
Run Windows built-in Disk Cleanup tool with predefined settings
#>
param([switch]$Full)
if (-not (Test-IsAdmin)) {
Write-Debug "Skipping Disk Cleanup tool - requires admin for full cleanup"
}
if (Test-DryRunMode) {
Write-DryRun "Windows Disk Cleanup tool"
return
}
# Set up registry keys for automated cleanup
$cleanupKey = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\VolumeCaches"
$cleanupItems = @(
"Active Setup Temp Folders"
"Downloaded Program Files"
"Internet Cache Files"
"Old ChkDsk Files"
"Recycle Bin"
"Setup Log Files"
"System error memory dump files"
"System error minidump files"
"Temporary Files"
"Temporary Setup Files"
"Thumbnail Cache"
"Windows Error Reporting Archive Files"
"Windows Error Reporting Queue Files"
"Windows Error Reporting System Archive Files"
"Windows Error Reporting System Queue Files"
)
if ($Full -and (Test-IsAdmin)) {
$cleanupItems += @(
"Previous Installations"
"Temporary Windows installation files"
"Update Cleanup"
"Windows Defender"
"Windows Upgrade Log Files"
)
}
# Enable cleanup items in registry
foreach ($item in $cleanupItems) {
$itemPath = Join-Path $cleanupKey $item
if (Test-Path $itemPath) {
Set-ItemProperty -Path $itemPath -Name "StateFlags0100" -Value 2 -Type DWord -ErrorAction SilentlyContinue
}
}
try {
# Run disk cleanup
$process = Start-Process -FilePath "cleanmgr.exe" `
-ArgumentList "/sagerun:100" `
-Wait -PassThru -NoNewWindow -ErrorAction Stop
if ($process.ExitCode -eq 0) {
Write-Success "Windows Disk Cleanup"
Set-SectionActivity
}
}
catch {
Write-Debug "Disk Cleanup failed: $_"
}
}
# ============================================================================
# Main System Cleanup Function
# ============================================================================
function Invoke-SystemCleanup {
<#
.SYNOPSIS
Run all system-level cleanup tasks (requires admin for full effect)
#>
param(
[switch]$IncludeComponentStore,
[switch]$IncludeDiskCleanup
)
Start-Section "System cleanup"
if (-not (Test-IsAdmin)) {
Write-Warning "Running without admin - some cleanup tasks will be skipped"
}
# System temp files
Clear-SystemTempFiles
# Windows logs
Clear-WindowsLogs -DaysOld 7
# Windows Update cache
Clear-WindowsUpdateFiles
# Installer cache
Clear-InstallerCache
# Memory dumps
Clear-MemoryDumps
# Font cache
Clear-SystemFontCache
# Optional: Component Store (can take a long time)
if ($IncludeComponentStore) {
Invoke-ComponentStoreCleanup
}
# Optional: Windows Disk Cleanup tool
if ($IncludeDiskCleanup) {
Invoke-DiskCleanupTool -Full
}
Stop-Section
}
# ============================================================================
# Exports
# ============================================================================
# Functions: Clear-SystemTempFiles, Clear-WindowsLogs, Invoke-SystemCleanup, etc.

349
windows/lib/clean/user.ps1 Normal file
View File

@@ -0,0 +1,349 @@
# Mole - User Cleanup Module
# Cleans user-level temporary files, caches, and downloads
#Requires -Version 5.1
Set-StrictMode -Version Latest
# Prevent multiple sourcing
if ((Get-Variable -Name 'MOLE_CLEAN_USER_LOADED' -Scope Script -ErrorAction SilentlyContinue) -and $script:MOLE_CLEAN_USER_LOADED) { return }
$script:MOLE_CLEAN_USER_LOADED = $true
# Import dependencies
$scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
. "$scriptDir\..\core\base.ps1"
. "$scriptDir\..\core\log.ps1"
. "$scriptDir\..\core\file_ops.ps1"
# ============================================================================
# Windows Temp Files Cleanup
# ============================================================================
function Clear-UserTempFiles {
<#
.SYNOPSIS
Clean user temporary files
#>
param([int]$DaysOld = 7)
Start-Section "User temp files"
# User temp directory
$userTemp = $env:TEMP
if (Test-Path $userTemp) {
Remove-OldFiles -Path $userTemp -DaysOld $DaysOld -Description "User temp files"
}
# Windows Temp (if accessible)
$winTemp = "$env:WINDIR\Temp"
if ((Test-Path $winTemp) -and (Test-IsAdmin)) {
Remove-OldFiles -Path $winTemp -DaysOld $DaysOld -Description "Windows temp files"
}
Stop-Section
}
# ============================================================================
# Downloads Folder Cleanup
# ============================================================================
function Clear-OldDownloads {
<#
.SYNOPSIS
Clean old files from Downloads folder (with user confirmation pattern)
#>
param([int]$DaysOld = 30)
$downloadsPath = [Environment]::GetFolderPath('UserProfile') + '\Downloads'
if (-not (Test-Path $downloadsPath)) {
return
}
# Find old installers and archives
$patterns = @('*.exe', '*.msi', '*.zip', '*.7z', '*.rar', '*.tar.gz', '*.iso')
$cutoffDate = (Get-Date).AddDays(-$DaysOld)
$oldFiles = @()
foreach ($pattern in $patterns) {
$files = Get-ChildItem -Path $downloadsPath -Filter $pattern -File -ErrorAction SilentlyContinue |
Where-Object { $_.LastWriteTime -lt $cutoffDate }
if ($files) {
$oldFiles += $files
}
}
if ($oldFiles.Count -gt 0) {
$paths = $oldFiles | ForEach-Object { $_.FullName }
Remove-SafeItems -Paths $paths -Description "Old downloads (>${DaysOld}d)"
}
}
# ============================================================================
# Recycle Bin Cleanup
# ============================================================================
function Clear-RecycleBin {
<#
.SYNOPSIS
Empty the Recycle Bin
#>
if (Test-DryRunMode) {
Write-DryRun "Recycle Bin (would empty)"
Set-SectionActivity
return
}
try {
# Use Shell.Application COM object
$shell = New-Object -ComObject Shell.Application
$recycleBin = $shell.Namespace(0xA) # Recycle Bin
$items = $recycleBin.Items()
if ($items.Count -gt 0) {
# Calculate size
$totalSize = 0
foreach ($item in $items) {
$totalSize += $item.Size
}
# Clear using Clear-RecycleBin cmdlet (Windows 10+)
Clear-RecycleBin -Force -ErrorAction SilentlyContinue
$sizeHuman = Format-ByteSize -Bytes $totalSize
Write-Success "Recycle Bin $($script:Colors.Green)($sizeHuman)$($script:Colors.NC)"
Set-SectionActivity
}
}
catch {
Write-Debug "Could not clear Recycle Bin: $_"
}
}
# ============================================================================
# Recent Files Cleanup
# ============================================================================
function Clear-RecentFiles {
<#
.SYNOPSIS
Clean old recent file shortcuts
#>
param([int]$DaysOld = 30)
$recentPath = "$env:APPDATA\Microsoft\Windows\Recent"
if (Test-Path $recentPath) {
Remove-OldFiles -Path $recentPath -DaysOld $DaysOld -Filter "*.lnk" -Description "Old recent shortcuts"
}
# AutomaticDestinations (jump lists)
$autoDestPath = "$recentPath\AutomaticDestinations"
if (Test-Path $autoDestPath) {
Remove-OldFiles -Path $autoDestPath -DaysOld $DaysOld -Description "Old jump list entries"
}
}
# ============================================================================
# Thumbnail Cache Cleanup
# ============================================================================
function Clear-ThumbnailCache {
<#
.SYNOPSIS
Clean Windows thumbnail cache
#>
$thumbCachePath = "$env:LOCALAPPDATA\Microsoft\Windows\Explorer"
if (-not (Test-Path $thumbCachePath)) {
return
}
# Thumbnail cache files (thumbcache_*.db)
$thumbFiles = Get-ChildItem -Path $thumbCachePath -Filter "thumbcache_*.db" -File -ErrorAction SilentlyContinue
if ($thumbFiles) {
$paths = $thumbFiles | ForEach-Object { $_.FullName }
Remove-SafeItems -Paths $paths -Description "Thumbnail cache"
}
# Icon cache
$iconCache = "$env:LOCALAPPDATA\IconCache.db"
if (Test-Path $iconCache) {
Remove-SafeItem -Path $iconCache -Description "Icon cache"
}
}
# ============================================================================
# Windows Error Reports Cleanup
# ============================================================================
function Clear-ErrorReports {
<#
.SYNOPSIS
Clean Windows Error Reporting files
#>
param([int]$DaysOld = 7)
$werPaths = @(
"$env:LOCALAPPDATA\Microsoft\Windows\WER"
"$env:LOCALAPPDATA\CrashDumps"
"$env:USERPROFILE\AppData\Local\Microsoft\Windows\WER"
)
foreach ($path in $werPaths) {
if (Test-Path $path) {
$items = Get-ChildItem -Path $path -Recurse -Force -ErrorAction SilentlyContinue
if ($items) {
$paths = $items | ForEach-Object { $_.FullName }
Remove-SafeItems -Paths $paths -Description "Error reports"
}
}
}
# Memory dumps
$dumpPaths = @(
"$env:LOCALAPPDATA\CrashDumps"
"$env:USERPROFILE\*.dmp"
)
foreach ($path in $dumpPaths) {
$dumps = Get-ChildItem -Path $path -Filter "*.dmp" -ErrorAction SilentlyContinue
if ($dumps) {
$paths = $dumps | ForEach-Object { $_.FullName }
Remove-SafeItems -Paths $paths -Description "Memory dumps"
}
}
}
# ============================================================================
# Windows Prefetch Cleanup (requires admin)
# ============================================================================
function Clear-Prefetch {
<#
.SYNOPSIS
Clean Windows Prefetch files (requires admin)
#>
param([int]$DaysOld = 14)
if (-not (Test-IsAdmin)) {
Write-Debug "Skipping Prefetch cleanup - requires admin"
return
}
$prefetchPath = "$env:WINDIR\Prefetch"
if (Test-Path $prefetchPath) {
Remove-OldFiles -Path $prefetchPath -DaysOld $DaysOld -Description "Prefetch files"
}
}
# ============================================================================
# Log Files Cleanup
# ============================================================================
function Clear-UserLogs {
<#
.SYNOPSIS
Clean old log files from common locations
#>
param([int]$DaysOld = 7)
$logLocations = @(
"$env:LOCALAPPDATA\Temp\*.log"
"$env:APPDATA\*.log"
"$env:USERPROFILE\*.log"
)
foreach ($location in $logLocations) {
$parent = Split-Path -Parent $location
$filter = Split-Path -Leaf $location
if (Test-Path $parent) {
$logs = Get-ChildItem -Path $parent -Filter $filter -File -ErrorAction SilentlyContinue |
Where-Object { $_.LastWriteTime -lt (Get-Date).AddDays(-$DaysOld) }
if ($logs) {
$paths = $logs | ForEach-Object { $_.FullName }
Remove-SafeItems -Paths $paths -Description "Old log files"
}
}
}
}
# ============================================================================
# Clipboard History Cleanup
# ============================================================================
function Clear-ClipboardHistory {
<#
.SYNOPSIS
Clear Windows clipboard history
#>
if (Test-DryRunMode) {
Write-DryRun "Clipboard history (would clear)"
return
}
try {
# Clear current clipboard
[System.Windows.Forms.Clipboard]::Clear()
# Clear clipboard history (Windows 10 1809+)
$clipboardPath = "$env:LOCALAPPDATA\Microsoft\Windows\Clipboard"
if (Test-Path $clipboardPath) {
Clear-DirectoryContents -Path $clipboardPath -Description "Clipboard history"
}
}
catch {
Write-Debug "Could not clear clipboard: $_"
}
}
# ============================================================================
# Main User Cleanup Function
# ============================================================================
function Invoke-UserCleanup {
<#
.SYNOPSIS
Run all user-level cleanup tasks
#>
param(
[int]$TempDaysOld = 7,
[int]$DownloadsDaysOld = 30,
[int]$LogDaysOld = 7,
[switch]$IncludeDownloads,
[switch]$IncludeRecycleBin
)
Start-Section "User essentials"
# Always clean these
Clear-UserTempFiles -DaysOld $TempDaysOld
Clear-RecentFiles -DaysOld 30
Clear-ThumbnailCache
Clear-ErrorReports -DaysOld 7
Clear-UserLogs -DaysOld $LogDaysOld
Clear-Prefetch -DaysOld 14
# Optional: Downloads cleanup
if ($IncludeDownloads) {
Clear-OldDownloads -DaysOld $DownloadsDaysOld
}
# Optional: Recycle Bin
if ($IncludeRecycleBin) {
Clear-RecycleBin
}
Stop-Section
}
# ============================================================================
# Exports
# ============================================================================
# Functions: Clear-UserTempFiles, Clear-OldDownloads, Clear-RecycleBin, etc.