Start-WindowsCleanup

Discussion in 'Scripting' started by GodHand, Sep 18, 2019.

  1. GodHand

    GodHand MDL Senior Member

    Jul 15, 2016
    455
    544
    10
    #1 GodHand, Sep 18, 2019
    Last edited: Oct 16, 2019
    Changed quite a bit up. Details are in the header notes for the function.

    Updated 10-16-2019: Added the option to remove any system restore points to the -Include parameter.

    Code:
    Function Start-WindowsCleanup
    {
    <#
        .SYNOPSIS
            Cleans-up temporary files and folders and reclaim disk space.
    
        .DESCRIPTION
            Cleans-up multiple areas of the Windows file system for both the current running user and the global system.
            Sets the StateFlags property on the VolumeCache subkeys in the registry and runs the Windows CleanMgr utility in advanced mode as a .NET process.
            Monitors the Windows CleanMgr utility .NET processes until completion.
            Removes the StateFlags property on the VolumeCache subkeys once the Windows CleanMgr utility has completed.
            Logs all clean-up actions to a transcript that is saved in the C:\Windows\Temp directory.
    
        .PARAMETER Include
            Valid settings for this parameter are:
    
            Downloads = Removes all content from all download folders and directories on the system.
            Restore Points = Removes all shadow copies (restore points) on the system.
            Chrome = Removes all cache, cookies and histories for the Google Chrome web browser.
            Firefox = Removes all cache, cookies and histories for the Mozilla Firefox web browser.
            IE = Removes all cache, cookies and histories for the Internet Explorer web browser.
            Edge = Removes all saved cache directories for the Microsoft Edge web browser.
    
            More than one parameter value may be entered at a time. If, for example, you want to also remove all Restore Points and all content from the Chrome, Firefox and Internet Explorer user and system profile directories, the following values would be passed with the parameter:
            -Include 'Restore Points', 'Chrome', 'Firefox', 'IE'
    
        .PARAMETER Additional
            Removes any user-specific file, folder or directory passed to the parameter when the function is called. This can be a single object or an array of multiple objects.
    
        .PARAMETER Force
            This switch can only be used when the -Additional parameter is used and will force the removal of objects that require ACL permission changes.
    
        .EXAMPLE
            PS C:\> Start-WindowsCleanup
    
        .EXAMPLE
            PS C:\> Start-WindowsCleanup -Include Downloads
    
        .EXAMPLE
            PS C:\> Start-WindowsCleanup -Include 'Chrome', 'FireFox', 'Edge' -Additional 'C:\My Notes', 'C:\Executable', 'D:\MapData' -Force
    
        .NOTES
            The integer value for the StateFlags registry property is randomly created each time the function is run and is not set to a static value.
            On Windows 10 builds 18362 and above, 'Update Cleanup' is excluded from the cleanup process due to a current bug in these builds preventing future updates from installing if previous updates have been removed.
            Any permission errors returned when cleaning can be ignored.
    #>
    
        [CmdletBinding(DefaultParameterSetName = 'None',
                       ConfirmImpact = 'High',
                       SupportsShouldProcess = $true)]
        Param
        (
            [Parameter(Mandatory = $false,
                       HelpMessage = 'Includes the clean-up of Downloads, Restore Points, Google Chrome, Mozilla Firefox, Internet Explorer and Microsoft Edge.')]
            [ValidateSet('Downloads', 'Restore Points', 'Chrome', 'Firefox', 'IE', 'Edge')]
            [string[]]$Include = $null,
            [Parameter(ParameterSetName = 'Additional',
                       HelpMessage = 'Removes any user-specific file, folder or directory passed to the parameter when the function is called. This can be a single object or an array of multiple objects.')]
            [string[]]$Additional,
            [Parameter(ParameterSetName = 'Additional',
                       HelpMessage = 'This switch can only be used when the -Additional parameter is used and will force the removal of objects that require ACL permission changes.')]
            [switch]$Force
        )
    
        Begin
        {
            # Check to make sure we are running with administrator permissions.
            If (!([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator))
            {
                Write-Warning "This script requires elevated access. Please relaunch Start-WindowsCleanup with administrator permissions."; Break
            }
    
            # Generate the StateFlags integer string and set it to its registry property name.
            $StateFlags = [Convert]::ToString($(Get-Random -Minimum 1 -Maximum 9999))
            $PropertyName = 'StateFlags{0:D4}' -f $StateFlags
    
            # Create the name of the transcript log using Unix time.
            $Transcript = Join-Path -Path $Env:SystemRoot\Temp -ChildPath "Start-WindowsCleanup_$(Get-Date -Date (Get-Date).ToUniversalTime() -UFormat %s -Millisecond 0).log"
    
            # Exclude downloads folders by default.
            $Excluded = [System.Collections.ArrayList]@('DownloadsFolder')
    
            # If the running system is Windows 10 build 18362 or greater, disable the cleanup of updates.
            If ((Get-CimInstance -ClassName Win32_OperatingSystem).BuildNumber -ge 18362) { [void]$Excluded.Add('Update Cleanup') }
    
            # Assign the pre-cleanup storage state to a variable.
            $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 the transcript.
            Start-Transcript -Path $Transcript
        }
        Process
        {
            If ($PSCmdlet.ShouldProcess("$Env:COMPUTERNAME, All distribution, logging and temporary content will be lost."))
            {
                Clear-Host
    
                # The array list of folders and directories that will be cleared.
                $FolderList = [System.Collections.ArrayList]@((Join-Path -Path $Env:TEMP -ChildPath "\*"),
                    (Join-Path -Path "$(Split-Path -Path $Env:LOCALAPPDATA -Parent)\*" -ChildPath "Temp\*"),
                    (Join-Path -Path $Env:LOCALAPPDATA -ChildPath "Microsoft\Windows\WER\*"),
                    (Join-Path -Path "$(Split-Path -Path $Env:LOCALAPPDATA -Parent)\*" -ChildPath "Microsoft\Windows\WER\*"),
                    (Join-Path -Path $Env:LOCALAPPDATA -ChildPath "Microsoft\Terminal Server Client\Cache\*"),
                    (Join-Path -Path "$(Split-Path -Path $Env:LOCALAPPDATA -Parent)\*" -ChildPath "Microsoft\Terminal Server Client\Cache\*"),
                    (Join-Path -Path $Env:LOCALAPPDATA -ChildPath "Microsoft\Terminal Server Client\Cache\*"),
                    (Join-Path -Path $Env:SystemRoot -ChildPath "Temp\*"),
                    (Join-Path -Path $Env:SystemRoot -ChildPath "Logs\CBS\*.log"),
                    (Join-Path -Path $Env:SystemRoot -ChildPath "Logs\DISM\*.log*"),
                    (Join-Path -Path $Env:SystemRoot -ChildPath "Logs\MeasuredBoot\*.log"),
                    (Join-Path -Path $Env:SystemRoot -ChildPath "WinSxS\ManifestCache\*"),
                    (Join-Path -Path $Env:SystemRoot -ChildPath "Panther\UnattendGC\*.log"),
                    (Join-Path -Path $Env:SystemRoot -ChildPath "drivers\*"),
                    (Join-Path -Path $Env:SystemRoot -ChildPath "minidump\*"),
                    (Join-Path -Path $Env:SystemRoot -ChildPath "Prefetch\*"),
                    (Join-Path -Path $Env:SystemRoot -ChildPath "*.log"),
                    (Join-Path -Path $Env:SystemRoot -ChildPath "*.dmp"),
                    (Join-Path -Path $Env:SystemDrive -ChildPath "*.dmp"),
                    (Join-Path -Path $Env:SystemDrive -ChildPath "LiveKernelReports\*.dmp"),
                    (Join-Path -Path $Env:SystemDrive -ChildPath "File*.chk"),
                    (Join-Path -Path $Env:SystemDrive -ChildPath "Found.*\*.chk"),
                    (Join-Path -Path $Env:SystemDrive -ChildPath 'Windows.old'),
                    (Join-Path -Path $Env:SystemDrive -ChildPath "swtools\*"),
                    (Join-Path -Path $Env:SystemDrive -ChildPath "swsetup\*"),
                    (Join-Path -Path $Env:HOMEDRIVE -ChildPath "inetpub\logs\LogFiles\*"),
                    (Join-Path -Path $Env:HOMEDRIVE -ChildPath "PerfLogs\*"),
                    (Join-Path -Path $Env:HOMEDRIVE -ChildPath "Intel\*"),
                    (Join-Path -Path $Env:HOMEDRIVE -ChildPath 'Config.Msi'))
    
                If ($PSBoundParameters.Include)
                {
                    Switch ($PSBoundParameters.Include)
                    {
                        'Downloads'
                        {
                            # Add all download folders and directories if the -Include parameter with the 'Downloads' value is used.
                            $Excluded.Remove('DownloadsFolder')
                            $DownloadsList = @((Join-Path -Path "$(Split-Path $Env:LOCALAPPDATA -Parent)\*" -ChildPath "Downloads\*"),
                                (Join-Path -Path $Env:LOCALAPPDATA -ChildPath "Downloads\*"),
                                (Join-Path -Path $Env:SystemDrive -ChildPath "Users\Administrator\Downloads\*"),
                                (Join-Path -Path (Get-ItemPropertyValue -Path "HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders" -Name "{374DE290-123F-4565-9164-39C4925E467B}" -ErrorAction SilentlyContinue) -ChildPath "\*"))
                            [void]$FolderList.Add($DownloadsList)
                        }
                        'Restore Points'
                        {
                            # Delete all system shadow copies if the -Include parameter with the 'Restore Points' value is used.
                            If (Get-WmiObject -Class Win32_ShadowCopy)
                            {
                                Get-WmiObject -Class Win32_ShadowCopy | ForEach-Object -Process {
                                    Write-Verbose ('Performing the operation "Delete ShadowCopy" on target "{0}"' -f $($_.ID)) -Verbose
                                    $_.Delete()
                                }
                            }
                        }
                        'Chrome'
                        {
                            If (Get-Process -Name chrome -ErrorAction SilentlyContinue)
                            {
                                # Stop any running Google Chrome process.
                                $Retries = 5
                                While ($Retries -gt 0 -and ((Get-Process -Name chrome -ErrorAction SilentlyContinue).Responding -eq $true))
                                {
                                    Stop-Process -Name chrome -Force -Verbose -ErrorAction SilentlyContinue
                                    Start-Sleep -Seconds 1
                                    If ((Get-Process -Name chrome -ErrorAction SilentlyContinue).Responding -eq $true) { Start-Sleep -Seconds 5 }
                                    $Retries--
                                }
                            }
    
                            If (!(Get-Process -Name chrome -ErrorAction SilentlyContinue))
                            {
                                # Add all Google Chrome cache, cookie and history directories if the -Include parameter with the 'Chrome' value is used.
                                $ChromeList = @((Join-Path -Path "$(Split-Path -Path $Env:LOCALAPPDATA -Parent)\*" -ChildPath "Google\Chrome\User Data\Default\Cache*\*"),
                                    (Join-Path -Path $Env:LOCALAPPDATA -ChildPath "Google\Chrome\User Data\Default\Cache*\*"),
                                    (Join-Path -Path "$(Split-Path -Path $Env:LOCALAPPDATA -Parent)\*" -ChildPath "Google\Chrome\User Data\Default\Cookies\*"),
                                    (Join-Path -Path $Env:LOCALAPPDATA -ChildPath "Google\Chrome\User Data\Default\Cookies\*"),
                                    (Join-Path -Path "$(Split-Path -Path $Env:LOCALAPPDATA -Parent)\*" -ChildPath "Google\Chrome\User Data\Default\Media Cache\*"),
                                    (Join-Path -Path $Env:LOCALAPPDATA -ChildPath "Google\Chrome\User Data\Default\Media Cache\*"),
                                    (Join-Path -Path "$(Split-Path -Path $Env:LOCALAPPDATA -Parent)\*" -ChildPath "Google\Chrome\User Data\Default\Cookies-Journal\*"),
                                    (Join-Path -Path $Env:LOCALAPPDATA -ChildPath "Google\Chrome\User Data\Default\Cookies-Journal\*"))
                                [void]$FolderList.Add($ChromeList)
                            }
                        }
                        'Firefox'
                        {
                            If (Get-Process -Name firefox -ErrorAction SilentlyContinue)
                            {
                                # Stop any running Mozilla Firefox process.
                                $Retries = 5
                                While ($Retries -gt 0 -and ((Get-Process -Name firefox -ErrorAction SilentlyContinue).Responding -eq $true))
                                {
                                    Stop-Process -Name firefox -Force -Verbose -ErrorAction SilentlyContinue
                                    Start-Sleep -Seconds 1
                                    If ((Get-Process -Name firefox -ErrorAction SilentlyContinue).Responding -eq $true) { Start-Sleep -Seconds 5 }
                                    $Retries--
                                }
                            }
    
                            If (!(Get-Process -Name firefox -ErrorAction SilentlyContinue))
                            {
                                # Add all Mozilla Firefox cache, cookie and history directories if the -Include parameter with the 'Firefox' value is used.
                                $FirefoxList = @((Join-Path -Path "$(Split-Path -Path $Env:LOCALAPPDATA -Parent)\*" -ChildPath "Mozilla\Firefox\Profiles\*.default\Cache*\*"),
                                    (Join-Path -Path $Env:LOCALAPPDATA -ChildPath "Mozilla\Firefox\Profiles\*.default\Cache*\*"),
                                    (Join-Path -Path "$(Split-Path -Path $Env:LOCALAPPDATA -Parent)\*" -ChildPath "Mozilla\Firefox\Profiles\*.default\jumpListCache\*"),
                                    (Join-Path -Path $Env:LOCALAPPDATA -ChildPath "Mozilla\Firefox\Profiles\*.default\jumpListCache\*"),
                                    (Join-Path -Path "$(Split-Path -Path $Env:LOCALAPPDATA -Parent)\*" -ChildPath "Mozilla\Firefox\Profiles\*.default\thumbnails\*"),
                                    (Join-Path -Path $Env:LOCALAPPDATA -ChildPath "Mozilla\Firefox\Profiles\*.default\thumbnails\*"),
                                    (Join-Path -Path $Env:APPDATA -ChildPath "Mozilla\Firefox\Profiles\*.default\*sqlite*"))
                                [void]$FolderList.Add($FirefoxList)
                            }
                        }
                        'IE'
                        {
                            If (Get-Process -Name iexplore -ErrorAction SilentlyContinue)
                            {
                                # Stop any running Internet Explorer process.
                                $Retries = 5
                                While ($Retries -gt 0 -and ((Get-Process -Name iexplore -ErrorAction SilentlyContinue).Responding -eq $true))
                                {
                                    Stop-Process -Name iexplore -Force -Verbose -ErrorAction SilentlyContinue
                                    Start-Sleep -Seconds 1
                                    If ((Get-Process -Name iexplore -ErrorAction SilentlyContinue).Responding -eq $true) { Start-Sleep -Seconds 5 }
                                    $Retries--
                                }
                            }
    
                            If (!(Get-Process -Name iexplore -ErrorAction SilentlyContinue))
                            {
                                # Add all Internet Explorer cache, cookie and history directories if the -Include parameter with the 'IE' value is used.
                                $IEList = @((Join-Path -Path $Env:LOCALAPPDATA -ChildPath "Microsoft\Windows\INetCache\*"),
                                    (Join-Path -Path "$(Split-Path -Path $Env:LOCALAPPDATA -Parent)\*" -ChildPath "Microsoft\Windows\INetCache\*"),
                                    (Join-Path -Path $Env:LOCALAPPDATA -ChildPath "Microsoft\Windows\Temporary Internet Files\*"),
                                    (Join-Path -Path "$(Split-Path -Path $Env:LOCALAPPDATA -Parent)\*" -ChildPath "Microsoft\Windows\Temporary Internet Files\*"),
                                    (Join-Path -Path $Env:LOCALAPPDATA -ChildPath "Microsoft\Windows\IECompatCache\*"),
                                    (Join-Path -Path "$(Split-Path -Path $Env:LOCALAPPDATA -Parent)\*" -ChildPath "Microsoft\Windows\IECompatCache\*"),
                                    (Join-Path -Path $Env:LOCALAPPDATA -ChildPath "Microsoft\Windows\IECompatUaCache\*"),
                                    (Join-Path -Path "$(Split-Path -Path $Env:LOCALAPPDATA -Parent)\*" -ChildPath "Microsoft\Windows\IECompatUaCache\*"),
                                    (Join-Path -Path $Env:LOCALAPPDATA -ChildPath "Microsoft\Windows\IEDownloadHistory\*"),
                                    (Join-Path -Path "$(Split-Path -Path $Env:LOCALAPPDATA -Parent)\*" -ChildPath "Microsoft\Windows\IEDownloadHistory\*"),
                                    (Join-Path -Path $Env:LOCALAPPDATA -ChildPath "Microsoft\Windows\INetCookies\*"),
                                    (Join-Path -Path "$(Split-Path -Path $Env:LOCALAPPDATA -Parent)\*" -ChildPath "Microsoft\Windows\INetCookies\*"))
                                [void]$FolderList.Add($IEList)
                            }
                        }
                        'Edge'
                        {
                            @('MicrosoftEdge', 'MicrosoftEdgeCP', 'MicrosoftEdgeSH') | ForEach-Object -Process {
                                $EdgeProcess = $_
                                If (Get-Process -Name $EdgeProcess -ErrorAction SilentlyContinue)
                                {
                                    # Stop any running Microsoft Edge process.
                                    $Retries = 5
                                    While ($Retries -gt 0 -and ((Get-Process -Name $EdgeProcess -ErrorAction SilentlyContinue).Responding -eq $true))
                                    {
                                        Stop-Process -Name $EdgeProcess -Force -Verbose -ErrorAction SilentlyContinue
                                        Start-Sleep -Seconds 1
                                        If ((Get-Process -Name $EdgeProcess -ErrorAction SilentlyContinue).Responding -eq $true) { Start-Sleep -Seconds 5 }
                                        $Retries--
                                    }
                                }
                            }
    
                            If (!(Get-Process -Name @('MicrosoftEdge', 'MicrosoftEdgeCP', 'MicrosoftEdgeSH') -ErrorAction SilentlyContinue))
                            {
                                # Add all Microsoft Edge cache directories if the -Include parameter with the 'Edge' value is used.
                                $EdgeList = @((Join-Path -Path "$(Split-Path -Path $Env:LOCALAPPDATA -Parent)\*" -ChildPath "Packages\Microsoft.MicrosoftEdge_8wekyb3d8bbwe\AC\#!*"),
                                    (Join-Path -Path $Env:LOCALAPPDATA -ChildPath "Packages\Microsoft.MicrosoftEdge_8wekyb3d8bbwe\AC\#!*"))
                                [void]$FolderList.Add($EdgeList)
                            }
                        }
                    }
                }
    
                If ($Excluded -notcontains 'Update Cleanup')
                {
                    If ((Get-Service -Name wuauserv -ErrorAction SilentlyContinue).Status -ne 'Stopped')
                    {
                        # Stop any running Windows Update Service.
                        $Retries = 5
                        While ($Retries -gt 0 -and ((Get-Service -Name wuauserv -ErrorAction SilentlyContinue).Status -ne 'Stopped'))
                        {
                            Stop-Service -Name wuauserv -Force -Verbose -ErrorAction SilentlyContinue
                            Start-Sleep -Seconds 1
                            If ((Get-Service -Name wuauserv -ErrorAction SilentlyContinue).Status -eq 'Running') { Start-Sleep -Seconds 5 }
                            $Retries--
                        }
                    }
    
                    If ((Get-Service -Name wuauserv -ErrorAction SilentlyContinue).Status -ne 'Running')
                    {
                        # If 'Update Cleanup' has not been excluded, add the 'SoftwareDistribution\Downloads' directory.
                        [void]$FolderList.Add((Join-Path -Path $Env:SystemRoot -ChildPath "SoftwareDistribution\Download\*"))
                    }
                }
    
                # Remove all content from each path added to the array list.
                $FolderList | Remove-Items
    
                If ($FolderList -match 'SoftwareDistribution')
                {
                    # Restart the Windows Update Service since the 'SoftwareDistribution\Downloads' directory has been cleared.
                    Start-Service -Name wuauserv -Verbose -ErrorAction SilentlyContinue
                }
    
                If ($PSBoundParameters.Additional)
                {
                    # Remove any additional files, folders or directories that were passed with the -Additional parameter.
                    If ($Force.IsPresent) { $Additional | Remove-Items -Force }
                    Else { $Additional | Remove-Items }
                }
    
                # Remove any junk folders from the Windows directory.
                Get-ChildItem -Path $Env:SystemRoot -Directory -Force -ErrorAction SilentlyContinue | Where-Object { ($_.Name -match "^\{\w{8}-\w{4}-\w{4}-\w{4}-\w{12}\}$") -and ($_.Name -notmatch "win|prog|res|rec|driv") } | Remove-Items
    
                # Remove any junk folders from the root directory.
                Get-ChildItem -Path $Env:SystemDrive -Directory -Force -ErrorAction SilentlyContinue | Where-Object { ($_.Name -notmatch "win|prog|res|rec|driv") -and ($_.Name -match "^[a-z0-9]{15,}$") -and ((("$($_.Name)" -replace '[0-9]', '').Length * .9) -lt ("$($_.Name)" -replace '[^0-9]', '').Length) } | Remove-Items
    
                # Clear all Recycle Bin items.
                If ($PSVersionTable.PSVersion.Major -lt 5) { (New-Object -ComObject Shell.Application).NameSpace(0xA).Items() | ForEach-Object -Process { Remove-Item -Path $_.Path -Recurse -Force -Verbose -ErrorAction SilentlyContinue } }
                Else { Clear-RecycleBin -Force -Confirm:$false -Verbose -ErrorAction SilentlyContinue }
    
                # Remove the last accessed registry key.
                Remove-ItemProperty -Path "HKCU:\Software\Microsoft\Windows\CurrentVersion\Applets\Regedit" -Name LastKey -Force -Verbose -ErrorAction SilentlyContinue
    
                # Add the StateFlags property name to the registry.
                Get-ChildItem -Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\VolumeCaches" -Exclude $Excluded -ErrorAction SilentlyContinue | Set-ItemProperty -Name $PropertyName -Value 2 -Force -ErrorAction SilentlyContinue
    
                # Start the Cleanmgr.exe as a .NET process.
                $ProcessInfo = New-Object -TypeName System.Diagnostics.ProcessStartInfo
                $ProcessInfo.FileName = "$Env:SystemRoot\System32\cleanmgr.exe"
                $ProcessInfo.Arguments = '/SAGERUN:{0}' -f $StateFlags
                $ProcessInfo.CreateNoWindow = $true
                $Process = New-Object -TypeName System.Diagnostics.Process
                $Process.StartInfo = $ProcessInfo
                [void]$Process.Start()
                $Process.WaitForExit()
    
                # Remove the StateFlags property name from the registry.
                Get-ChildItem -Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\VolumeCaches" -Exclude $Excluded -ErrorAction SilentlyContinue | Remove-ItemProperty -Name $PropertyName -Force -ErrorAction SilentlyContinue
            }
        }
        End
        {
            # Assign the post-cleanup storage state to a variable.
            $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
            # Display the disk space reclaimed by the clean-up process.
            Write-Output "`n`n`t`t`tBefore Clean-up:`n$PreClean" -Verbose
            Write-Output "`n`n`t`t`tAfter Clean-up:`n$PostClean`n`n" -Verbose
    
            # Stop the transcript.
            Stop-Transcript
        }
    }
    
    # Create a helper function to aid in the clean-up process.
    Function Remove-Items
    {
        [CmdletBinding()]
        Param
        (
            [Parameter(ValueFromPipeline = $true,
                       ValueFromPipelineByPropertyName = $true)]
            [string[]]$Path,
            [switch]$Force
        )
    
        Process
        {
            ForEach ($Item In $Path)
            {
                $Item = $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($Item)
                If ($Force.IsPresent)
                {
                    If ($null -eq $Item) { Continue }
                    $MaxRetry = 5
                    If (((Get-Item -Path $Item -Force -ErrorAction SilentlyContinue) -isnot [IO.DirectoryInfo])) { $TAKEOWN = ('TAKEOWN.EXE /F "{0}" /A' -f $Item) }
                    Else { $TAKEOWN = ('TAKEOWN.EXE /F "{0}" /A /R /D Y' -f $Item) }
                    Do
                    {
                        $GetPermissions = $TAKEOWNResult = $ICACLSResult = $ATTRIBResult = $RemoveResult = $null
                        Write-Verbose "Executing $TAKEOWN"
                        $TAKEOWNResult = Invoke-Expression $TAKEOWN -ErrorAction SilentlyContinue
                        $ICACLS = ('ICACLS.EXE "{0}" /INHERITANCE:E /GRANT *S-1-5-32-544:F /T /Q /C /L' -f $Item)
                        Write-Verbose "Executing $ICACLS"
                        $ICACLSResult = Invoke-Expression $ICACLS -ErrorAction SilentlyContinue
                        $ATTRIB = ('ATTRIB.EXE -A "{0}" /S /D /L' -f $Item)
                        Write-Verbose "Executing $ATTRIB"
                        $ATTRIBResult = Invoke-Expression $ATTRIB -ErrorAction SilentlyContinue
                        Write-Verbose "Removing $Item"
                        Try { Remove-Item -Path $Item -Recurse -Force -Verbose -ErrorAction SilentlyContinue }
                        Catch { $RemoveResult = $($_.Exception.Message) }
                        $GetPermissions = ($TAKEOWNResult + $ICACLSResult + $ATTRIBResult + $RemoveResult) | Select-String -Pattern 'Access is denied'
                    }
                    While ($null -ne $GetPermissions -or (--$MaxRetry -le 0))
                }
                Else
                {
                    If (((Get-Item -Path $Item -Force -ErrorAction SilentlyContinue) -is [IO.DirectoryInfo])) { Get-ChildItem -Path $Item -Recurse -Force -ErrorAction SilentlyContinue | Remove-Item -Recurse -Force -Verbose -ErrorAction SilentlyContinue }
                    Else { Remove-Item -Path $Item -Recurse -Force -Verbose -ErrorAction SilentlyContinue }
                }
            }
        }
    }
     
  2. abbodi1406

    abbodi1406 MDL KB0000001

    Feb 19, 2011
    9,823
    37,261
    300
    The issues actually start with build 18362 (v1903), 18363 is just registry version for 1909 :)
     
  3. GodHand

    GodHand MDL Senior Member

    Jul 15, 2016
    455
    544
    10
    Thanks for the clarification. I changed it from 18363 to 18362.
     
  4. GodHand

    GodHand MDL Senior Member

    Jul 15, 2016
    455
    544
    10
    Added optional Microsoft Edge cache directory clean-up to the -Include parameter set.
     
  5. vigipirate

    vigipirate MDL Member

    Feb 24, 2011
    144
    38
    10
    please create broser bat or cmd
     
  6. GodHand

    GodHand MDL Senior Member

    Jul 15, 2016
    455
    544
    10
    What?
     
  7. coleoptere2007

    coleoptere2007 MDL Guru

    Apr 8, 2008
    2,688
    1,391
    90
    the guy ask you to create a batch or cmd file :laie:
     
  8. GodHand

    GodHand MDL Senior Member

    Jul 15, 2016
    455
    544
    10
    That's not going to happen.