mirror of
https://github.com/tw93/Mole.git
synced 2026-02-15 13:25:04 +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:
429
windows/lib/clean/apps.ps1
Normal file
429
windows/lib/clean/apps.ps1
Normal 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.
|
||||
385
windows/lib/clean/caches.ps1
Normal file
385
windows/lib/clean/caches.ps1
Normal 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
537
windows/lib/clean/dev.ps1
Normal 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.
|
||||
420
windows/lib/clean/system.ps1
Normal file
420
windows/lib/clean/system.ps1
Normal 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
349
windows/lib/clean/user.ps1
Normal 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.
|
||||
Reference in New Issue
Block a user