mirror of
https://github.com/tw93/Mole.git
synced 2026-02-09 15:29:17 +00:00
chore: restructure windows branch (move windows/ content to root, remove macos files)
This commit is contained in:
442
lib/clean/apps.ps1
Normal file
442
lib/clean/apps.ps1
Normal file
@@ -0,0 +1,442 @@
|
||||
# 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 using stricter matching
|
||||
# Require exact match or that folder name is a clear prefix/suffix of app name
|
||||
$isInstalled = $false
|
||||
$folderLower = $folder.Name.ToLower()
|
||||
foreach ($name in $installedNames) {
|
||||
# Exact match
|
||||
if ($name -eq $folderLower) {
|
||||
$isInstalled = $true
|
||||
break
|
||||
}
|
||||
# Folder is prefix of app name (e.g., "chrome" matches "chrome browser")
|
||||
if ($name.StartsWith($folderLower) -and $folderLower.Length -ge 4) {
|
||||
$isInstalled = $true
|
||||
break
|
||||
}
|
||||
# App name is prefix of folder (e.g., "vscode" matches "vscode-data")
|
||||
if ($folderLower.StartsWith($name) -and $name.Length -ge 4) {
|
||||
$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-DropboxCache {
|
||||
<#
|
||||
.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-DropboxCache
|
||||
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.
|
||||
Reference in New Issue
Block a user