Automated Windows Clean-up PowerShell function.

Discussion in 'Scripting' started by GodHand, Jul 11, 2018.

  1. GodHand

    GodHand MDL Senior Member

    Jul 15, 2016
    341
    319
    10
    #1 GodHand, Jul 11, 2018
    Last edited: Aug 8, 2018
    **This has been updated. Its output it different, and is entirely verbose, outputting all its results and removals to a transcript log that is regenerated each time its run similar to Windows' logs.

    Also re-arranged how some process blocks run.**

    This is a fairly simple Windows Clean-up function I will adjust and use on both sysprep and live installations. I have added the bulk of the default folders and directories that can accumulate a sizable amount of junk. One can simply add, remove or change the directories that are cleaned-up to incorporate custom or additional folders to clean.

    What it does:
    - Measures the total size of all contents within a folder/directory that's being cleaned.
    - Performs the actual cleaning process, returning the total sum of all contents removed.
    - Enables all Clean-up Manager options by adding the StateFlags registry property to each key present.
    - Runs the Clean-up Manager process as a .NET object class to prevent its GUI output, thus not requiring you to check boxes for clean-up.
    - Disables all Clean-up Manager options previously added by removing the StateFlags registry property..
    - Returns a PSCustomObject showing combined clean-up results.

    Code:
    Function Start-WindowsCleanup {
    <#
        .SYNOPSIS
            Clean-up temporary files and folders and reclaim disk space.
        
        .DESCRIPTION
            This functions cleans-up temporary Windows files, folders and directories.
            This function runs the Windows Disk Clean-up Manager by enabling all of its available clean-up options within the registry and then running the CleanMgr.exe as a .NET process.
            It 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.
        
        .PARAMETER StateFlags
            An optional numerical value for the StateFlags registry property name.
            This is not mandatory and simply allows one to change the numerical value of the StateFlags property name to any integer between 1-9999.
        
        .EXAMPLE
            PS C:\> Start-WindowsCleanup
            PS C:\> Start-WindowsCleanup -StateFlags 1234
    #>
        [CmdletBinding(ConfirmImpact = 'High',
            SupportsShouldProcess = $true)]
        Param
        (
            [Parameter(Position = 0,
                HelpMessage = 'An optional numerical value for the StateFlags registry property name.')]
            [ValidateRange(1, 9999)]
            [int]$StateFlags = 1
        )
        Begin {
            $StateFlagsName = "StateFlags{0:D4}" -f $StateFlags
            $Report = "Start-WindowsCleanup_" + $(Get-Date -Format "MM-dd-yyyy")
            Start-Transcript -Path "$Env:SystemRoot\Temp\$Report.log"
            Function Clear-FolderContents {
                [CmdletBinding()]
                Param
                (
                    [string]$Folder,
                    [switch]$Recurse
                )
                If (Test-Path -Path $Folder) {
                    If ($Recurse) {
                        Get-ChildItem -Path $($Folder) -Recurse -Force -ErrorAction SilentlyContinue | Remove-Item -Recurse -Force -Verbose -ErrorAction SilentlyContinue
                    }
                    Else {
                        Remove-Item -Path $($Folder) -Force -Verbose -ErrorAction SilentlyContinue
                    }
                }
            }
        }
        Process {
            If ($PSCmdlet.ShouldProcess("$Env:COMPUTERNAME, all distribution, logging and temporary content will be lost.")) {
                $Before = Get-WmiObject Win32_LogicalDisk | Where-Object DriveType -EQ 3 | Select-Object `
                @{ 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-Warning "Cleaning-up Temporary, Distribution and Logging Folders. This may take a few minutes depending on their sizes. Please be patient."
                Start-Sleep 5
                Clear-Host
                Get-Service -Name wuauserv -ErrorAction SilentlyContinue | Stop-Service -Verbose
                Start-Sleep 3
                Clear-FolderContents -Folder "$Env:TEMP\*" -Recurse
                Clear-FolderContents -Folder "$Env:SystemRoot\Temp\*" -Recurse
                Clear-FolderContents -Folder "C:\Users\*\AppData\Local\Temp\*" -Recurse
                Clear-FolderContents -Folder "$Env:SystemRoot\SoftwareDistribution\*" -Recurse
                Clear-FolderContents -Folder "C:\Users\*\AppData\Local\Microsoft\Windows\Temporary Internet Files\*" -Recurse
                Clear-FolderContents -Folder "C:\Users\*\AppData\Local\Microsoft\Windows\WER\*" -Recurse
                Clear-FolderContents -Folder "C:\Users\*\AppData\Local\Microsoft\Windows\IECompatCache\*" -Recurse
                Clear-FolderContents -Folder "C:\Users\*\AppData\Local\Microsoft\Windows\IECompatUaCache\*" -Recurse
                Clear-FolderContents -Folder "C:\Users\*\AppData\Local\Microsoft\Windows\IEDownloadHistory\*" -Recurse
                Clear-FolderContents -Folder "C:\Users\*\AppData\Local\Microsoft\Windows\INetCache\*" -Recurse
                Clear-FolderContents -Folder "C:\Users\*\AppData\Local\Microsoft\Windows\INetCookies\*" -Recurse
                Clear-FolderContents -Folder "C:\Users\*\AppData\Local\Microsoft\Terminal Server Client\Cache\*" -Recurse
                Clear-FolderContents -Folder "$Env:ProgramData\Microsoft\Windows\WER\*" -Recurse
                Clear-FolderContents -Folder "$Env:SystemDrive\Windows\Logs\WindowsUpdate\*" -Recurse
                Clear-FolderContents -Folder "$Env:SystemRoot\Logs\CBS\*.log" -Recurse
                Clear-FolderContents -Folder "$Env:SystemRoot\Logs\DISM\*.log*" -Recurse
                Clear-FolderContents -Folder "$Env:SystemDrive\inetpub\logs\LogFiles\*" -Recurse
                Clear-FolderContents -Folder "$Env:SystemDrive\Intel\*" -Recurse
                Clear-FolderContents -Folder "$Env:SystemDrive\PerfLogs\*" -Recurse
                Clear-FolderContents -Folder "$Env:SystemRoot\minidump\*" -Recurse
                Clear-FolderContents -Folder "$Env:SystemRoot\Prefetch\*" -Recurse
                Clear-FolderContents -Folder "$Env:SystemRoot\memory.dmp"
                Clear-FolderContents -Folder "$Env:HOMEDRIVE\Config.Msi"
                If (Test-Path -Path 'C:\$Recycle.Bin') { Remove-Item -LiteralPath 'C:\$Recycle.Bin' -Recurse -Force -Confirm:$false -Verbose -ErrorAction SilentlyContinue }
                If ($PSVersionTable.PSVersion.Major -le 4) {
                    $RecycleBin = (New-Object -ComObject Shell.Application).NameSpace(0xA)
                    $RecycleBin.Items() | ForEach-Object -Process { Remove-Item -LiteralPath $_.Path -Recurse -Force -Confirm:$false -Verbose -ErrorAction SilentlyContinue }
                }
                ElseIf ($PSVersionTable.PSVersion.Major -ge 5) {
                    Clear-RecycleBin -Force -Confirm:$false -Verbose -ErrorAction SilentlyContinue
                }
                
                $VolumeCache = Get-ChildItem -Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\VolumeCaches"
                $VolumeCache.ForEach{
                    $EnableFlag = @{
                        Path         = $($_.PSPath)
                        Name         = $StateFlagsName
                        Value        = 2
                        PropertyType = 'DWORD'
                        Force        = $true
                        Verbose      = $true
                        ErrorAction  = 'SilentlyContinue'
                    }
                    [void](New-ItemProperty @EnableFlag)
                }
                
                $ObjProcessInfo = New-Object System.Diagnostics.ProcessStartInfo
                $ObjProcess = New-Object System.Diagnostics.Process
                $ObjProcessInfo.FileName = "$($Env:SystemRoot)\System32\cleanmgr.exe"
                $ObjProcessInfo.Arguments = '/SAGERUN:{0}' -f $StateFlags.ToString()
                $ObjProcessInfo.CreateNoWindow = $true
                $ObjProcess.StartInfo = $ObjProcessInfo
                [void]$ObjProcess.Start()
                $GetProcess = Get-Process -Name cleanmgr -ErrorAction SilentlyContinue
                While ($($GetProcess.Refresh(); $GetProcess.ProcessName)) { Start-Sleep 0.5 }
                Get-Process -Name explorer | Stop-Process -Verbose
                Start-Sleep 5
                Get-Service -Name wuauserv -ErrorAction SilentlyContinue | Start-Service -Verbose
                Start-Sleep 3
                $VolumeCache = Get-ChildItem -Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\VolumeCaches"
                $VolumeCache.ForEach{
                    $DisableFlag = @{
                        Path        = $($_.PSPath)
                        Name        = $StateFlagsName
                        ErrorAction = 'SilentlyContinue'
                    }
                    Get-ItemProperty @DisableFlag | Remove-ItemProperty -Name $StateFlagsName -Verbose -ErrorAction SilentlyContinue
                }
                $After = Get-WmiObject Win32_LogicalDisk | Where-Object DriveType -EQ 3 | Select-Object `
                @{ 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
                Clear-Host
                Write-Output "`t`t`tBefore Clean-up:`n$Before"
                Write-Output "`t`t`tAfter Clean-up:`n$After"
            }
        }
        End {
            Stop-Transcript
        }
    }
    # SIG # Begin signature block
    # MIIMBQYJKoZIhvcNAQcCoIIL9jCCC/ICAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB
    # gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR
    # AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQUJiHLBhOy0PVVKkjHuG0MYyp6
    # A7+gggj8MIIDfTCCAmWgAwIBAgIQfY66zkudTZ9EnV2nSZm8oDANBgkqhkiG9w0B
    # AQsFADBFMRQwEgYKCZImiZPyLGQBGRYEVEVDSDEVMBMGCgmSJomT8ixkARkWBU9N
    # TklDMRYwFAYDVQQDEw1PTU5JQy5URUNILUNBMB4XDTE4MDMxMzIxNTY1OFoXDTIz
    # MDMxMzIyMDY1OFowRTEUMBIGCgmSJomT8ixkARkWBFRFQ0gxFTATBgoJkiaJk/Is
    # ZAEZFgVPTU5JQzEWMBQGA1UEAxMNT01OSUMuVEVDSC1DQTCCASIwDQYJKoZIhvcN
    # AQEBBQADggEPADCCAQoCggEBAO6V7MmlK+QuOqWIzrLbmhv9acRXB46vi4RV2xla
    # MTDUimrSyGtpoDQTYK2QZ3idDq1nxrnfAR2XytTwVCcCFoWLpFFRack5k/q3QFFV
    # WP2DbSqoWfNG/EFd0qx8p81X5mH09t1mnN/K+BX1jiBS60rQYTsSGMkSSn/IUxDs
    # sLvatjToctZnCDiqG8SgPdWtVfHRLLMmT0l8paOamO0bpaSSsTpBaan+qiYidnxa
    # eIR23Yvv26Px1kMFYNp5YrWfWJEw5udB4W8DASO8TriypXXpca2jCEkVswNwNW/n
    # Ng7QQqECDVwVm3BVSClNcf1J52uU+Nvx36gKRl5xcogW4h0CAwEAAaNpMGcwEwYJ
    # KwYBBAGCNxQCBAYeBABDAEEwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQFMAMB
    # Af8wHQYDVR0OBBYEFH/3cqyAb+6RpNGa2+j3ldMI8axTMBAGCSsGAQQBgjcVAQQD
    # AgEAMA0GCSqGSIb3DQEBCwUAA4IBAQBYMivmEQPQpT1OfiPLVFaGFbnKmWo0dTWo
    # vkCQMq54NdUqvnCkOIC9O3nrsBqdQhTPAtDow1C1qWQipGf/JyMCTh9ZIEoz3u4z
    # RsiKMjIlPJkar1OsTsvKcAaya+a10LTcBMfF4DyOFaGqvKNrTaD3MmFQIBblQ8TS
    # QOzQPOXUwY/2IgI9w1AA8VO0N2coYzvj4i79RSQ77eg1iefjBRqs347o4/b7pWtS
    # 95+FBGr7JhhV3i9EI95172O4jmEkmoJQgr2mzvThjp9WiyeyjpnBAikV14YmEIyu
    # DmKue5ZuxG+D3W3ZwFyGytUCHYWwMshTRwI0z236dZG9OhYDSfibMIIFdzCCBF+g
    # AwIBAgITIQAAAAV87PzZFzK4xAAAAAAABTANBgkqhkiG9w0BAQsFADBFMRQwEgYK
    # CZImiZPyLGQBGRYEVEVDSDEVMBMGCgmSJomT8ixkARkWBU9NTklDMRYwFAYDVQQD
    # Ew1PTU5JQy5URUNILUNBMB4XDTE4MDQxODEyMjAzNloXDTE5MDQxODEyMjAzNlow
    # UzEUMBIGCgmSJomT8ixkARkWBFRFQ0gxFTATBgoJkiaJk/IsZAEZFgVPTU5JQzEO
    # MAwGA1UEAxMFVXNlcnMxFDASBgNVBAMTC0JlblRoZUdyZWF0MIIBIjANBgkqhkiG
    # 9w0BAQEFAAOCAQ8AMIIBCgKCAQEA9xWMMTEOCpdnZu3eDTVbytEzoTnHQYeS/2jg
    # wGLYU3+43C3viMoNVj+nLANJydTIRW5Dca+6JfO8UH25kf0XQ+AiXirQfjb9ec9u
    # I+au+krmlL1fSR076lPgYzqnqPMQzOER8U2J2+uF18UtxEVO3rq7Cnxlich4jXzy
    # gTy8XiNSAfUGR1nfq7HjahJ/CKopwl/7NcfmV5ZDzogRob1eErOPJXGAkewJuKqp
    # /qItYzGH+9XADCyO0GYVIOsXNIE0Ho0bdBPZ3eDdamL1vocTlEkTe0/drs3o2AkS
    # qcgg2I0uBco/p8CxCR7Tfq2zX1DFW9B7+KGNobxq+l+V15rTMwIDAQABo4ICUDCC
    # AkwwJQYJKwYBBAGCNxQCBBgeFgBDAG8AZABlAFMAaQBnAG4AaQBuAGcwEwYDVR0l
    # BAwwCgYIKwYBBQUHAwMwDgYDVR0PAQH/BAQDAgeAMB0GA1UdDgQWBBSIikO7ZjAP
    # GlMAUcP2kulHiqpJnDAfBgNVHSMEGDAWgBR/93KsgG/ukaTRmtvo95XTCPGsUzCB
    # yQYDVR0fBIHBMIG+MIG7oIG4oIG1hoGybGRhcDovLy9DTj1PTU5JQy5URUNILUNB
    # LENOPURPUkFETyxDTj1DRFAsQ049UHVibGljJTIwS2V5JTIwU2VydmljZXMsQ049
    # U2VydmljZXMsQ049Q29uZmlndXJhdGlvbixEQz1PTU5JQyxEQz1URUNIP2NlcnRp
    # ZmljYXRlUmV2b2NhdGlvbkxpc3Q/YmFzZT9vYmplY3RDbGFzcz1jUkxEaXN0cmli
    # dXRpb25Qb2ludDCBvgYIKwYBBQUHAQEEgbEwga4wgasGCCsGAQUFBzAChoGebGRh
    # cDovLy9DTj1PTU5JQy5URUNILUNBLENOPUFJQSxDTj1QdWJsaWMlMjBLZXklMjBT
    # ZXJ2aWNlcyxDTj1TZXJ2aWNlcyxDTj1Db25maWd1cmF0aW9uLERDPU9NTklDLERD
    # PVRFQ0g/Y0FDZXJ0aWZpY2F0ZT9iYXNlP29iamVjdENsYXNzPWNlcnRpZmljYXRp
    # b25BdXRob3JpdHkwMQYDVR0RBCowKKAmBgorBgEEAYI3FAIDoBgMFkJlblRoZUdy
    # ZWF0QE9NTklDLlRFQ0gwDQYJKoZIhvcNAQELBQADggEBAD1ZkdqIaFcqxTK1YcVi
    # QENxxkixwVHJW8ZATwpQa8zQBh3B1cMromiR6gFvPmphMI1ObRtuTohvuZ+4tK7/
    # IohAt6TwzyDFqY+/HzoNCat07Vb7DrA2fa+QMOl421kVUnZyYLI+gEod/zJqyuk8
    # ULBmUxCXxxH26XVC016AuoOedKwzBgAFyIDlIAivZcSOtaSyALJSZ2Pk29R69dp5
    # ICb+zCXCWPQJkbsU6eTlZAwaMmR2Vx4TQeDl49YIIwoDXDT4zBTcJ6n2k6vHQDWR
    # K9zaF4qAD9pwlQICbLgTeZBz5Bz2sXzhkPsmY6LNKTAOnuk0QbjsKXSKoB/QRAip
    # FiUxggJzMIICbwIBATBcMEUxFDASBgoJkiaJk/IsZAEZFgRURUNIMRUwEwYKCZIm
    # iZPyLGQBGRYFT01OSUMxFjAUBgNVBAMTDU9NTklDLlRFQ0gtQ0ECEyEAAAAFfOz8
    # 2RcyuMQAAAAAAAUwCQYFKw4DAhoFAKCB7TAZBgkqhkiG9w0BCQMxDAYKKwYBBAGC
    # NwIBBDAcBgorBgEEAYI3AgELMQ4wDAYKKwYBBAGCNwIBFTAjBgkqhkiG9w0BCQQx
    # FgQU+WtvgoATg1FLvyUQ6BJFONg+DPcwgYwGCisGAQQBgjcCAQwxfjB8oHqAeABD
    # AGwAZQBhAG4ALQB1AHAAIAB0AGUAbQBwAG8AcgBhAHIAeQAgAGYAaQBsAGUAcwAg
    # AGEAbgBkACAAZgBvAGwAZABlAHIAcwAgAGEAbgBkACAAcgBlAGMAbABhAGkAbQAg
    # AGQAaQBzAGsAIABzAHAAYQBjAGUALjANBgkqhkiG9w0BAQEFAASCAQAm/n004gbc
    # fw6k14VtbKlHkQfho6pG1F1mCeeCPachyM7R2Fsc2DvG2GgmkOsUgjaOy6NNFhHM
    # 3AURMSZn6Ip85C1auFBrY36hNOeE/xx0bvqbQoC1iEwifZX8ino4zprGP3J9YYRb
    # H3Rv0VmAvleSIxs2r9tU2qRq7sBdAZZzO98eENjftmIW9S3b+uQb99pc9XlMOKbn
    # Tahyky3s3MK2iayxmnDKeYL2agRRvPAUKDIsvJX9TYTEwc1A0SVKbQUIMyuPGZoM
    # giq6RBbRNIsSfDgZUgIOHvxt2seXI4bdf8UNMztcVNXh3v5GQQ/MKKB9SCSSoQFe
    # tX5udpAjX5C0
    # SIG # End signature block
    To run, you can copy and paste the code into a PowerShell console/ISE, or right-click and run-as Administrator.
     
  2. tehhunter

    tehhunter MDL Novice

    Aug 9, 2012
    18
    4
    0
    thank you excellent