Start-WindowsCleanup

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

  1. GodHand

    GodHand MDL Addicted

    Jul 15, 2016
    508
    750
    30
    #1 GodHand, Sep 18, 2019
    Last edited: May 10, 2020
    Updated 05-09-2020
    - Updated the code to include a new helper function to eliminate the redundant service and process stopping loops.
    - Included the clean-up of Microsoft Edge Chromium content in addition to the previously present Microsoft Edge HTML content.
    - The verification for the removal of downloaded content is now a messagebox utilizing Microsoft's PresentationFramework.

    Updated 05-03-2020
    - Added a -GUI switch, that can be used in place of the -Include parameter, that outputs a Gridview GUI list of all of the values in the -Include parameter allowing for the selection of items to include in the removal process as opposed to manually entering them.

    Updated 04-19-2020
    - Added the ability to remove all outdated and duplicate device drivers selectively to the -Include parameter.
    - Additional code improvements.

    Updated 03-13-2020
    - Added the ability to remove all event logs and event tracer log files to the -Include parameter.
    - Changed the -Include parameter 'Restore Points' to 'RestorePoints' for convenience.
    - Additional contextual modifications.

    Updated 02-25-2020
    - Added parameter and switch command example details.
    - Corrected a few typos.
    - Added additional code improvements.

    Updated 02-15-2020
    - Multiple code improvements and a correction to the switch statement.

    Updated 01-16-2020:
    - Added additional directories for removal.
    - Added methods to clean-up the component store and/or reset the image base using a background job.
    - Added a timed pop-up verification for the removal of download folders' contents in case it was accidentally entered when calling the function.
    - Assorted other code changes.

    Updated 10-23-2019: The package family name for the Microsoft Edge app is queried and used for the Microsoft Edge cache paths instead of a static string value. This ensures the proper paths are returned if the package family name changes down the road for some reason.

    Updated 11-09-2019: Assorted clean-up improvements.

    Updated 11-14-2019: Added additional logging and update clean-up locations. Tweaked the preclean-up and post clean-up results that get returned. Added some code changes and optimizations.

    Code:
    Function Start-WindowsCleanup
    {
        <#
        .SYNOPSIS
            Cleans-up a system clutter and reclaims 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.
            Removes the StateFlags property on the VolumeCache subkeys once the Windows CleanMgr utility has completed.
            Cleans-up the WinSxS Component Store by removing superseded component files and resetting the image base.
            Logs all clean-up actions to a transcript that is saved in the C:\Windows\Temp directory.
      
        .PARAMETER Include
            Includes user-specific directories, outside of temporary and logging directories, in the clean-up process. The acceptable values for this parameter are: Downloads, RestorePoints, EventLogs, DuplicateDrivers, Chrome, Firefox, IE and Edge.
          
            Downloads = Removes all content from all download folders and directories.
            RestorePoints = Removes all system restore points.
            EventLogs = Removes all event logs and event tracing log files.
            DuplicateDrivers = Outputs a Gridview list of any outdated and duplicate drivers for selective removal.
            Chrome = Removes all cache, cookie, history and logging directories for the Google Chrome web browser.
            Firefox = Removes all cache, cookie, history and logging directories for the Mozilla Firefox web browser.
            IE = Removes all cache, cookie, history and logging directories for the Internet Explorer web browser.
            Edge = Removes all cache, cookie, history and logging 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, Event Logs 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 'RestorePoints', 'EventLogs', 'Chrome', 'Firefox', 'IE'
      
        .PARAMETER GUI
            Outputs a Gridview GUI list of all of the values in the -Include parameter allowing for the selection of items to include in the removal process as opposed to manually entering them.
          
            This switch can be used in place of the -Include parameter.
      
        .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 ComponentCleanup
            Removes all superseded components in the component store.
      
        .PARAMETER ResetBase
            Removes all superseded components in the component store and also resets the image base, further reducing the size of the component store.
          
            By default the ResetBase feature is disabled for Windows 10 builds 18362 and above unless the -Force switch is used.
      
        .PARAMETER Force
            This switch can only be used with the Additional parameter, and ComponentCleanup and ResetBase switches.
          
            When used with the Additional parameter, any objects that contain access control list permissions will be force removed.
            When used with ResetBase switch, the ComponentCleanup with Image Base Reset will run on Windows 10 builds 18362 and above.
      
        .EXAMPLE
            PS C:\> Start-WindowsCleanup
          
            This command will clean-up all distribution, logging and temporary content.
      
        .EXAMPLE
            PS C:\> Start-WindowsCleanup -Include Downloads -ComponentCleanup
          
            This command will clean-up all distribution, logging and temporary content, remove any downloaded items and perform a clean-up of the Component Store.
      
        .EXAMPLE
            PS C:\> Start-WindowsCleanup -Include 'RestorePoints', 'EventLogs', 'DuplicateDrivers'
          
            This command will clean-up all distribution, logging and temporary content, remove all system restore points and output a Gridview list of any outdated and duplicate drivers for selective removal.
      
        .EXAMPLE
            PS C:\> Start-WindowsCleanup -Include 'Downloads', 'RestorePoints', 'EventLogs', 'Chrome', 'FireFox', 'Edge' -Additional 'C:\My Notes', 'C:\Executable', 'D:\MapData' -Force
          
            This command will perform six primary clean-up tasks:
            1 - Remove all distribution, logging and temporary content.
            2 = Remove any downloaded content.
            3 - Remove all system restore points.
            4 - Remove all event logs and event tracing log files.
            5 - Remove all cache, cookies, logging and temporary files and saved history for Google Chrome, Mozilla FireFox and Microsoft Edge.
            6 - Remove all additionally added objects by bypassing access control list permissions.
      
        .EXAMPLE
            PS C:\> Start-WindowsCleanup -GUI -ResetBase -Force
          
            This command will remove distribution, logging and temporary content, output a Gridview GUI list allowing for the selection of additional items to include in the clean-up process, clean-up the Component Store and perform an image base reset even if the Windows 10 build is 18362+ due to the -Force switch being used.
      
        .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, the ResetBase switch and 'Update Cleanup' are excluded from the cleanup process due to a current bug in these builds preventing future updates from installing if previous updates have been removed.
            On Windows 10 builds 18362 and above, the excluded ResetBase feature can be invoked if used with the Force switch.
            When removing outdated and duplicate drivers, ensure the current device driver is functioning properly as you will not be able to roll back the driver for that specific device.
            If the removal of outdated and duplicate drivers has been included in the removal process, realize it can take some time for the list of drivers installed on the system to be compiled so just be patient.
        #>
      
        [CmdletBinding(DefaultParameterSetName = 'None',
            ConfirmImpact = 'High',
            SupportsShouldProcess = $true)]
        Param
        (
            [Parameter(ParameterSetName = 'Include',
                HelpMessage = 'Includes the clean-up of Downloads, Restore Points, Event Logs, Google Chrome, Mozilla Firefox, Internet Explorer and Microsoft Edge.')]
            [ValidateSet('Downloads', 'RestorePoints', 'EventLogs', 'DuplicateDrivers', 'Chrome', 'Firefox', 'IE', 'Edge')]
            [String[]]$Include = $null,
            [Parameter(ParameterSetName = 'GUI',
                HelpMessage = 'Outputs a Gridview GUI list of all of the values in the -Include parameter allowing for the selection of items to include in the removal process as opposed to manually entering them.')]
            [Switch]$GUI,
            [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 = 'ComponentCleanup',
                HelpMessage = 'Removes all superseded components in the component store.')]
            [Switch]$ComponentCleanup,
            [Parameter(ParameterSetName = 'ResetBase',
                HelpMessage = 'Removes all superseded components in the component store and also resets the image base, further reducing the size of the component store.')]
            [Switch]$ResetBase,
            [Parameter(ParameterSetName = 'Additional',
                HelpMessage = 'Can only be used with the Additional and ResetBase parameters.')]
            [Parameter(ParameterSetName = 'ResetBase')]
            [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."; Exit }
          
            # Create helper functions to aid in the clean-up process.
            Function Remove-Items
            {
                [CmdletBinding()]
                Param
                (
                    [Parameter(Mandatory = $true,
                        ValueFromPipeline = $true,
                        ValueFromPipelineByPropertyName = $true)]
                    [Alias('FullName')]
                    [String[]]$Path,
                    [Switch]$Force
                )
              
                Process
                {
                    ForEach ($Item In $Path)
                    {
                        $Item = $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($Item)
                        If ($Force.IsPresent)
                        {
                            If ($null -eq $Item) { Continue }
                            $Retries = 5
                            If (((Get-Item -Path $Item -Force -ErrorAction SilentlyContinue) -is [IO.DirectoryInfo])) { $TAKEOWN = ('TAKEOWN.EXE /F "{0}" /A /R /D Y' -f $Item) }
                            Else { $TAKEOWN = ('TAKEOWN.EXE /F "{0}" /A' -f $Item) }
                            Do
                            {
                                $RET = $TAKEOWNRET = $ICACLSRET = $ATTRIBRET = $REMRET = $null
                                Write-Verbose ('Performing the operation {0}' -f $TAKEOWN) -Verbose
                                $TAKEOWNRET = Invoke-Expression $TAKEOWN
                                $ICACLS = ('ICACLS.EXE "{0}" /INHERITANCE:E /GRANT *S-1-5-32-544:F /T /Q /C /L' -f $Item)
                                Write-Verbose ('Performing the operation {0}' -f $ICACLS) -Verbose
                                $ICACLSRET = Invoke-Expression $ICACLS
                                $ATTRIB = ('ATTRIB.EXE -A "{0}" /S /D /L' -f $Item)
                                Write-Verbose ('Performing the operation {0}' -f $ATTRIB) -Verbose
                                $ATTRIBRET = Invoke-Expression $ATTRIB
                                Try { Remove-Item -Path $Item -Recurse -Force -Verbose }
                                Catch { $REMRET = $PSItem.Exception.Message }
                                $RET = ($TAKEOWNRET + $ICACLSRET + $ATTRIBRET + $REMRET) | Select-String -Pattern 'Access is denied'
                            }
                            While ($null -ne $RET -or (--$Retries -le 0))
                        }
                        Else
                        {
                            Try
                            {
                                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 }
                            }
                            Catch [UnauthorizedAccessException], [Management.Automation.ItemNotFoundException] { }
                        }
                    }
                }
            }
          
            Function Stop-Running
            {
                [CmdletBinding()]
                Param
                (
                    [Parameter(Mandatory = $true,
                        ValueFromPipeline = $true)]
                    [String[]]$Name
                )
              
                Process
                {
                    ForEach ($Object In $Name)
                    {
                        $Running = Get-Process | Where-Object -Property Name -Like *$Object*
                        If (!$Running) { $Running = Get-Service | Where-Object -Property Name -EQ $Object }
                        $Running | ForEach-Object -Process {
                            If ($PSItem -is [Diagnostics.Process])
                            {
                                If ($PSItem.Name -eq 'explorer')
                                {
                                    While ((Get-Process -Name explorer).HasExited -eq $false) { Stop-Process -Name explorer -Force -Verbose }
                                }
                                Else
                                {
                                    $Retries = 5
                                    While ($Retries -gt 0 -and ((Get-Process -Name $PSItem.Name -ErrorAction SilentlyContinue).Responding -eq $true))
                                    {
                                        Stop-Process -Name $PSItem.Name -Force -Verbose -ErrorAction SilentlyContinue
                                        Start-Sleep 1
                                        If ((Get-Process -Name $PSItem.Name -ErrorAction SilentlyContinue).Responding -eq $true) { Start-Sleep 5 }
                                        $Retries--
                                    }
                                }
                            }
                            ElseIf ($PSItem -is [ServiceProcess.ServiceController])
                            {
                                If ((Get-Service -Name $PSItem.Name -ErrorAction SilentlyContinue).Status -ne 'Stopped')
                                {
                                    $Retries = 5
                                    While ($Retries -gt 0 -and ((Get-Service -Name $PSItem.Name -ErrorAction SilentlyContinue).Status -ne 'Stopped'))
                                    {
                                        Stop-Service -Name $PSItem.Name -Force -Verbose -ErrorAction SilentlyContinue
                                        Start-Sleep 1
                                        If ((Get-Service -Name $PSItem.Name -ErrorAction SilentlyContinue).Status -eq 'Running') { Start-Sleep 5 }
                                        $Retries--
                                    }
                                }
                            }
                            Else
                            {
                                $null
                            }
                        }
                    }
                }
            }
          
            # Assign the local and global paths to their own variables for easier path building.
            $GlobalAppData = $Env:APPDATA
            $LocalAppData = $Env:LOCALAPPDATA
            $RootAppData = "$(Split-Path -Path $LocalAppData)\*"
          
            # 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
          
            # Assign 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.
            $ExcludedList = [Collections.Generic.List[String]]@('DownloadsFolder')
          
            # If the running system is Windows 10 build 18362 or greater, disable the ResetBase features unless the -Force switch is used.
            If ((Get-CimInstance -ClassName Win32_OperatingSystem).BuildNumber -ge 18362 -and $PSBoundParameters.ResetBase -and !$Force.IsPresent) { $ResetBase = $false }
          
            # If the ResetBase parameter set name is present, assign the name of the log that will be used for the PowerShell job using Unix time.
            If ($PSBoundParameters.ComponentCleanup -or $PSBoundParameters.ResetBase) { $DISMLog = Join-Path -Path $Env:TEMP -ChildPath "DismCleanupImage_$(Get-Date -Date (Get-Date).ToUniversalTime() -UFormat %s -Millisecond 0).log" }
          
            # 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) { $ExcludedList.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 @{ Name = 'Drive'; Expression = { ($PSItem.DeviceID) } },
                @{ Name = 'Size (GB)'; Expression = { '{0:N1}' -f ($PSItem.Size / 1GB) } },
                @{ Name = 'FreeSpace (GB)'; Expression = { '{0:N1}' -f ($PSItem.Freespace / 1GB) } },
                @{ Name = 'PercentFree'; Expression = { '{0:P1}' -f ($PSItem.FreeSpace / $PSItem.Size) } } | Format-Table -AutoSize | Out-String).Trim()
        }
        Process
        {
            If ($PSBoundParameters.ComponentCleanup -or $PSBoundParameters.ResetBase)
            {
                If ($PSCmdlet.ShouldProcess($Env:COMPUTERNAME, 'Remove all superseded components in the component store'))
                {
                    Clear-Host
                  
                    If ($PSBoundParameters.ComponentCleanup)
                    {
                        # Start a PowerShell Dism job to clean-up the Component Store.
                        Write-Verbose "Removing all superseded components in the component store." -Verbose
                        $DISMJob = Start-Job -ScriptBlock { Param ($DISMLog) Dism.exe /Online /Cleanup-Image /StartComponentCleanup | Out-File -FilePath $DISMLog } -ArgumentList $DISMLog -ErrorAction SilentlyContinue
                    }
                    ElseIf ($PSBoundParameters.ResetBase)
                    {
                        # Start a PowerShell Dism job to clean-up the Component Store and reset the image base.
                        Write-Verbose "Removing all superseded components in the component store and resetting the image base." -Verbose
                        $DISMJob = Start-Job -ScriptBlock { Param ($DISMLog) Dism.exe /Online /Cleanup-Image /StartComponentCleanup /ResetBase | Out-File -FilePath $DISMLog } -ArgumentList $DISMLog -ErrorAction SilentlyContinue
                    }
                  
                    Do
                    {
                        Start-Sleep 5
                        Get-Content -Path $DISMLog -Tail 3 | Select-String -Pattern '%' | Select-Object -Last 1
                    }
                    While ((Get-Job -Id $DISMJob.Id).State -eq 'Running')
                  
                    If ((Get-Job -Id $DISMJob.Id).State -eq 'Completed') { $DISMJob | Remove-Job -ErrorAction SilentlyContinue }
                  
                    $DISMLog | Remove-Items
                }
            }
          
            If (!$PSCmdlet.ShouldProcess($Env:COMPUTERNAME, 'Start-WindowsCleanup')) { Break }
          
            Clear-Host
          
            # Start the transcript.
            Start-Transcript -Path $Transcript
          
            # The list of initial items that will be cleaned-up.
            $RemovalList = [Collections.Generic.List[Object]]@(
                (Join-Path -Path $Env:TEMP -ChildPath "\*"),
                (Join-Path -Path $RootAppData -ChildPath "Temp\*"),
                (Join-Path -Path $LocalAppData -ChildPath "Microsoft\Windows\WER\*"),
                (Join-Path -Path $RootAppData -ChildPath "Microsoft\Windows\WER\*"),
                (Join-Path -Path $LocalAppData -ChildPath "Microsoft\Terminal Server Client\Cache\*"),
                (Join-Path -Path $RootAppData -ChildPath "Microsoft\Terminal Server Client\Cache\*"),
                (Join-Path -Path $LocalAppData -ChildPath "Microsoft\Terminal Server Client\Cache\*"),
                (Join-Path -Path $Env:SystemRoot -ChildPath "debug\WIA\*.log"),
                (Join-Path -Path $Env:SystemRoot -ChildPath "drivers\*"),
                (Join-Path -Path $Env:SystemRoot -ChildPath "INF\*.log*"),
                (Join-Path -Path $Env:SystemRoot -ChildPath "Logs\CBS\*Persist*"),
                (Join-Path -Path $Env:SystemRoot -ChildPath "Logs\DISM\*"),
                (Join-Path -Path $Env:SystemRoot -ChildPath "Logs\dosvc\*.*"),
                (Join-Path -Path $Env:SystemRoot -ChildPath "Logs\MeasuredBoot\*.log"),
                (Join-Path -Path $Env:SystemRoot -ChildPath "Logs\NetSetup\*.*"),
                (Join-Path -Path $Env:SystemRoot -ChildPath "Logs\SIH\*.*"),
                (Join-Path -Path $Env:SystemRoot -ChildPath "Logs\WindowsBackup\*.etl"),
                (Join-Path -Path $Env:SystemRoot -ChildPath "minidump\*"),
                (Join-Path -Path $Env:SystemRoot -ChildPath "Panther\UnattendGC\*.log"),
                (Join-Path -Path $Env:SystemRoot -ChildPath "Prefetch\*"),
                (Join-Path -Path $Env:SystemRoot -ChildPath "security\logs\*.*"),
                (Join-Path -Path $Env:SystemRoot -ChildPath "Temp\*"),
                (Join-Path -Path $Env:SystemRoot -ChildPath "WinSxS\ManifestCache\*"),
                (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 "File*.chk"),
                (Join-Path -Path $Env:SystemDrive -ChildPath "Found.*\*.chk"),
                (Join-Path -Path $Env:SystemDrive -ChildPath "LiveKernelReports\*.dmp"),
                (Join-Path -Path $Env:SystemDrive -ChildPath "swsetup\*"),
                (Join-Path -Path $Env:SystemDrive -ChildPath "swtools\*"),
                (Join-Path -Path $Env:SystemDrive -ChildPath "Windows.old"),
                (Join-Path -Path $Env:HOMEDRIVE -ChildPath "Config.Msi"),
                (Join-Path -Path $Env:HOMEDRIVE -ChildPath "inetpub\logs\LogFiles\*"),
                (Join-Path -Path $Env:HOMEDRIVE -ChildPath "Intel\*"),
                (Join-Path -Path $Env:HOMEDRIVE -ChildPath "PerfLogs\*")
            )
          
            If ($PSCmdlet.ParameterSetName -eq 'Include' -or $PSCmdlet.ParameterSetName -eq 'GUI')
            {
                If ($PSBoundParameters.GUI)
                {
                    # If the GUI parameter set name is present, create an output Gridview list allowing for the selection of items to include in the removal process.
                    $IncludeList = [Ordered]@{
                        Downloads        = 'Removes all content from all download folders and directories.'
                        RestorePoints    = 'Removes all system restore points.'
                        EventLogs        = 'Removes all event logs and event tracing log files.'
                        DuplicateDrivers = 'Outputs a Gridview list of any outdated and duplicate drivers for selective removal.'
                        Chrome           = 'Removes all cache, cookie, history and logging directories for the Google Chrome web browser.'
                        Firefox          = 'Removes all cache, cookie, history and logging directories for the Mozilla Firefox web browser.'
                        IE               = 'Removes all cache, cookie, history and logging directories for the Internet Explorer web browser.'
                        Edge             = 'Removes all cache, cookie, history and logging directories for the Microsoft Edge web browser.'
                    }
                    $IncludeList = $IncludeList.Keys | Select-Object -Property @{ Label = 'Name'; Expression = { $PSItem } }, @{ Label = 'Description'; Expression = { $IncludeList[$PSItem] } } | Out-GridView -Title "Select items to include in the clean-up process." -PassThru
                    If ($IncludeList) { $IncludeList = $IncludeList.GetEnumerator().Name }
                }
                Else
                {
                    If ($null -ne $Include) { $IncludeList = $Include }
                }
              
                If ($IncludeList)
                {
                    Switch ($IncludeList)
                    {
                        'Downloads'
                        {
                            # Before adding downloads content to the removal list, verify the parameter value was not issued by accident.
                            Add-Type -AssemblyName PresentationFramework
                            $Verify = [Windows.MessageBox]::Show('Are you sure you want to remove all downloads?', 'Verify Removal', 'YesNo', 'Question')
                            Switch ($Verify)
                            {
                                Yes { [Void]$ExcludedList.Remove('DownloadsFolder'); Break }
                                No { Break }
                                Default { Break }
                            }
                            # If verified, add all download folders and directories to the removal list.
                            If ($ExcludedList -notcontains 'DownloadsFolder')
                            {
                                $RemovalList.Add((
                                        (Join-Path -Path $RootAppData -ChildPath "Downloads\*"),
                                        (Join-Path -Path $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 "\*")
                                    ))
                            }
                        }
                        'RestorePoints'
                        {
                            # Delete all system shadow copies if the -Include parameter with the 'RestorePoints' 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 $PSItem.ID) -Verbose
                                    $PSItem.Delete()
                                }
                            }
                        }
                        'EventLogs'
                        {
                            # Delete all event logs and event tracer log files if the -Include parameter with the 'EventLogs' value is used.
                            Get-WinEvent -ListLog * | Where-Object { $PSItem.IsEnabled -eq $true -and $PSItem.RecordCount -gt 0 } | ForEach-Object -Process {
                                Write-Verbose ('Performing the operation "ClearLog" on target "{0}"' -f $PSItem.LogName) -Verbose
                                [Diagnostics.Eventing.Reader.EventLogSession]::GlobalSession.ClearLog($PSItem.LogName)
                            } 2> $null
                        }
                        'DuplicateDrivers'
                        {
                            # Delete all outdated and duplicate drivers if the -Include parameter with the 'DuplicateDrivers' value is used.
                            $AllDrivers = Get-WindowsDriver -Online -All | Where-Object -Property Driver -Like oem*inf | Select-Object -Property @{ Name = 'OriginalFileName'; Expression = { $PSItem.OriginalFileName | Split-Path -Leaf } }, Driver, ClassDescription, ProviderName, Date, Version
                            $DuplicateDrivers = $AllDrivers | Group-Object -Property OriginalFileName | Where-Object -Property Count -GT 1 | ForEach-Object -Process { $PSItem.Group | Sort-Object -Property Date -Descending | Select-Object -Skip 1 }
                            If ($DuplicateDrivers)
                            {
                                $DuplicateDrivers | Out-GridView -Title 'Remove Duplicate Drivers' -PassThru | ForEach-Object -Process {
                                    $Driver = $PSItem.Driver.Trim()
                                    Write-Verbose ('Performing the action "Delete Driver" on target {0}' -f $Driver) -Verbose
                                    Start-Process -FilePath PNPUTIL -ArgumentList ('/Delete-Driver {0} /Force' -f $Driver) -WindowStyle Hidden -Wait
                                }
                            }
                        }
                        'Chrome'
                        {
                            # Add all Google Chrome cache, cookie, history and logging directories if the -Include parameter with the 'Chrome' value is used.
                            'chrome' | Stop-Running
                            $RemovalList.Add((
                                    (Join-Path -Path $RootAppData -ChildPath "Google\Chrome\User Data\Default\Cache*\*"),
                                    (Join-Path -Path $LocalAppData -ChildPath "Google\Chrome\User Data\Default\Cache*\*"),
                                    (Join-Path -Path $RootAppData -ChildPath "Google\Chrome\User Data\Default\Cookies\*"),
                                    (Join-Path -Path $LocalAppData -ChildPath "Google\Chrome\User Data\Default\Cookies\*"),
                                    (Join-Path -Path $RootAppData -ChildPath "Google\Chrome\User Data\Default\Media Cache\*"),
                                    (Join-Path -Path $LocalAppData -ChildPath "Google\Chrome\User Data\Default\Media Cache\*"),
                                    (Join-Path -Path $RootAppData -ChildPath "Google\Chrome\User Data\Default\Cookies-Journal\*"),
                                    (Join-Path -Path $LocalAppData -ChildPath "Google\Chrome\User Data\Default\Cookies-Journal\*")
                                ))
                        }
                        'Firefox'
                        {
                            # Add all Mozilla Firefox cache, cookie, history and logging directories if the -Include parameter with the 'Firefox' value is used.
                            'firefox' | Stop-Running
                            $RemovalList.Add((
                                    (Join-Path -Path $RootAppData -ChildPath "Mozilla\Firefox\Profiles\*.default\Cache*\*"),
                                    (Join-Path -Path $LocalAppData -ChildPath "Mozilla\Firefox\Profiles\*.default\Cache*\*"),
                                    (Join-Path -Path $GlobalAppData -ChildPath "Mozilla\Firefox\Profiles\*.default\Cache*\*"),
                                    (Join-Path -Path $RootAppData -ChildPath "Mozilla\Firefox\Profiles\*.default\jumpListCache\*"),
                                    (Join-Path -Path $LocalAppData -ChildPath "Mozilla\Firefox\Profiles\*.default\jumpListCache\*"),
                                    (Join-Path -Path $GlobalAppData -ChildPath "Mozilla\Firefox\Profiles\*.default\jumpListCache\*"),
                                    (Join-Path -Path $RootAppData -ChildPath "Mozilla\Firefox\Profiles\*.default\thumbnails\*"),
                                    (Join-Path -Path $LocalAppData -ChildPath "Mozilla\Firefox\Profiles\*.default\thumbnails\*"),
                                    (Join-Path -Path $GlobalAppData -ChildPath "Mozilla\Firefox\Profiles\*.default\*sqlite*"),
                                    (Join-Path -Path $RootAppData -ChildPath "Mozilla\Firefox\Profiles\*.default\*.log"),
                                    (Join-Path -Path $LocalAppData -ChildPath "Mozilla\Firefox\Profiles\*.default\*.log"),
                                    (Join-Path -Path $GlobalAppData -ChildPath "Mozilla\Firefox\Profiles\*.default\*.log"),
                                    (Join-Path -Path $RootAppData -ChildPath "Mozilla\Firefox\Profiles\*.default\storage\*"),
                                    (Join-Path -Path $LocalAppData -ChildPath "Mozilla\Firefox\Profiles\*.default\storage\*"),
                                    (Join-Path -Path $GlobalAppData -ChildPath "Mozilla\Firefox\Profiles\*.default\storage\*"),
                                    (Join-Path -Path $RootAppData -ChildPath "Mozilla\Firefox\Crash Reports\*"),
                                    (Join-Path -Path $LocalAppData -ChildPath "Mozilla\Firefox\Crash Reports\*"),
                                    (Join-Path -Path $GlobalAppData -ChildPath "Mozilla\Firefox\Crash Reports\*"),
                                    (Join-Path -Path $RootAppData -ChildPath "Mozilla\Firefox\Profiles\*.default\startupCache\*"),
                                    (Join-Path -Path $LocalAppData -ChildPath "Mozilla\Firefox\Profiles\*.default\startupCache\*"),
                                    (Join-Path -Path $GlobalAppData -ChildPath "Mozilla\Firefox\Profiles\*.default\datareporting\*")
                                ))
                        }
                        'IE'
                        {
                            # Add all Internet Explorer cache, cookie, history and logging directories if the -Include parameter with the 'IE' value is used.
                            'iexplore' | Stop-Running
                            $RemovalList.Add((
                                    (Join-Path -Path $LocalAppData -ChildPath "Microsoft\Internet Explorer\*.log"),
                                    (Join-Path -Path $RootAppData -ChildPath "Microsoft\Internet Explorer\*.log"),
                                    (Join-Path -Path $LocalAppData -ChildPath "Microsoft\Internet Explorer\*.txt"),
                                    (Join-Path -Path $RootAppData -ChildPath "Microsoft\Internet Explorer\*.txt"),
                                    (Join-Path -Path $LocalAppData -ChildPath "Microsoft\Internet Explorer\CacheStorage\*.*"),
                                    (Join-Path -Path $RootAppData -ChildPath "Microsoft\Internet Explorer\CacheStorage\*.*"),
                                    (Join-Path -Path $LocalAppData -ChildPath "Microsoft\Windows\INetCache\*"),
                                    (Join-Path -Path $RootAppData -ChildPath "Microsoft\Windows\INetCache\*"),
                                    (Join-Path -Path $LocalAppData -ChildPath "Microsoft\Windows\Temporary Internet Files\*"),
                                    (Join-Path -Path $RootAppData -ChildPath "Microsoft\Windows\Temporary Internet Files\*"),
                                    (Join-Path -Path $LocalAppData -ChildPath "Microsoft\Windows\IECompatCache\*"),
                                    (Join-Path -Path $RootAppData -ChildPath "Microsoft\Windows\IECompatCache\*"),
                                    (Join-Path -Path $LocalAppData -ChildPath "Microsoft\Windows\IECompatUaCache\*"),
                                    (Join-Path -Path $RootAppData -ChildPath "Microsoft\Windows\IECompatUaCache\*"),
                                    (Join-Path -Path $LocalAppData -ChildPath "Microsoft\Windows\IEDownloadHistory\*"),
                                    (Join-Path -Path $RootAppData -ChildPath "Microsoft\Windows\IEDownloadHistory\*"),
                                    (Join-Path -Path $LocalAppData -ChildPath "Microsoft\Windows\INetCookies\*"),
                                    (Join-Path -Path $RootAppData -ChildPath "Microsoft\Windows\INetCookies\*")
                                ))
                        }
                        'Edge'
                        {
                            # Add Microsoft Edge HTML and Microsoft Edge Chromium cache, cookie, history and logging directories if the -Include parameter with the 'Edge' value is used.
                            'msedge', 'MicrosoftEdge*' | Stop-Running
                            If (Get-AppxPackage -Name Microsoft.MicrosoftEdge | Select-Object -ExpandProperty PackageFamilyName)
                            {
                                $EdgePackageName = Get-AppxPackage -Name Microsoft.MicrosoftEdge | Select-Object -ExpandProperty PackageFamilyName
                                $RemovalList.Add((
                                        (Join-Path -Path $RootAppData -ChildPath "Packages\$EdgePackageName\AC\#!00*"),
                                        (Join-Path -Path $LocalAppData -ChildPath "Packages\$EdgePackageName\AC\#!00*"),
                                        (Join-Path -Path $RootAppData -ChildPath "Packages\$EdgePackageName\AC\Temp\*"),
                                        (Join-Path -Path $LocalAppData -ChildPath "Packages\$EdgePackageName\AC\Temp\*"),
                                        (Join-Path -Path $RootAppData -ChildPath "Packages\$EdgePackageName\AC\Microsoft\Cryptnet*Cache\*"),
                                        (Join-Path -Path $LocalAppData -ChildPath "Packages\$EdgePackageName\AC\Microsoft\Cryptnet*Cache\*"),
                                        (Join-Path -Path $RootAppData -ChildPath "Packages\$EdgePackageName\AC\MicrosoftEdge\Cookies\*"),
                                        (Join-Path -Path $LocalAppData -ChildPath "Packages\$EdgePackageName\AC\MicrosoftEdge\Cookies\*"),
                                        (Join-Path -Path $RootAppData -ChildPath "Packages\$EdgePackageName\AC\MicrosoftEdge\UrlBlock\*.tmp"),
                                        (Join-Path -Path $LocalAppData -ChildPath "Packages\$EdgePackageName\AC\MicrosoftEdge\UrlBlock\*.tmp"),
                                        (Join-Path -Path $RootAppData -ChildPath "Packages\$EdgePackageName\AC\MicrosoftEdge\User\Default\ImageStore\*"),
                                        (Join-Path -Path $LocalAppData -ChildPath "Packages\$EdgePackageName\AC\MicrosoftEdge\User\Default\ImageStore\*"),
                                        (Join-Path -Path $RootAppData -ChildPath "Packages\$EdgePackageName\AC\MicrosoftEdge\User\Default\Recovery\Active\*.dat"),
                                        (Join-Path -Path $LocalAppData -ChildPath "Packages\$EdgePackageName\AC\MicrosoftEdge\User\Default\Recovery\Active\*.dat"),
                                        (Join-Path -Path $RootAppData -ChildPath "Packages\$EdgePackageName\AC\MicrosoftEdge\User\Default\DataStore\Data\nouser1\*\DBStore\LogFiles\*"),
                                        (Join-Path -Path $LocalAppData -ChildPath "Packages\$EdgePackageName\AC\MicrosoftEdge\User\Default\DataStore\Data\nouser1\*\DBStore\LogFiles\*"),
                                        (Join-Path -Path $RootAppData -ChildPath "Packages\$EdgePackageName\AC\MicrosoftEdge\User\Default\DataStore\Data\nouser1\*\Favorites\*.ico"),
                                        (Join-Path -Path $LocalAppData -ChildPath "Packages\$EdgePackageName\AC\MicrosoftEdge\User\Default\DataStore\Data\nouser1\*\Favorites\*.ico"),
                                        (Join-Path -Path $RootAppData -ChildPath "Packages\$EdgePackageName\AppData\User\Default\Indexed DB\*"),
                                        (Join-Path -Path $LocalAppData -ChildPath "Packages\$EdgePackageName\AppData\User\Default\Indexed DB\*"),
                                        (Join-Path -Path $RootAppData -ChildPath "Packages\$EdgePackageName\TempState\*"),
                                        (Join-Path -Path $LocalAppData -ChildPath "Packages\$EdgePackageName\TempState\*"),
                                        (Join-Path -Path $RootAppData -ChildPath "Packages\$EdgePackageName\LocalState\Favicons\PushNotificationGrouping\*"),
                                        (Join-Path -Path $LocalAppData -ChildPath "Packages\$EdgePackageName\LocalState\Favicons\PushNotificationGrouping\*")
                                    ))
                            }
                            If ((Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\msedge.exe" -ErrorAction Ignore) -or @((Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*" -ErrorAction Ignore | Where-Object -Property DisplayName -EQ 'Microsoft Edge'), (Get-ItemProperty -Path "HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*" -ErrorAction Ignore | Where-Object -Property DisplayName -EQ 'Microsoft Edge')))
                            {
                                $RemovalList.Add((
                                        (Join-Path -Path $LocalAppData -ChildPath "Microsoft\Edge\User Data\Profile *\Cache\*"),
                                        (Join-Path -Path $LocalAppData -ChildPath "Microsoft\Edge\User Data\Profile *\Code Cache\js\*"),
                                        (Join-Path -Path $LocalAppData -ChildPath "Microsoft\Edge\User Data\Profile *\Code Cache\wasm\*"),
                                        (Join-Path -Path $LocalAppData -ChildPath "Microsoft\Edge\User Data\Profile *\Cookies\*"),
                                        (Join-Path -Path $LocalAppData -ChildPath "Microsoft\Edge\User Data\CrashPad\*.pma"),
                                        (Join-Path -Path $LocalAppData -ChildPath "Microsoft\Edge\User Data\CrashPad\metadata"),
                                        (Join-Path -Path $LocalAppData -ChildPath "Microsoft\Edge\User Data\Profile *\data_reduction_proxy_leveldb\*"),
                                        (Join-Path -Path $LocalAppData -ChildPath "Microsoft\Edge\User Data\Profile *\Extension State\*"),
                                        (Join-Path -Path $LocalAppData -ChildPath "Microsoft\Edge\User Data\Profile *\Feature Engagement Package\AvailabilityDB\*"),
                                        (Join-Path -Path $LocalAppData -ChildPath "Microsoft\Edge\User Data\Profile *\Feature Engagement Package\EventDB\*"),
                                        (Join-Path -Path $LocalAppData -ChildPath "Microsoft\Edge\User Data\Profile *\File System\000\*"),
                                        (Join-Path -Path $LocalAppData -ChildPath "Microsoft\Edge\User Data\Profile *\File System\Origins\*"),
                                        (Join-Path -Path $LocalAppData -ChildPath "Microsoft\Edge\User Data\Profile *\IndexedDB\*"),
                                        (Join-Path -Path $LocalAppData -ChildPath "Microsoft\Edge\User Data\Profile *\Service Worker\CacheStorage\*"),
                                        (Join-Path -Path $LocalAppData -ChildPath "Microsoft\Edge\User Data\Profile *\Service Worker\Database\*"),
                                        (Join-Path -Path $LocalAppData -ChildPath "Microsoft\Edge\User Data\Profile *\Service Worker\ScriptCache\*"),
                                        (Join-Path -Path $LocalAppData -ChildPath "Microsoft\Edge\User Data\Profile *\Current Tabs"),
                                        (Join-Path -Path $LocalAppData -ChildPath "Microsoft\Edge\User Data\Profile *\Last Tabs"),
                                        (Join-Path -Path $LocalAppData -ChildPath "Microsoft\Edge\User Data\Profile *\History"),
                                        (Join-Path -Path $LocalAppData -ChildPath "Microsoft\Edge\User Data\Profile *\History Provider Cache"),
                                        (Join-Path -Path $LocalAppData -ChildPath "Microsoft\Edge\User Data\Profile *\History-journal"),
                                        (Join-Path -Path $LocalAppData -ChildPath "Microsoft\Edge\User Data\Profile *\Network Action Predictor"),
                                        (Join-Path -Path $LocalAppData -ChildPath "Microsoft\Edge\User Data\Profile *\Top Sites"),
                                        (Join-Path -Path $LocalAppData -ChildPath "Microsoft\Edge\User Data\Profile *\Visited Links"),
                                        (Join-Path -Path $LocalAppData -ChildPath "Microsoft\Edge\User Data\Profile *\Login Data"),
                                        (Join-Path -Path $LocalAppData -ChildPath "Microsoft\Edge\User Data\Profile *\*\*.log"),
                                        (Join-Path -Path $LocalAppData -ChildPath "Microsoft\Edge\User Data\Profile *\*\*log*"),
                                        (Join-Path -Path $LocalAppData -ChildPath "Microsoft\Edge\User Data\Profile *\*\MANIFEST-*"),
                                        (Join-Path -Path $LocalAppData -ChildPath "Microsoft\Edge\User Data\Profile *\Shortcuts"),
                                        (Join-Path -Path $LocalAppData -ChildPath "Microsoft\Edge\User Data\Profile *\QuotaManager"),
                                        (Join-Path -Path $LocalAppData -ChildPath "Microsoft\Edge\User Data\Profile *\Web Data"),
                                        (Join-Path -Path $LocalAppData -ChildPath "Microsoft\Edge\User Data\Profile *\Current Session"),
                                        (Join-Path -Path $LocalAppData -ChildPath "Microsoft\Edge\User Data\Profile *\Last Session"),
                                        (Join-Path -Path $LocalAppData -ChildPath "Microsoft\Edge\User Data\Profile *\Session Storage\*"),
                                        (Join-Path -Path $LocalAppData -ChildPath "Microsoft\Edge\User Data\Profile *\Site Characteristics Database\*"),
                                        (Join-Path -Path $LocalAppData -ChildPath "Microsoft\Edge\User Data\Profile *\Sync Data\LevelDB\*"),
                                        (Join-Path -Path $Env:ProgramData -ChildPath "Microsoft\EdgeUpdate\Log\*"),
                                        (Join-Path -Path ${Env:ProgramFiles(x86)} -ChildPath "Microsoft\Edge\Application\SetupMetrics\*.pma"),
                                        (Join-Path -Path ${Env:ProgramFiles(x86)} -ChildPath "Microsoft\EdgeUpdate\Download\*")
                                    ))
                            }
                        }
                    }
                }
            }
          
            If ($ExcludedList -notcontains 'Update Cleanup')
            {
                # If 'Update Cleanup' has not been excluded, add the 'SoftwareDistribution\Downloads' directory and log files.
                'wuauserv' | Stop-Running
                $RemovalList.Add((
                        (Join-Path -Path $Env:SystemRoot -ChildPath "SoftwareDistribution\Download\*"),
                        (Join-Path -Path $Env:SystemRoot -ChildPath "SoftwareDistribution\DataStore\Logs\*.*"),
                        (Join-Path -Path $Env:SystemRoot -ChildPath "Logs\WindowsUpdate\*.*"),
                        (Join-Path -Path $Env:ProgramData -ChildPath "USOShared\Logs\*.*")
                    ))
            }
          
            # Remove all content from each path added to the array list.
            $RemovalList | Remove-Items
          
            If ($RemovalList -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.
                $Additional | Remove-Items -Force:$Force
            }
          
            # Remove any junk folders from the Windows directory.
            Get-ChildItem -Path $Env:SystemRoot -Directory -Force -ErrorAction SilentlyContinue | Where-Object { ($PSItem.Name -match "^\{\w{8}-\w{4}-\w{4}-\w{4}-\w{12}\}$") -and ($PSItem.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 { ($PSItem.Name -notmatch "win|prog|res|rec|driv") -and ($PSItem.Name -match "^[a-z0-9]{15,}$") -and ((("$($PSItem.Name)" -replace '[0-9]', '').Length * .9) -lt ("$($PSItem.Name)" -replace '[^0-9]', '').Length) } | Remove-Items
          
            # Remove all Recycle Bin items from all system drives. This method is more thorough than using its shell object or the Clear-RecycleBin cmdlet.
            Get-PSDrive -PSProvider FileSystem | ForEach-Object -Process {
                $RecycleBin = Join-Path -Path $PSItem.Root -ChildPath '$Recycle.Bin\'
                If (Test-Path -Path $RecycleBin) { Get-ChildItem -Path (Join-Path -Path $RecycleBin -ChildPath '*\$I*') -Recurse -Force -ErrorAction SilentlyContinue | ForEach-Object -Process { $($PSItem.FullName.Replace('$I', '$R')), $($PSItem.FullName) | Remove-Items } }
            }
          
            # 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 $ExcludedList -ErrorAction SilentlyContinue | Set-ItemProperty -Name $PropertyName -Value 2 -Force -ErrorAction SilentlyContinue
          
            # Start the Cleanmgr.exe as a .NET process.
            $ProcessInfo = New-Object -TypeName Diagnostics.ProcessStartInfo
            $ProcessInfo.FileName = '{0}' -f "$Env:SystemRoot\System32\cleanmgr.exe"
            $ProcessInfo.Arguments = '/SAGERUN:{0}' -f $StateFlags
            $ProcessInfo.CreateNoWindow = $true
            $Process = New-Object -TypeName Diagnostics.Process
            $Process.StartInfo = $ProcessInfo
            [Void]$Process.Start()
            $Process.WaitForExit()
            If ($null -ne $Process) { $Process.Dispose() }
          
            # Remove the StateFlags property name from the registry.
            Get-ChildItem -Path HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\VolumeCaches -Exclude $ExcludedList -ErrorAction SilentlyContinue | Remove-ItemProperty -Name $PropertyName -Force -ErrorAction SilentlyContinue
          
            # Restart the Windows Explorer process.
            'explorer' | Stop-Running
        }
        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 @{ Name = 'Drive'; Expression = { ($PSItem.DeviceID) } },
                @{ Name = 'Size (GB)'; Expression = { '{0:N1}' -f ($PSItem.Size / 1GB) } },
                @{ Name = 'FreeSpace (GB)'; Expression = { '{0:N1}' -f ($PSItem.Freespace / 1GB) } },
                @{ Name = 'PercentFree'; Expression = { '{0:P1}' -f ($PSItem.FreeSpace / $PSItem.Size) } } | Format-Table -AutoSize | Out-String).Trim()
          
            # Display the disk space reclaimed by the clean-up process.
            @(("`n`n`tBefore Clean-up:`n{0}" -f $PreClean), ("`n`n`tAfter Clean-up:`n{0}`n" -f $PostClean)) | Write-Output
          
            # Stop the transcript.
            Stop-Transcript -ErrorAction Ignore
            Write-Output ''
        }
    }
    
     
  2. abbodi1406

    abbodi1406 MDL KB0000001

    Feb 19, 2011
    10,653
    43,863
    340
    The issues actually start with build 18362 (v1903), 18363 is just registry version for 1909 :)
     
  3. GodHand

    GodHand MDL Addicted

    Jul 15, 2016
    508
    750
    30
    Thanks for the clarification. I changed it from 18363 to 18362.
     
  4. GodHand

    GodHand MDL Addicted

    Jul 15, 2016
    508
    750
    30
    Added optional Microsoft Edge cache directory clean-up to the -Include parameter set.
     
  5. vigipirate

    vigipirate MDL Member

    Feb 24, 2011
    177
    44
    10
    please create broser bat or cmd
     
  6. GodHand

    GodHand MDL Addicted

    Jul 15, 2016
    508
    750
    30
    What?
     
  7. coleoptere2007

    coleoptere2007 MDL Guru

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

    GodHand MDL Addicted

    Jul 15, 2016
    508
    750
    30
    That's not going to happen.
     
  9. GodHand

    GodHand MDL Addicted

    Jul 15, 2016
    508
    750
    30
    Updated with clean-up improvements.
     
  10. rayleigh_otter

    rayleigh_otter MDL Expert

    Aug 8, 2018
    1,121
    921
    60
    I would love to see bat/cmd versions(cos i know my way around them) of powersmell stuff but you have to accept and respect a developers choice. We have 2 choices, try to create our own bats or learn powersmell.
     
  11. MMIKEE

    MMIKEE MDL Senior Member

    Oct 6, 2012
    322
    292
    10
    GUI's <and / or> bat/cmd scripts to be able to use @GodHand powershell scripts would be Greatly Appreciated since NOT every MDL member is a powershell expert or even remotely close to being one...
     
    Stop hovering to collapse... Click to collapse... Hover to expand... Click to expand...
  12. GodHand

    GodHand MDL Addicted

    Jul 15, 2016
    508
    750
    30
    You do not have to be anywhere close to a "PowerShell expert" to run any of the functions I post - that's why I post them.

    Functions can be copied and then pasted right into an elevated PowerShell console and then executed by typing the function name, or they can be saved saved to a .ps1 file and called directly within a PowerShell console like you'd call one batch script from another.
     
  13. rayleigh_otter

    rayleigh_otter MDL Expert

    Aug 8, 2018
    1,121
    921
    60
    Knowing something works isnt enough for me, i like to know how and why, thats how i learnt the basics of bat's and cmd's.
     
  14. rayleigh_otter

    rayleigh_otter MDL Expert

    Aug 8, 2018
    1,121
    921
    60
    Just out of interest @GodHand, do you know of a tool that converts bats and cmds to powershell? I prefer to use one type of file only and combine stuff into 1 large script rather than seperate bats/cmds and powershells.
     
  15. GodHand

    GodHand MDL Addicted

    Jul 15, 2016
    508
    750
    30
    #15 GodHand, Nov 10, 2019
    Last edited: Nov 10, 2019
    (OP)
    There is no tool that can do that. PowerShell code logic and syntax are completely different and you can't just convert it - you have to rewrite it.

    You can execute bat/cmd scripts within PowerShell and monitor them using many PowerShell's cmdlets, though, which is not hard. Likewise, you can encode PowerShell scripts and execute them within bat/cmd scripts.

    If you are interested in learning and knowing the 'how and why,' why are you asking me to create a version in a depreciated format for you instead of taking the time to look at the code to understand exactly what it's doing?

    It's not a complicated function.
     
  16. rayleigh_otter

    rayleigh_otter MDL Expert

    Aug 8, 2018
    1,121
    921
    60
    Im not. You create a PS script in that format only as is your right to do so i want to learn PS so i know what you do and how you do it. Im backing you on your choice of PS scripts only, im on your side. :)
     
  17. GodHand

    GodHand MDL Addicted

    Jul 15, 2016
    508
    750
    30
    Updated 11-14-2019: Added additional logging and update clean-up locations. Tweaked the preclean-up and post clean-up results that get returned. Added some code changes and optimizations.
     
  18. GodHand

    GodHand MDL Addicted

    Jul 15, 2016
    508
    750
    30
    Updated 01-16-2020:
    - Added additional directories for removal.
    - Added methods to clean-up the component store and/or reset the image base using a background job.
    - Added a timed pop-up verification for the removal of download folders' contents in case it was accidentally entered when calling the function.
    - Assorted other code changes.
     
  19. Windows_Addict

    Windows_Addict MDL Addicted

    Jul 19, 2018
    502
    865
    30
    @vigipirate @rayleigh_otter @MMIKEE

    Batch script to call Powershell function,

    Save the Powershell (.ps1) script and batch script (.cmd) in the same directory.

    Code:
    @echo off
    
    reg query HKU\S-1-5-19 1>nul 2>nul || (
    echo ==== Error ====
    echo Right click on this file and select 'Run as administrator'
    echo Press any key to exit...
    pause >nul
    exit /b
    )
    
    REM                                                   File name                 Function name
    powershell -ExecutionPolicy ByPass -command ". "%~dp0Start-WindowsCleanup.ps1"; Start-WindowsCleanup;"
    pause
    It works with GodHand's other script too,
    P.S. To avoid any possible errors, make sure that the pathname does not have spaces or special characters.
     
  20. GodHand

    GodHand MDL Addicted

    Jul 15, 2016
    508
    750
    30
    Updated 02-13-2020
    - Multiple code improvements.