Updated 08-28-19 Code: Function Start-WindowsCleanup { <# .SYNOPSIS Clean-up temporary files and folders and reclaim disk space. .DESCRIPTION Cleans-up temporary Windows files, folders and directories. Sets the proper StateFlags on all available VolumeCaches in the registry and runs the advanced CleanMgr.exe as a .NET process to circumvent the GUI that requires one to manually select each section to clean. Monitors the .NET processes until completion and then continues with the script. Enables all options by adding the StateFlags registry property name to the VolumeCache registry keys. These options are then disabled, after CleanMgr.exe has run, to ensure no other programs can utilize its features without permission. logs all actions processed to a transcript that located in 'C:\Temp'. .PARAMETER StateFlags An optional integer for the StateFlags registry property name in case a specific value is required. The default value is 1. .EXAMPLE PS C:\> Start-WindowsCleanup PS C:\> Start-WindowsCleanup -StateFlags 1234 .NOTES The Download folder is not included in the clean-up with Windows Disk Clean-up Manager to make sure no downloaded files are removed without explicit permission. Any permissions errors returned when cleaning can be ignored. #> [CmdletBinding(ConfirmImpact = 'High', SupportsShouldProcess = $true)] Param ( [Parameter(Mandatory = $false, HelpMessage = 'An optional integer for the StateFlags registry property.')] [ValidateRange(1, 9999)] [int]$StateFlags = 5432 ) Begin { $PropertyName = "StateFlags{0:D4}" -f $StateFlags $ReportLog = Join-Path -Path "$Env:SystemRoot\Temp" -ChildPath "Start-WindowsCleanup_$(Get-Date -Format "MM-dd-yyyy").log" Function Clear-Item { [CmdletBinding()] Param ( [string]$Path, [switch]$Remove ) If ($Remove.IsPresent) { Remove-Item -Path $($Path) -Recurse -Force -Verbose -ErrorAction SilentlyContinue } Else { Get-ChildItem -Path $($Path) -Recurse -Force -ErrorAction SilentlyContinue | Remove-Item -Recurse -Force -Verbose -Erroraction SilentlyContinue } } $PreClean = Get-CimInstance -ClassName Win32_LogicalDisk | Where-Object -Property DriveType -EQ 3 | Select-Object -Property 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 Start-Transcript -Path $ReportLog } Process { If ($PSCmdlet.ShouldProcess("$Env:COMPUTERNAME, All distribution, logging and temporary content will be lost")) { Clear-Host Clear-Item -Path "$Env:TEMP\*" Clear-Item -Path "$Env:SystemRoot\Temp\*" Clear-Item -Path "C:\Users\*\AppData\Local\Temp\*" Clear-Item -Path "$Env:SystemRoot\SoftwareDistribution\Download\*" Clear-Item -Path "C:\Users\*\AppData\Local\Microsoft\Windows\Temporary Internet Files\*" Clear-Item -Path "C:\Users\*\AppData\Local\Microsoft\Windows\IECompatCache\*" Clear-Item -Path "C:\Users\*\AppData\Local\Microsoft\Windows\IECompatUaCache\*" Clear-Item -Path "C:\Users\*\AppData\Local\Microsoft\Windows\IEDownloadHistory\*" Clear-Item -Path "C:\Users\*\AppData\Local\Microsoft\Windows\INetCache\*" Clear-Item -Path "C:\Users\*\AppData\Local\Microsoft\Windows\INetCookies\*" Clear-Item -Path "C:\Users\*\AppData\Local\Microsoft\Terminal Server Client\Cache\*" Clear-Item -Path "C:\Users\*\AppData\Local\Microsoft\Windows\WER\*" Clear-Item -Path "$Env:ProgramData\Microsoft\Windows\WER\*" Clear-Item -Path "$Env:SystemRoot\Logs\*" Clear-Item -Path "$Env:SystemRoot\WinSxS\ManifestCache\*" Clear-Item -Path "$Env:SystemDrive\swtools\*" Clear-Item -Path "$Env:SystemDrive\swsetup\*" Clear-Item -Path "$Env:SystemRoot\drivers\*" Clear-Item -Path "$Env:SystemDrive\Users\Administrator\Downloads\*" Clear-Item -Path "$Env:SystemRoot\minidump\*" Clear-Item -Path "$Env:SystemRoot\Prefetch\*" Clear-Item -Path "$Env:HOMEDRIVE\inetpub\logs\LogFiles\*" Clear-Item -Path "$Env:HOMEDRIVE\PerfLogs\*" Clear-Item -Path "$Env:HOMEDRIVE\Intel\*" Clear-Item -Path "$Env:HOMEDRIVE\Config.Msi" -Remove Clear-Item -Path "$Env:SystemRoot\*.log" -Remove Clear-Item -Path "$Env:SystemRoot\Logs\CBS\*.log" -Remove Clear-Item -Path "$Env:SystemRoot\Logs\DISM\*.log*" -Remove Clear-Item -Path "$Env:SystemRoot\memory.dmp" -Remove If ($PSVersionTable.PSVersion.Major -lt 5) { (New-Object -ComObject Shell.Application).NameSpace(0xA).Items() | ForEach-Object -Process { Remove-Item -Path $_.Path -Force -Recurse -Verbose -ErrorAction SilentlyContinue } } Else { Clear-RecycleBin -Force -Confirm:$false -Verbose -ErrorAction SilentlyContinue } Remove-ItemProperty -Path "HKCU:\Software\Microsoft\Windows\CurrentVersion\Applets\Regedit" -Name LastKey -Force -ErrorAction SilentlyContinue Get-ChildItem -Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\VolumeCaches" -Exclude "Downloaded Program Files", "DownloadsFolder" -ErrorAction SilentlyContinue | ForEach-Object { Set-ItemProperty -Path $($_.PsPath) -Name $PropertyName -Value 2 -Force -ErrorAction SilentlyContinue } $ProcessInfo = New-Object -TypeName System.Diagnostics.ProcessStartInfo $ProcessInfo.FileName = "$Env:SystemRoot\System32\cleanmgr.exe" $ProcessInfo.Arguments = '/SAGERUN:{0}' -f $StateFlags.ToString() $ProcessInfo.CreateNoWindow = $true $Process = New-Object -TypeName System.Diagnostics.Process $Process.StartInfo = $ProcessInfo [void]$Process.Start() $Process.WaitForExit() Get-ChildItem -Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\VolumeCaches" -Exclude "Downloaded Program Files", "DownloadsFolder" -ErrorAction SilentlyContinue | ForEach-Object { Remove-ItemProperty -Path $($_.PsPath) -Name $PropertyName -Force -ErrorAction SilentlyContinue } } } End { $PostClean = Get-CimInstance -ClassName Win32_LogicalDisk | Where-Object -Property DriveType -EQ 3 | Select-Object -Property 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 Write-Output "`n`n`t`t`tBefore Clean-up:`n$PreClean" -Verbose Write-Output "`t`t`tAfter Clean-up:`n$PostClean" -Verbose Stop-Transcript } } Code: Function Reset-WindowsUpdate { <# .SYNOPSIS Cleans-up Windows Update distribution folders and resets all dependent services to their default state to mitigate any updating problems. .DESCRIPTION Stops all Windows Update dependent services, then proceeds to clean all folders used by Windows Update. Regenerates the default file structure that Windows requires for proper WSUS service access and authentication. Returns all dependent files, discretionary access control lists and permissions back to their default state. Resets the local network. Restarts any stopped Windows Update dependent services. Optionally, the system will display a progress bar countdown before restarting to further clear any cache storage. .EXAMPLE PS C:\> Reset-WindowsUpdate .NOTES Works with the latest Windows 10 builds and does not revert custom policy settings set in Group Policy. It is highly recommended to restart the device after running this function to clear additional system cache reserves and to apply the default service DACLs. #> [CmdletBinding()] Param () Begin { $DefaultErrorAction = $ErrorActionPreference $ErrorActionPreference = 'SilentlyContinue' } Process { Clear-Host Write-Host "Stopping the BITS, wuauserv, AppIDSvc and CryptSvc services..." -NoNewline -ForegroundColor Cyan Get-Service -Name BITS, wuauserv, AppIDSvc, CryptSvc | Where-Object -Property Status -EQ Running | Stop-Service -Force Clear-DnsClientCache Write-Host "[Complete]" -ForegroundColor Cyan Write-Host "Resetting Update Containers..." -NoNewline -ForegroundColor Cyan Remove-Item -Path "$Env:ALLUSERSPROFILE\Application Data\Microsoft\Network\Downloader\qmgr*.dat" -Force Remove-Item -Path "$Env:ALLUSERSPROFILE\Microsoft\Network\Downloader\qmgr*.dat" -Force Get-ChildItem -Path $Env:SystemRoot\Logs\WindowsUpdate\* | Remove-Item -Recurse -Force If (Test-Path -Path $Env:SystemRoot\WinSxS\pending.xml.bak) { Remove-Item -Path $Env:SystemRoot\WinSxS\pending.xml.bak -Force } If (Test-Path -Path $Env:SystemRoot\SoftwareDistribution.bak) { Remove-Item -Path $Env:SystemRoot\SoftwareDistribution.bak -Recurse -Force } If (Test-Path -Path $Env:SystemRoot\System32\Catroot2.bak) { Remove-Item -Path $Env:SystemRoot\System32\Catroot2.bak -Recurse -Force } If (Test-Path -Path $Env:SystemRoot\WindowsUpdate.log.bak) { Remove-Item -Path $Env:SystemRoot\WindowsUpdate.log.bak -Force } If (Test-Path -Path $Env:SystemRoot\WinSxS\pending.xml) { Start-Process -FilePath TAKEOWN -ArgumentList ('/F "{0}"' -f "$Env:SystemRoot\WinSxS\pending.xml") -WindowStyle Hidden -Wait Start-Process -FilePath ATTRIB -ArgumentList ('-R -S -H /S /D "{0}"' -f "$Env:SystemRoot\WinSxS\pending.xml") -WindowStyle Hidden -Wait Rename-Item -Path $Env:SystemRoot\WinSxS\pending.xml -NewName pending.xml.bak -Force } If (Test-Path -Path $Env:SystemRoot\SoftwareDistribution) { Start-Process -FilePath ATTRIB -ArgumentList ('-R -S -H /S /D "{0}"' -f "$Env:SystemRoot\SoftwareDistribution") -WindowStyle Hidden -Wait Rename-Item -Path $Env:SystemRoot\SoftwareDistribution -NewName SoftwareDistribution.bak -Force If (Test-Path -Path $Env:SystemRoot\SoftwareDistribution) { Write-Warning "Failed to reset the Software Distribution folder."; Break } } If (Test-Path -Path $Env:SystemRoot\System32\Catroot2) { Start-Process -FilePath ATTRIB -ArgumentList ('-R -S -H /S /D "{0}"' -f "$Env:SystemRoot\System32\Catroot2") -WindowStyle Hidden -Wait Rename-Item -Path $Env:SystemRoot\System32\Catroot2 -NewName Catroot2.bak -Force } If (Test-Path -Path $Env:SystemRoot\WindowsUpdate.log) { Start-Process -FilePath ATTRIB -ArgumentList ('-R -S -H /S /D "{0}"' -f "$Env:SystemRoot\WindowsUpdate.log") -WindowStyle Hidden -Wait Rename-Item -Path $Env:SystemRoot\WindowsUpdate.log -NewName WindowsUpdate.log.bak -Force } Write-Host "[Complete]" -ForegroundColor Cyan Write-Host "Resetting the wuauserv and BITS discretionary access control list (DACL)..." -NoNewline -ForegroundColor Cyan Start-Process -FilePath SC.EXE -ArgumentList ('SDSET wuauserv D:(A;;CCLCSWRPWPDTLOCRRC;;;SY)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;BA)(A;;CCLCSWLOCRRC;;;AU)(A;;CCLCSWRPWPDTLOCRRC;;;PU)') -WindowStyle Hidden -Wait Start-Process -FilePath SC.EXE -ArgumentList ('SDSET BITS D:(A;;CCLCSWRPWPDTLOCRRC;;;SY)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;BA)(A;;CCLCSWLOCRRC;;;AU)(A;;CCLCSWRPWPDTLOCRRC;;;PU)') -WindowStyle Hidden -Wait Write-Host "[Complete]" -ForegroundColor Cyan Write-Host "Re-registering Update Modules..." -NoNewline -ForegroundColor Cyan Set-Location -Path $Env:SystemRoot\System32 @('atl.dll', 'urlmon.dll', 'mshtml.dll', 'shdocvw.dll', 'browseui.dll', 'jscript.dll', 'vbscript.dll', 'scrrun.dll', 'msxml.dll', 'msxml3.dll', 'msxml6.dll', 'actxprxy.dll', 'softpub.dll', 'wintrust.dll', 'dssenh.dll', 'rsaenh.dll', 'gpkcsp.dll', 'sccbase.dll', 'slbcsp.dll', 'cryptdlg.dll', 'oleaut32.dll', 'ole32.dll', 'shell32.dll', 'initpki.dll', 'wuapi.dll', 'wuaueng.dll', 'wuaueng1.dll', 'wucltui.dll', 'wups.dll', 'wups2.dll', 'wuweb.dll', 'qmgr.dll', 'qmgrprxy.dll', 'wucltux.dll', 'muweb.dll', 'wuwebv.dll', 'wudriver.dll') | ForEach-Object { Start-Process -FilePath REGSVR32 -ArgumentList ('/S {0}' -f $($_)) -WindowStyle Hidden -Wait } Write-Host "Removing Windows Update Client Settings..." -NoNewline -ForegroundColor Cyan Remove-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate" -Name AccountDomainSid -Force Remove-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate" -Name PingID -Force Remove-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate" -Name SusClientId -Force Write-Host "Restarting the BITS, wuauserv, AppIDSvc and CryptSvc services..." -NoNewline -ForegroundColor Cyan Start-Process -FilePath NETSH -ArgumentList ('WINSOCK RESET') -WindowStyle Hidden -Wait Start-Process -FilePath NETSH -ArgumentList ('WINHTTP RESET PROXY') -WindowStyle Hidden -Wait Get-BitsTransfer | Remove-BitsTransfer Get-Service -Name BITS, wuauserv, AppIDSvc, CryptSvc, DcomLaunch, TrustedInstaller | Set-Service -StartupType Automatic Get-Service -Name BITS, wuauserv, AppIDSvc, CryptSvc | Where-Object -Property Status -EQ Stopped | Start-Service Write-Host "[Complete]" -ForegroundColor Cyan $Wshell = New-Object -ComObject Wscript.Shell $Popup = $Wshell.Popup("Restart $($Env:COMPUTERNAME) complete the reset?", 10, "Restart Device", 4 + 32) If ($Popup -eq 6) { $Restart = 15 ForEach ($Count In (1 .. $Restart)) { Write-Progress -Id 1 -Activity "Restarting $($Env:COMPUTERNAME) to complete the reset" -Status "Restarting in $Restart seconds, $($Restart - $Count) seconds left" -PercentComplete (($Count / $Restart) * 100) Start-Sleep -Seconds 1 } Restart-Computer } } End { [void][Runtime.InteropServices.Marshal]::ReleaseComObject($WShell) $ErrorActionPreference = $DefaultErrorAction } }
It works perfectly fine. It's a function, so open PowerShell ISE, copy the contents of the .ps1 into the script pane, hit F5 then type the Start-WindowsCleanup or Reset-WindowsUpdate...whichever you want to run. Of you can copy and paste all of its contents in a regular elevated PowerShell console shell and type the function command.
After hitting F5 in PowerShell ISE, you can see it automatically detects the command and the parameters available to it. And just hit enter to run it:
Thanks.. just tried Windows cleanup, its really great, i guess i'll just replace the ccleaner with this one. I assume it'll work with win 7 too. btw if its possible please consider to make one click cleaner method for it for the convenience.
I know it's possible to use "dot sourcing" to execute functions from ps1 script Code: . .\script.ps1 or . C:\Downloads\script.ps1 Code: Start-WindowsCleanup i recommend not to remove all SoftwareDistribution contents, that will reset WU Download folder and maybe *.log is enough thanks
I personally prefer resetting Windows Update, as it returns all update programs back to their default settings; however, anyone using the function can simply remove that removal command or replace it with something else And yes you can dot source the script and run the function. Two dots sources the script so you can follow up with the function command itself in the console if you want to pass additional parameters. You would use a single dot to run a script, not a function.
You need to call the function name, not just load it into session. See the examples in the first post.
I got this error windows 10 version 2004 Code: Stopping the BITS, wuauserv, AppIDSvc and CryptSvc services...[Complete] Resetting Update Containers...WARNING: Failed to reset the Software Distribution folder. How to fix?