diff --git a/Clear-TempFiles.ps1 b/Clear-TempFiles.ps1 index d7d315d..ccfa940 100644 --- a/Clear-TempFiles.ps1 +++ b/Clear-TempFiles.ps1 @@ -1,5 +1,40 @@ # Calling PowerShell as Admin and setting Execution Policy to Bypass to avoid Cannot run Scripts error -param ([switch]$Elevated) +[CmdletBinding(SupportsShouldProcess = $true)] +param ( + [switch]$Elevated, + + # Non-interactive mode: runs browser and application cache cleanup only (no prompts, no destructive ops) + [switch]$CacheOnly +) + +$ScriptVersion = '2.9.0' + +$Script:Config = @{ + DownloadsRetentionDays = 90 + InetLogRetentionDays = 30 + System32LogRetentionMonths = 2 + AzureLogRetentionDays = 7 + OfficeCacheRetentionDays = 7 + LFSAgentLogRetentionDays = 30 + SotiLogRetentionYears = 1 + CBSLogRetentionDays = 14 + PantherLogRetentionDays = 30 + FailedReqLogRetentionDays = 30 + CTempThresholdBytes = 500MB + WUFolderThresholdBytes = 1.5GB + CTempPath = 'C:\Temp' + ExcludedUsers = @( + 'Public', + 'Default', + 'Default User', + 'All Users', + 'defaultuser0' + ) +} + +$Script:CleanupStats = @{ + Failed = 0 +} function CheckAdmin { $currentUser = New-Object Security.Principal.WindowsPrincipal $([Security.Principal.WindowsIdentity]::GetCurrent()) @@ -15,6 +50,10 @@ function Ask-YesNo { [string]$Default = 'N' ) + if ($script:NonInteractive) { + return $Default + } + $Answer = Read-Host "$Question (Y/N) [Default: $Default]" if ([string]::IsNullOrWhiteSpace($Answer)) { @@ -69,18 +108,33 @@ function Format-Size { } function Remove-FolderContents { + [CmdletBinding(SupportsShouldProcess = $true)] param ( [Parameter(Mandatory = $true)] [string]$Path ) - if (Test-Path $Path) { - Get-ChildItem -Path $Path -Force -ErrorAction SilentlyContinue | - Remove-Item -Recurse -Force -ErrorAction SilentlyContinue -Verbose + if (-not (Test-Path $Path)) { + return + } + + $Items = @(Get-ChildItem -Path $Path -Force -ErrorAction SilentlyContinue) + + foreach ($Item in $Items) { + if ($PSCmdlet.ShouldProcess($Item.FullName, 'Remove')) { + try { + Remove-Item -Path $Item.FullName -Recurse -Force -ErrorAction Stop -Verbose + } + catch { + $Script:CleanupStats.Failed++ + Write-Verbose "Failed to remove $($Item.FullName): $($_.Exception.Message)" + } + } } } function Remove-OldFiles { + [CmdletBinding(SupportsShouldProcess = $true)] param ( [Parameter(Mandatory = $true)] [string]$Path, @@ -121,13 +175,58 @@ function Remove-OldFiles { } foreach ($File in $Files) { - Remove-Item -Path $File.FullName -Force -ErrorAction SilentlyContinue -Verbose + if ($PSCmdlet.ShouldProcess($File.FullName, 'Remove')) { + try { + Remove-Item -Path $File.FullName -Force -ErrorAction Stop -Verbose + } + catch { + $Script:CleanupStats.Failed++ + Write-Verbose "Failed to remove $($File.FullName): $($_.Exception.Message)" + } + } } } +function Remove-ItemSafe { + [CmdletBinding(SupportsShouldProcess = $true)] + param ( + [Parameter(Mandatory = $true)] + [string]$Path, + + [switch]$Recurse + ) + + if (-not (Test-Path $Path)) { + return + } + + if ($PSCmdlet.ShouldProcess($Path, 'Remove')) { + try { + Remove-Item -Path $Path -Recurse:$Recurse -Force -ErrorAction Stop -Verbose + } + catch { + $Script:CleanupStats.Failed++ + Write-Verbose "Failed to remove ${Path}: $($_.Exception.Message)" + } + } +} + +function Get-DiskSpaceReport { + Get-CimInstance -ClassName Win32_LogicalDisk | + Where-Object { $_.DriveType -eq 3 } | + Select-Object SystemName, + @{ Name = 'Drive'; Expression = { $_.DeviceID } }, + @{ Name = 'Size (GB)'; Expression = { '{0:N1}' -f ($_.Size / 1GB) } }, + @{ Name = 'FreeSpace (GB)'; Expression = { '{0:N1}' -f ($_.FreeSpace / 1GB) } }, + @{ Name = 'PercentFree'; Expression = { '{0:P1}' -f ($_.FreeSpace / $_.Size) } } | + Format-Table -AutoSize | + Out-String +} + if ((CheckAdmin) -eq $false) { if ($Elevated) { - # Could not elevate, quit + Write-Error 'Administrator privileges are required. Elevation was denied or failed.' + exit 1 } else { # Detecting PowerShell (powershell.exe) or PowerShell Core (pwsh) @@ -138,7 +237,14 @@ if ((CheckAdmin) -eq $false) { $PowerShellCmdLine = 'powershell.exe' } - $CommandLine = "-NoProfile -ExecutionPolicy Bypass -File `"" + $MyInvocation.MyCommand.Path + "`" " + $MyInvocation.UnboundArguments + ' -Elevated' + $CommandLine = "-NoProfile -ExecutionPolicy Bypass -File `"" + $MyInvocation.MyCommand.Path + "`" " + ($MyInvocation.UnboundArguments -join ' ') + if ($CacheOnly) { + $CommandLine += ' -CacheOnly' + } + if ($WhatIfPreference) { + $CommandLine += ' -WhatIf' + } + $CommandLine += ' -Elevated' Start-Process "$PSHOME\$PowerShellCmdLine" -Verb RunAs -ArgumentList $CommandLine } @@ -149,36 +255,48 @@ if ((CheckAdmin) -eq $false) { $host.UI.RawUI.WindowTitle = 'Clean Temp Files' function Cleanup { + [CmdletBinding(SupportsShouldProcess = $true)] + param () + $script:NonInteractive = $CacheOnly.IsPresent + $Script:CleanupStats.Failed = 0 + + Write-Host -ForegroundColor Cyan "Clean Temp Files v$ScriptVersion`n" + + if ($CacheOnly) { + Write-Host -ForegroundColor Yellow 'CacheOnly mode: running browser and application cache cleanup only.' + Write-Host -ForegroundColor Yellow 'Destructive operations and system maintenance tasks are skipped.`n' + } + # Set Date for Log $LogDate = Get-Date -Format 'MM-d-yy-HHmm' - # Set Deletion Dates - $DelDownloadsDate = (Get-Date).AddDays(-90) - $DelInetLogDate = (Get-Date).AddDays(-30) - $System32LogDate = (Get-Date).AddMonths(-2) - $DelAZLogDate = (Get-Date).AddDays(-7) - $DelOfficeCacheDate = (Get-Date).AddDays(-7) - $DelLFSAgentLogDate = (Get-Date).AddDays(-30) - $DelSotiLogDate = (Get-Date).AddYears(-1) - $DelCBSLogDate = (Get-Date).AddDays(-14) - $DelPantherLogDate = (Get-Date).AddDays(-30) - $DelFailedReqLogDate = (Get-Date).AddDays(-30) + # Set Deletion Dates from configuration + $DelDownloadsDate = (Get-Date).AddDays(-$Script:Config.DownloadsRetentionDays) + $DelInetLogDate = (Get-Date).AddDays(-$Script:Config.InetLogRetentionDays) + $System32LogDate = (Get-Date).AddMonths(-$Script:Config.System32LogRetentionMonths) + $DelAZLogDate = (Get-Date).AddDays(-$Script:Config.AzureLogRetentionDays) + $DelOfficeCacheDate = (Get-Date).AddDays(-$Script:Config.OfficeCacheRetentionDays) + $DelLFSAgentLogDate = (Get-Date).AddDays(-$Script:Config.LFSAgentLogRetentionDays) + $DelSotiLogDate = (Get-Date).AddYears(-$Script:Config.SotiLogRetentionYears) + $DelCBSLogDate = (Get-Date).AddDays(-$Script:Config.CBSLogRetentionDays) + $DelPantherLogDate = (Get-Date).AddDays(-$Script:Config.PantherLogRetentionDays) + $DelFailedReqLogDate = (Get-Date).AddDays(-$Script:Config.FailedReqLogRetentionDays) + $CTempPath = $Script:Config.CTempPath # Prompt options - $DeleteOldDownloads = Ask-YesNo -Question 'Would you like to delete files older than 90 days in the Downloads folder for All Users?' -Default 'N' + $DeleteOldDownloads = Ask-YesNo -Question "Would you like to delete files older than $($Script:Config.DownloadsRetentionDays) days in the Downloads folder for All Users?" -Default 'N' $CleanBin = Ask-YesNo -Question 'Would you like to empty the Recycle Bin for All Users?' -Default 'N' $CloseBrowsers = Ask-YesNo -Question 'Would you like to close Edge/Chrome/Firefox before cleaning browser cache?' -Default 'N' $CleanPrintSpooler = Ask-YesNo -Question 'Would you like to clear the print spooler queue? This will remove stuck print jobs' -Default 'N' - # C:\Temp handling. Only ask if the folder exists and is larger than 500MB. + # C:\Temp handling. Only ask if the folder exists and is larger than the configured threshold. $CleanCTemp = 'N' - $CTempPath = 'C:\Temp' if (Test-Path $CTempPath) { $CTempSizeBytes = Get-FolderSizeBytes -Path $CTempPath $CTempSizeFormatted = Format-Size -Bytes $CTempSizeBytes - if ($CTempSizeBytes -gt 500MB) { + if ($CTempSizeBytes -gt $Script:Config.CTempThresholdBytes) { Write-Host -ForegroundColor Yellow "$CTempPath currently contains approximately $CTempSizeFormatted." $CleanCTemp = Ask-YesNo -Question "Would you like to clean $CTempPath?" -Default 'N' } @@ -196,7 +314,7 @@ function Cleanup { if (Test-Path "$env:windir\SoftwareDistribution") { $WUFolderSizeBytes = Get-FolderSizeBytes -Path "$env:windir\SoftwareDistribution" - if ($WUFolderSizeBytes -gt 1.5GB) { + if ($WUFolderSizeBytes -gt $Script:Config.WUFolderThresholdBytes) { Write-Host "The Windows Update folder is $(Format-Size -Bytes $WUFolderSizeBytes)" $CleanWU = Ask-YesNo -Question 'Do you want to clean the Software Distribution folder and reset Windows Updates?' -Default 'N' } @@ -213,15 +331,7 @@ function Cleanup { } # Get Disk Size Before - $Before = Get-WmiObject Win32_LogicalDisk | - Where-Object { $_.DriveType -eq '3' } | - Select-Object SystemName, - @{ Name = 'Drive'; Expression = { $_.DeviceID } }, - @{ Name = 'Size (GB)'; Expression = { '{0:N1}' -f ($_.Size / 1GB) } }, - @{ Name = 'FreeSpace (GB)'; Expression = { '{0:N1}' -f ($_.FreeSpace / 1GB) } }, - @{ Name = 'PercentFree'; Expression = { '{0:P1}' -f ($_.FreeSpace / $_.Size) } } | - Format-Table -AutoSize | - Out-String + $Before = Get-DiskSpaceReport # Define log file location $CleanupLog = "$env:USERPROFILE\Cleanup$LogDate.log" @@ -232,13 +342,7 @@ function Cleanup { # Create list of users Write-Host -ForegroundColor Green "Getting the list of Users`n" - $ExcludedUsers = @( - 'Public', - 'Default', - 'Default User', - 'All Users', - 'defaultuser0' - ) + $ExcludedUsers = $Script:Config.ExcludedUsers $Users = Get-ChildItem 'C:\Users' -Directory -ErrorAction SilentlyContinue | Where-Object { $ExcludedUsers -notcontains $_.Name } | @@ -382,6 +486,16 @@ function Cleanup { } Write-Host -ForegroundColor Yellow "Done...`n" + # Clear Delivery Optimization Cache + $DeliveryOptimizationPath = "$env:windir\ServiceProfiles\NetworkService\AppData\Local\Microsoft\Windows\DeliveryOptimization\Cache" + + if (Test-Path $DeliveryOptimizationPath) { + Write-Host -ForegroundColor Yellow "Clearing Delivery Optimization Cache`n" + Remove-FolderContents -Path $DeliveryOptimizationPath + Write-Host -ForegroundColor Yellow "Done...`n" + } + + if (-not $CacheOnly) { # Clear User Temp Folders Write-Host -ForegroundColor Yellow "Clearing User Temp Folders`n" foreach ($User in $Users) { @@ -413,7 +527,7 @@ function Cleanup { # CBS logs can be actively used, so only delete older files. if (Test-Path "$env:windir\Logs\CBS") { - Write-Host -ForegroundColor Yellow "Deleting CBS logs older than 14 days`n" + Write-Host -ForegroundColor Yellow "Deleting CBS logs older than $($Script:Config.CBSLogRetentionDays) days`n" Remove-OldFiles -Path "$env:windir\Logs\CBS" -OlderThan $DelCBSLogDate -Recurse Write-Host -ForegroundColor Yellow "Done...`n" } @@ -423,18 +537,9 @@ function Cleanup { Write-Host -ForegroundColor Yellow "Done...`n" - # Clear Delivery Optimization Cache - $DeliveryOptimizationPath = "$env:windir\ServiceProfiles\NetworkService\AppData\Local\Microsoft\Windows\DeliveryOptimization\Cache" - - if (Test-Path $DeliveryOptimizationPath) { - Write-Host -ForegroundColor Yellow "Clearing Delivery Optimization Cache`n" - Remove-FolderContents -Path $DeliveryOptimizationPath - Write-Host -ForegroundColor Yellow "Done...`n" - } - # Clear Windows memory dump files Write-Host -ForegroundColor Yellow "Clearing Windows memory dump files`n" - Remove-Item -Path "$env:windir\MEMORY.DMP" -Force -ErrorAction SilentlyContinue -Verbose + Remove-ItemSafe -Path "$env:windir\MEMORY.DMP" Remove-FolderContents -Path "$env:windir\Minidump" Write-Host -ForegroundColor Yellow "Done...`n" @@ -467,6 +572,7 @@ function Cleanup { Remove-OldFiles -Path 'C:\inetpub\logs\FailedReqLogFiles' -OlderThan $DelFailedReqLogDate -Recurse Write-Host -ForegroundColor Yellow "Done...`n" } + } # Delete Microsoft Teams Previous Version files Write-Host -ForegroundColor Yellow "Clearing Teams Previous Version`n" @@ -499,28 +605,9 @@ function Cleanup { } Write-Host -ForegroundColor Yellow "Done...`n" - # Clear HP Support Assistant Installation Folder - if (Test-Path 'C:\swsetup') { - Write-Host -ForegroundColor Yellow "Clearing HP Support Assistant Installation Folder C:\swsetup`n" - Remove-Item -Path 'C:\swsetup' -Recurse -Force -ErrorAction SilentlyContinue -Verbose - Write-Host -ForegroundColor Yellow "Done...`n" - } - - # Clear HP Support Framework SoftPaq Cache - $HPSoftPaqPath = 'C:\ProgramData\HP\HP Support Framework\Softpaq' - - if (Test-Path $HPSoftPaqPath) { - Write-Host -ForegroundColor Yellow "Clearing HP Support Framework SoftPaq Cache`n" - - # Keep the SoftPaq folder itself, but remove any files/folders inside it. - Remove-FolderContents -Path $HPSoftPaqPath - - Write-Host -ForegroundColor Yellow "Done...`n" - } - # Delete files older than 90 days from Downloads folder if ($DeleteOldDownloads -eq 'Y') { - Write-Host -ForegroundColor Yellow "Deleting files older than 90 days from User Downloads folder`n" + Write-Host -ForegroundColor Yellow "Deleting files older than $($Script:Config.DownloadsRetentionDays) days from User Downloads folder`n" foreach ($User in $Users) { $UserDownloads = "C:\Users\$User\Downloads" @@ -533,13 +620,6 @@ function Cleanup { Write-Host -ForegroundColor Yellow "Done...`n" } - # Delete files older than 7 days from Azure Log folder - if (Test-Path 'C:\WindowsAzure\Logs') { - Write-Host -ForegroundColor Yellow "Deleting files older than 7 days from Azure Log folder`n" - Remove-OldFiles -Path 'C:\WindowsAzure\Logs' -OlderThan $DelAZLogDate -Recurse - Write-Host -ForegroundColor Yellow "Done...`n" - } - # Delete files older than 7 days from Office Cache Folder Write-Host -ForegroundColor Yellow "Clearing Office Cache Folder`n" foreach ($User in $Users) { @@ -551,6 +631,33 @@ function Cleanup { } Write-Host -ForegroundColor Yellow "Done...`n" + if (-not $CacheOnly) { + # Clear HP Support Assistant Installation Folder + if (Test-Path 'C:\swsetup') { + Write-Host -ForegroundColor Yellow "Clearing HP Support Assistant Installation Folder C:\swsetup`n" + Remove-ItemSafe -Path 'C:\swsetup' -Recurse + Write-Host -ForegroundColor Yellow "Done...`n" + } + + # Clear HP Support Framework SoftPaq Cache + $HPSoftPaqPath = 'C:\ProgramData\HP\HP Support Framework\Softpaq' + + if (Test-Path $HPSoftPaqPath) { + Write-Host -ForegroundColor Yellow "Clearing HP Support Framework SoftPaq Cache`n" + + # Keep the SoftPaq folder itself, but remove any files/folders inside it. + Remove-FolderContents -Path $HPSoftPaqPath + + Write-Host -ForegroundColor Yellow "Done...`n" + } + + # Delete files older than 7 days from Azure Log folder + if (Test-Path 'C:\WindowsAzure\Logs') { + Write-Host -ForegroundColor Yellow "Deleting files older than 7 days from Azure Log folder`n" + Remove-OldFiles -Path 'C:\WindowsAzure\Logs' -OlderThan $DelAZLogDate -Recurse + Write-Host -ForegroundColor Yellow "Done...`n" + } + # Delete files older than 30 days from LFSAgent Log folder https://www.lepide.com/ if (Test-Path "$env:windir\LFSAgent\Logs") { Write-Host -ForegroundColor Yellow "Deleting files older than 30 days from LFSAgent Log folder`n" @@ -588,6 +695,7 @@ function Cleanup { Write-Host -ForegroundColor Yellow "Done...`n" } + } # Clear print spooler queue if requested if ($CleanPrintSpooler -eq 'Y') { @@ -617,7 +725,7 @@ function Cleanup { if ($CleanWindowsOld -eq 'Y') { if (Test-Path 'C:\Windows.old') { Write-Host -ForegroundColor Yellow "Deleting C:\Windows.old`n" - Remove-Item -Path 'C:\Windows.old' -Recurse -Force -ErrorAction SilentlyContinue -Verbose + Remove-ItemSafe -Path 'C:\Windows.old' -Recurse Write-Host -ForegroundColor Yellow "Done...`n" } } @@ -634,7 +742,7 @@ function Cleanup { Write-Warning "$ErrorMessage" } - Remove-Item "$env:windir\SoftwareDistribution" -Recurse -Force -ErrorAction SilentlyContinue -Verbose + Remove-ItemSafe -Path "$env:windir\SoftwareDistribution" -Recurse Start-Sleep -Seconds 3 try { @@ -650,72 +758,72 @@ function Cleanup { } # Empty Recycle Bin -if ($CleanBin -eq 'Y') { - Write-Host -ForegroundColor Green "Cleaning Recycle Bin`n" + if ($CleanBin -eq 'Y') { + Write-Host -ForegroundColor Green "Cleaning Recycle Bin`n" - $RecycleBin = "C:\`$Recycle.Bin" - $BinFolders = Get-ChildItem $RecycleBin -Directory -Force -ErrorAction SilentlyContinue - - foreach ($Folder in $BinFolders) { - # Translate the SID to a User Account - try { - $ObjSID = New-Object System.Security.Principal.SecurityIdentifier ($Folder.Name) - $ObjUser = $ObjSID.Translate([System.Security.Principal.NTAccount]) - Write-Host -ForegroundColor Yellow -BackgroundColor Black "Cleaning $ObjUser Recycle Bin" - } - catch { - $ObjUser = $Folder.Name - Write-Host -ForegroundColor Yellow -BackgroundColor Black "Cleaning $ObjUser Recycle Bin" - } + $RecycleBin = "C:\`$Recycle.Bin" + $BinFolders = Get-ChildItem $RecycleBin -Directory -Force -ErrorAction SilentlyContinue - # Force array output so += does not fail when only one file is returned - $Files = @( - Get-ChildItem $Folder.FullName -File -Recurse -Force -ErrorAction SilentlyContinue - ) + foreach ($Folder in $BinFolders) { + # Translate the SID to a User Account + try { + $ObjSID = New-Object System.Security.Principal.SecurityIdentifier ($Folder.Name) + $ObjUser = $ObjSID.Translate([System.Security.Principal.NTAccount]) + Write-Host -ForegroundColor Yellow -BackgroundColor Black "Cleaning $ObjUser Recycle Bin" + } + catch { + $ObjUser = $Folder.Name + Write-Host -ForegroundColor Yellow -BackgroundColor Black "Cleaning $ObjUser Recycle Bin" + } - $Directories = @( - Get-ChildItem $Folder.FullName -Directory -Recurse -Force -ErrorAction SilentlyContinue | - Sort-Object FullName -Descending - ) + # Force array output so += does not fail when only one file is returned + $Files = @( + Get-ChildItem $Folder.FullName -File -Recurse -Force -ErrorAction SilentlyContinue + ) - $ItemsToDelete = @($Files + $Directories) - $ItemTotal = $ItemsToDelete.Count + $Directories = @( + Get-ChildItem $Folder.FullName -Directory -Recurse -Force -ErrorAction SilentlyContinue | + Sort-Object FullName -Descending + ) - if ($ItemTotal -eq 0) { - Write-Host -ForegroundColor Cyan "Recycle Bin is already empty for $ObjUser`n" - continue - } + $ItemsToDelete = @($Files + $Directories) + $ItemTotal = $ItemsToDelete.Count - for ($i = 1; $i -le $ItemTotal; $i++) { - $Item = $ItemsToDelete[($i - 1)] + if ($ItemTotal -eq 0) { + Write-Host -ForegroundColor Cyan "Recycle Bin is already empty for $ObjUser`n" + continue + } - Write-Progress ` - -Activity "Recycle Bin Clean-up" ` - -Status "Attempting to Delete Item [$i / $ItemTotal]: $($Item.FullName)" ` - -PercentComplete (($i / $ItemTotal) * 100) ` - -Id 1 + for ($i = 1; $i -le $ItemTotal; $i++) { + $Item = $ItemsToDelete[($i - 1)] + + Write-Progress ` + -Activity "Recycle Bin Clean-up" ` + -Status "Attempting to Delete Item [$i / $ItemTotal]: $($Item.FullName)" ` + -PercentComplete (($i / $ItemTotal) * 100) ` + -Id 1 + + if ($PSCmdlet.ShouldProcess($Item.FullName, 'Remove')) { + try { + Remove-Item -Path $Item.FullName -Recurse -Force -ErrorAction Stop + } + catch { + $Script:CleanupStats.Failed++ + Write-Verbose "Failed to remove $($Item.FullName): $($_.Exception.Message)" + } + } + } - Remove-Item -Path $Item.FullName -Recurse -Force -ErrorAction SilentlyContinue + Write-Progress -Activity "Recycle Bin Clean-up" -Status "Complete" -Completed -Id 1 } - Write-Progress -Activity "Recycle Bin Clean-up" -Status "Complete" -Completed -Id 1 + Write-Host -ForegroundColor Green "Done`n `n" } - Write-Host -ForegroundColor Green "Done`n `n" -} - Write-Host -ForegroundColor Green "All Tasks Done!`n`n" # Get Drive size after clean - $After = Get-WmiObject Win32_LogicalDisk | - Where-Object { $_.DriveType -eq '3' } | - Select-Object SystemName, - @{ Name = 'Drive'; Expression = { $_.DeviceID } }, - @{ Name = 'Size (GB)'; Expression = { '{0:N1}' -f ($_.Size / 1GB) } }, - @{ Name = 'FreeSpace (GB)'; Expression = { '{0:N1}' -f ($_.FreeSpace / 1GB) } }, - @{ Name = 'PercentFree'; Expression = { '{0:P1}' -f ($_.FreeSpace / $_.Size) } } | - Format-Table -AutoSize | - Out-String + $After = Get-DiskSpaceReport # Report WinSxS and Installer folder sizes $WinSxSPath = "$env:windir\WinSxS" @@ -741,11 +849,21 @@ if ($CleanBin -eq 'Y') { Write-Host -ForegroundColor Yellow "`nPlease rerun Windows Update to pull down the latest updates.`n" } + if ($Script:CleanupStats.Failed -gt 0) { + Write-Host -ForegroundColor Yellow "`nCleanup completed with $($Script:CleanupStats.Failed) item(s) that could not be removed (locked, in use, or access denied)." + Write-Host -ForegroundColor Yellow 'Check the transcript log for verbose details.`n' + } + # Read some of the output before going away - Start-Sleep -Seconds 15 + if (-not $CacheOnly) { + Start-Sleep -Seconds 15 - # Open Text File - Invoke-Item $CleanupLog + # Open Text File + Invoke-Item $CleanupLog + } + else { + Write-Host -ForegroundColor Cyan "Transcript saved to: $CleanupLog" + } # Stop Transcript Stop-Transcript diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..3c97387 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 Clean-Temp-Files contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md index d359de1..3622e06 100644 --- a/README.md +++ b/README.md @@ -1,75 +1,178 @@ # Clean Browser Cache and Recycle Bin -This Powershell script was created by [Lemtek](https://github.com/lemtek/Powershell/blob/master/Clear_Browser_Caches) and has been edited with changes and additions by [Bromeego](https://github.com/Bromeego/Clean-Temp-Files) and from other users which have forked earlier versions. Credit and thanks is noted below in the changelog. +A PowerShell script for Windows that frees disk space by clearing browser caches, temp folders, logs, and vendor-specific caches. Originally created by [Lemtek](https://github.com/lemtek/Powershell/blob/master/Clear_Browser_Caches) and maintained by [Bromeego](https://github.com/Bromeego/Clean-Temp-Files) with contributions from the community. -Powershell script to delete cache & cookies in Firefox, Chrome, Chromium, Opera, Yandex, Edge & IE browsers. With options to empty the Recycle Bin for all users and Downloads folder for files older than 90 days. +**Current version: 2.9.0** -v2.8.2: +## Requirements -* Added cleaning of Windows Error Reporting and CBS (Component-Based Servicing) folders +- Windows 10 or later (Windows Server supported for many tasks) +- Administrator privileges (the script self-elevates via UAC) +- Windows PowerShell 5.1 or PowerShell 7 (`pwsh`) -v2.8.1: +## Usage -* Added cleaning of Inetpub logfiles directory -* Added cleaning of user CrashDumps directory +### Interactive (default) -v2.8: +Right-click PowerShell and choose **Run as Administrator**, then: -* Added cleaning of Microsoft Teams previous version folder -* Added Dropbox cache cleaning - Found on [bluPhy](https://github.com/bluPhy/Clean-Temp-Files) - Thanks! -* Added SnagIt CrashDump cleaning -* Added Yandex Browser -* Added another Cache folder for Internet Explorer/Edge -* Added clearing of Firefox OfflineCache folder -* Added deleting of files older than 90 days within User\Downloads Folder. The date can be changed on line 28 -* Removed unneeded command from Firefox cleaning -* Fixed command for Firefox cleaning -* Split Internet Explorer, User Temp Folders, Opera and Chromium to their own sections -* Split Opera and Chromium sections into their own -* Renamed Internet Explorer section to Internet Explorer & Edge -* Expanded the -EA parameter to read the full name -* Fixed output error on line 37 - Found on [bluPhy](https://github.com/bluPhy/Clean-Temp-Files) - Thanks! -* Updated README.md with proper formatting +```powershell +Set-Location C:\path\to\Clean-Temp-Files +powershell.exe -ExecutionPolicy Bypass -File .\Clear-TempFiles.ps1 +``` -v2.7: +The script prompts for UAC elevation if not already running as admin. Destructive operations default to **No**. -* Borrowed Chromium and Opera Cleaning - Credit [Anst-foto](https://github.com/anst-foto/Powershell) -* Redone Recycle Bin cleaning. Will ask for confirmation at the start of the script then will clean All Users Recycle Bin - Credit [Chris Rakowitz](https://community.spiceworks.com/scripts/show_download/3677-empty-recycle-bins) -* Translate SID to User account when running the Recycle Bin Cleaning for nicer output. If SID cannot be translated then just show SID +### Cache-only mode (non-interactive) -v2.6: +For scheduled tasks or unattended runs that should only clear browser and application caches: -* Fixes from Github which were not pulled from Master -* Fixed C:\users\\%username% could not be found if the profiledir points to another directory - Credit [Mahagon](https://github.com/Mahagon/Powershell) -* Amend Clear Internet Explorer Output - Credit [Watnabe](https://github.com/Watnabe/Powershell) +```powershell +powershell.exe -ExecutionPolicy Bypass -File .\Clear-TempFiles.ps1 -CacheOnly +``` -v2.5: +This skips all prompts and runs **Tier 1** cleanup only (see below). No recycle bin, Downloads purge, `Windows.old`, or system maintenance. -* Added Disk Size, Free Space, % Free. Before and After - Code Borrowed from [Technet Article](https://gallery.technet.microsoft.com/scriptcenter/Clean-up-your-C-Drive-bc7bb3ed) -* Write to Text File -* Tabbed in code, cleaner to read -* Updated Alias' to Full Content for easier maintenance +### Preview changes (WhatIf) -v2.4: +```powershell +powershell.exe -ExecutionPolicy Bypass -File .\Clear-TempFiles.ps1 -WhatIf +``` -* Resolved *.default issue, issue was with the file path name not with *.default, but issue resolved +Shows what would be removed without deleting anything. -v2.3: +## Cleanup tiers -* Added Cache2 to Mozilla directories but found that *.default is not working +### Tier 1 — runs automatically (or with `-CacheOnly`) -v2.2: +- Browser caches: Firefox, Chrome, Edge, IE/legacy Edge, Chromium, Opera, Yandex +- Delivery Optimization cache +- Microsoft Teams `previous` / `stage` folders +- SnagIt crash dumps +- Dropbox cache +- Office GrooveFileCache (files older than 7 days) -* Added Cyan colour to verbose output +Cookies and local storage are **not** cleared, so users stay signed in to websites. -v2.1: +### Tier 2 — runs in full mode only (no prompt) -* Added the location 'C:\Windows\Temp\*' and 'C:\`$recycle.bin\' +- User `%TEMP%`, WER, AppCache, CrashDumps +- `%windir%\Temp`, ProgramData WER +- CBS logs (older than 14 days), System32 LogFiles (older than 2 months) +- Memory dumps, Panther/setup logs, IIS logs +- HP `C:\swsetup`, HP SoftPaq cache +- Azure VM logs, LFSAgent logs, SOTI MobiControl logs, Cylance logs -v2: +### Tier 3 — prompted (default: No) -* Changed the retrieval of user list to dir the c:\users folder and export to csv +- Downloads files older than 90 days (all users) +- Empty all users' recycle bins +- Force-close Edge/Chrome/Firefox before cache cleanup +- Clear print spooler queue +- Clean `C:\Temp` (only if folder exists and exceeds 500 MB) +- Reset Windows Update (`SoftwareDistribution`) if folder exceeds 1.5 GB +- Delete `C:\Windows.old` -v1: +## Configuration -* Compiled script +Retention windows and thresholds are defined at the top of `Clear-TempFiles.ps1` in the `$Script:Config` hashtable. For example, to change Downloads retention from 90 days: + +```powershell +DownloadsRetentionDays = 90 # change this value in $Script:Config +``` + +## Logging + +A transcript is saved to `%USERPROFILE%\Cleanup{date}.log` and opened when the script finishes. + +## Warnings + +- This is an **admin tool**. Run only on systems you manage and understand. +- Tier 2 actions include deleting security product logs (Cylance) and forensic artifacts (memory dumps, WER). +- Force-closing browsers may cause unsaved tab data loss. +- Deleting `C:\Windows.old` prevents rollback to a previous Windows version. +- Locked or in-use files are skipped; a summary is shown at the end if any removals failed. + +## Changelog + +### v2.9.0 + +- Added script version, centralized configuration (`$Script:Config`) +- Added `-CacheOnly` for non-interactive cache cleanup +- Added `-WhatIf` support for previewing removals +- Replaced deprecated `Get-WmiObject` with `Get-CimInstance` +- Fixed silent exit when elevation fails +- Fixed recycle bin section indentation +- Added failure summary for items that could not be removed +- Expanded README with usage, tiers, and warnings +- Added MIT license + +### v2.8.2 + +- Added cleaning of Windows Error Reporting and CBS (Component-Based Servicing) folders + +### v2.8.1 + +- Added cleaning of Inetpub logfiles directory +- Added cleaning of user CrashDumps directory + +### v2.8 + +- Added cleaning of Microsoft Teams previous version folder +- Added Dropbox cache cleaning - Found on [bluPhy](https://github.com/bluPhy/Clean-Temp-Files) - Thanks! +- Added SnagIt CrashDump cleaning +- Added Yandex Browser +- Added another Cache folder for Internet Explorer/Edge +- Added clearing of Firefox OfflineCache folder +- Added deleting of files older than 90 days within User\Downloads Folder +- Removed unneeded command from Firefox cleaning +- Fixed command for Firefox cleaning +- Split Internet Explorer, User Temp Folders, Opera and Chromium to their own sections +- Split Opera and Chromium sections into their own +- Renamed Internet Explorer section to Internet Explorer & Edge +- Expanded the -EA parameter to read the full name +- Fixed output error on line 37 - Found on [bluPhy](https://github.com/bluPhy/Clean-Temp-Files) - Thanks! +- Updated README.md with proper formatting + +### v2.7 + +- Borrowed Chromium and Opera Cleaning - Credit [Anst-foto](https://github.com/anst-foto/Powershell) +- Redone Recycle Bin cleaning. Will ask for confirmation at the start of the script then will clean All Users Recycle Bin - Credit [Chris Rakowitz](https://community.spiceworks.com/scripts/show_download/3677-empty-recycle-bins) +- Translate SID to User account when running the Recycle Bin Cleaning for nicer output. If SID cannot be translated then just show SID + +### v2.6 + +- Fixes from Github which were not pulled from Master +- Fixed C:\users\\%username% could not be found if the profiledir points to another directory - Credit [Mahagon](https://github.com/Mahagon/Powershell) +- Amend Clear Internet Explorer Output - Credit [Watnabe](https://github.com/Watnabe/Powershell) + +### v2.5 + +- Added Disk Size, Free Space, % Free. Before and After - Code Borrowed from [Technet Article](https://gallery.technet.microsoft.com/scriptcenter/Clean-up-your-C-Drive-bc7bb3ed) +- Write to Text File +- Tabbed in code, cleaner to read +- Updated Alias' to Full Content for easier maintenance + +### v2.4 + +- Resolved *.default issue, issue was with the file path name not with *.default, but issue resolved + +### v2.3 + +- Added Cache2 to Mozilla directories but found that *.default is not working + +### v2.2 + +- Added Cyan colour to verbose output + +### v2.1 + +- Added the location 'C:\Windows\Temp\*' and 'C:\`$recycle.bin\' + +### v2 + +- Changed the retrieval of user list to dir the c:\users folder and export to csv + +### v1 + +- Compiled script