PowerShell: Performing System Disk Cleanup

Version 2:

# cleanupWindows.ps1
# Version 0.0.2

################################## Excuting Program as an Administrator ####################################
# Run this function ad-hoc to relaunch as Admin prior to going through the next commands
Function elevate{
    # Get the ID and security principal of the current user account
    $myWindowsID=[System.Security.Principal.WindowsIdentity]::GetCurrent()
    $myWindowsPrincipal=new-object System.Security.Principal.WindowsPrincipal($myWindowsID)

    # Get the security principal for the Administrator role
    $adminRole=[System.Security.Principal.WindowsBuiltInRole]::Administrator

    # Check to see if we are currently running "as Administrator"
    if ($myWindowsPrincipal.IsInRole($adminRole)){
        # We are running "as Administrator" - so change the title and background color to indicate this
        $Host.UI.RawUI.WindowTitle = $myInvocation.MyCommand.Definition + "(Elevated)"
        $Host.UI.RawUI.BackgroundColor = "Black"
        clear-host
    }else{
        # Relaunch as administrator
        start-process powershell -verb runas
        
        # Exit from the current, unelevated, process
        exit
        }        
    Write-Host -NoNewLine "Running as Administrator..."
    }

# Get the ID and security principal of the current user account
$myWindowsID=[System.Security.Principal.WindowsIdentity]::GetCurrent()
$myWindowsPrincipal=new-object System.Security.Principal.WindowsPrincipal($myWindowsID)
# Get the security principal for the Administrator role
$adminRole=[System.Security.Principal.WindowsBuiltInRole]::Administrator
# Check to see if we are currently running "as Administrator"
if ($myWindowsPrincipal.IsInRole($adminRole)){
    # We are running "as Administrator" - so change the title and background color to indicate this
    $Host.UI.RawUI.WindowTitle = $myInvocation.MyCommand.Definition + "(Elevated)"
    $Host.UI.RawUI.BackgroundColor = "Black"
    clear-host
}else{
    # We are not running "as Administrator" - so relaunch as administrator
    # Create a new process object that starts PowerShell
    $newProcess = new-object System.Diagnostics.ProcessStartInfo "PowerShell";
    
    # Specify the current script path and name as a parameter
    $newProcess.Arguments = $myInvocation.MyCommand.Definition;
    
    # Indicate that the process should be elevated
    $newProcess.Verb = "runas";
    
    # Start the new process
    [System.Diagnostics.Process]::Start($newProcess);
    
    # Exit from the current, unelevated, process
    exit
    }
Write-Host -NoNewLine "Running as Administrator..."
################################## Excuting Program as an Administrator ####################################

function cleanupWindows($removeBloatware=$true){
    ## Variables Declaration ####
    $prefetchData="$env:SystemDrive\Windows\Prefetch\*"
    $cbs="$env:SystemDrive\Windows\Logs\CBS\*"  
    $swtools="$env:SystemDrive\swtools\*" 
    $drivers="$env:SystemDrive\drivers\*" 
    $swsetup="$env:SystemDrive\swsetup\*"
    $softwareDistribution="$env:SystemDrive\Windows\SoftwareDistribution\Download\*"
    function cleanup{
        param([string[]]$directory)
        foreach ($x in $directory){
            if ($x.Substring($x.Length - 2) -ne "\*"){
                if($x.Substring($x.Length - 1) -ne "\"){$x+="\*"}else{$x+="*"}            
                }
            Remove-Item -Path $x -Force -Recurse -ea Ignore -Confirm:$false
        }
    }
    function runDiskCleanup{
        $ErrorActionPreference = 'Stop'
        Try{
            Start-Process -FilePath Cleanmgr -ArgumentList '/sagerun:1' -Wait
            write-host "Windows Disk Cleanup has been successful." -ForegroundColor Green
            return $true
        }
        Catch{
            write-warning $_
            return $False
        }
    }
    
    function runDism{
        $ErrorActionPreference = 'Stop'
        Try{
            $dismResult = dism.exe /online /cleanup-Image /spsuperseded
            If($dismResult -match 'The operation completed successfully\.$'){
                Write-Host "DISM Completed Successfully." -ForegroundColor Green
            }Else{
                Write-Host "DISM is unable to clean old ServicePack Files." -ForegroundColor Red
            }
            return $dismResult
        }
        Catch [System.Exception]{
            $ErrorActionPreference = 'SilentlyContinue'
            return $False
        }
    }
    
    function runIisCleanup{
        param(
            $deleteLogsOlderThanDays=30
        )
        $iisExists=.{Try{
                Import-Module WebAdministration -ErrorAction Stop
                return $True
            }Catch{
                return $False
            }}
        if($iisExists){
            $iisLogPaths = .{
                $null=Import-Module WebAdministration
                Add-PSSnapin WebAdministration -ErrorAction SilentlyContinue
                Import-Module WebAdministration -ErrorAction SilentlyContinue
                $iisLogs = @()
                foreach($website in $(get-website)){
                    $logDirectory="$($website.logFile.directory)\w3svc$($website.id)".replace("%SystemDrive%",$env:SystemDrive)
                    $logInfo = [pscustomobject] @{                    
                        sitename = $website.name
                        logDirectory = $logDirectory
                    }
                    $iisLogs += $logInfo
                }
                return $iisLogs
            }
            If($iisLogPaths){
                Foreach($item in $iisLogPaths){
                    Write-host "Checking Website : $($item.sitename)"
                    $oldLogs=.{
                        $ErrorActionPreference='stop'
                        Try{
                            $logFiles=Get-ChildItem $item.logDirectory -Recurse -File *.log -EA Ignore
                            $expiredLogs=$logFiles | where-object LastWriteTime -le ((get-date).AddDays(-$deleteLogsOlderThanDays))
                            return $expiredLogs.FullName
                        }Catch{
                            return $Null
                        }                    
                    }
                    If ($($oldLogs | Measure-Object).count -gt 0){ 
                        ForEach ($file in $oldLogs){
                            remove-item $file -force
                            write-host "Purged: $file"
                        } 
                    }else{ 
                        Write-Host "No IIS Log Files Older than $deleteLogsOlderThanDays days for $($item.sitename)." -ForegroundColor Green
                    }
                }
            Write-Host "IIS Log files purging older than $deleteLogsOlderThanDays days have completed!" -ForegroundColor Green
            }
        }else{
            write-host "IIS is not detected on $env:computername"
        }
    }

    function cleanUserProfiles{
        $profiles=(get-childitem c:\users -Directory -EA Ignore).Name
        if($profiles){
            Foreach($profile in $profiles){
                Write-host "Processing profile: $profile"
                $tempPath = "C:\Users\$profile\AppData\Local\Temp"
                $downloadPath = "C:\Users\$profile\Downloads"
                cleanup $tempPath
                cleanup $downloadPath
            }
        }
    }

    Function clearRecycleBinLegacy($retentionDays=0){
        # This function doesn't work on Windows 10
        Try{
            $shell = New-Object -ComObject Shell.Application
            $recycleBin = $shell.NameSpace(0xa)
            foreach($item in $recycleBin.Items()){
                $deletedDate = $recycleBin.GetDetailsOf($item,2) -replace "\u200f|\u200e","" #Invisible Unicode Characters
                $deletedDateTime = Get-Date $deletedDate 
                [Int]$deletedDays = (New-TimeSpan -Start $deletedDateTime -End $(Get-Date)).Days
                write-host $deletedDate
                If($deletedDays -ge $retentionDays){
                    Remove-Item -Path $item.Path -Confirm:$false -Force -Recurse
                }
            }
            return $true
        }Catch {
            write-warning $_
            return $false
        }
    }

    function removeBloatware{
        $osType=switch ((Get-CimInstance -ClassName Win32_OperatingSystem).ProductType){
            1 {'client'} # ClientOs
            2 {'domaincontroller'} #ServerOs
            3 {'memberserver'}
            }
        $windowsVersion=[System.Environment]::OSVersion.Version
        if($osType -eq 'client' -and $windowsVersion -ge [version]'10.0'){
            write-host 'Removing bloatware...'
            [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
            $bloatwareRemovalDownload="https://github.com/Sycnex/Windows10Debloater/archive/master.zip"
            $bloatwareRemovalDestination="C:\Temp\Windows10Debloater-master.zip"
            (New-Object System.Net.WebClient).DownloadFile($bloatwareRemovalDownload, $bloatwareRemovalDestination)
            $destination="C:\Temp"
            expand-archive -path $bloatwareRemovalDestination -DestinationPath $destination
            PowerShell.exe -executionpolicy bypass -File C:\Temp\Windows10Debloater-master\Windows10Debloater.ps1 -Confirm:$False   
        }else{
            write-host "Windows $windowsVersion is a $osType. Hence, this bloatware removal routine doesn't apply."
        }
    }

    write-host "Delete files in Temp directories..."
    cleanup 'C:\windows\Temp','C:\Temp'
    cleanup 'C:\ProgramData\Microsoft\Windows\WER\ReportArchive'
    cleanup 'C:\ProgramData\Microsoft\Windows\WER\ReportQueue'
    cleanup 'C:\ServiceProfiles\LocalService\AppData\Local\Temp'
    cleanup $softwareDistribution
    write-Host "Clean prefetch data..."
    cleanup  $prefetchData
    write-Host "Clean CBS logs..."
    $null=stop-service wuauserv
    cleanup $cbs
    start-service wuauserv
    write-Host "Clean swtools data..."
    cleanup  $swtools
    write-Host "Clean drivers data..."
    cleanup  $drivers
    write-Host "Clean swsetup data..."
    cleanup  $swsetup
    write-Host "Clean softwareDistribution data..."
    cleanup  $softwareDistribution
    cleanUserProfiles
    runDiskCleanup
    runDism
    runIisCleanup

    write-host "Disabling Automatic Startup Repair..."
    $null=cmd.exe /c "bcdedit /set {default} recoveryenabled No"
    $null=cmd.exe /c "bcdedit /set {default} bootstatuspolicy ignoreallfailures"

    write-host 'Turning off hibernation to remove disk reservations for that purpose'
    $null=powercfg /setactive SCHEME_MIN
    $null=powercfg /hibernate off

    $windowsVersion=[System.Environment]::OSVersion.Version
    if($windowsVersion -lt [version]'10.0'){
        clearRecycleBin
    }else{
        write-host 'Disabling Windows Media (a vector of attack surface from malware)'
        Disable-WindowsOptionalFeature -FeatureName "WindowsMediaPlayer" -Online

        write-host 'Disabling XPS...'
        Disable-WindowsOptionalFeature -Online -FeatureName "Printing-XPSServices-Features"

        write-host 'Removing Workfolder Client'
        Disable-WindowsOptionalFeature -Online -FeatureName "WorkFolders-Client"

        write-host 'Removing Windows Store'
        Get-AppxPackage -AllUsers | Where-Object {$_.Name -like "Microsoft.WindowsStore*"} | remove-appxpackage

        write-host "Clearing all superseded versions of every component in the component store...."
        # This also removes any backup components needed for uninstallation of service packs already installed
        Dism.exe /online /Cleanup-Image /startcomponentcleanup /resetbase 

        write-Host "Emptying Recycle Bin." -ForegroundColor Yellow      
        Clear-RecycleBin -Force # PoweerShell 5

        write-host "Prune Event Logs..."
        $null=wevtutil el | Foreach-Object {wevtutil cl "$_"}
      
        write-host "Performing Disk Cleanup..."
        (Get-Volume).DriveLetter|ForEach-Object{cleanmgr /d $_ /VeryLowDisk}

        write-host 'Disabling the annoying Windows Update notifications...'
        $system32="$env:windir\System32"
        $annoyingNotifications="$system32\musnotification.exe","$system32\musnotificationux.exe"
        $denyExecute= New-Object System.Security.AccessControl.FileSystemAccessRule("Everyone","Execute","Deny")
        $annoyingNotifications|ForEach-Object{
            $acl = Get-ACL $_ 
            $acl.AddAccessRule($denyExecute)
            Set-Acl $_ $acl 
            }   
    }
    if($removeBloatware){removeBloatware}
    $volumes = gwmi -Class win32_volume -Filter "DriveType!=5" -ea stop| ?{$_.DriveLetter -ne $isnull}|`
        Select-object @{Name="Letter";Expression={$_.DriveLetter}},`
        @{Name="Label";Expression={$_.Label}},`
        @{Name="Capacity";Expression={"{0:N2} GiB" -f ($_.Capacity/1073741824)}},`
        @{Name = "Available"; Expression = {"{0:N2} GiB" -f ($_.FreeSpace/1073741824)}},`
        @{Name = "Utilization"; Expression = {"{0:N2} %" -f  ((($_.Capacity-$_.FreeSpace) / $_.Capacity)*100)}}`
        | sort -property Letter
    write-host "Current storage stats:`r`n$volumes"
    return $volumes
}

cleanupWindows

Version 1:

# Windows-Cleanup-v0.01.ps1

################################## Excuting Program as an Administrator ####################################
# Run this function ad-hoc to relaunch as Admin prior to going through the next commands
Function elevate{
# Get the ID and security principal of the current user account
$myWindowsID=[System.Security.Principal.WindowsIdentity]::GetCurrent()
$myWindowsPrincipal=new-object System.Security.Principal.WindowsPrincipal($myWindowsID)
 
# Get the security principal for the Administrator role
$adminRole=[System.Security.Principal.WindowsBuiltInRole]::Administrator
 
# Check to see if we are currently running "as Administrator"
if ($myWindowsPrincipal.IsInRole($adminRole))
   {
   # We are running "as Administrator" - so change the title and background color to indicate this
   $Host.UI.RawUI.WindowTitle = $myInvocation.MyCommand.Definition + "(Elevated)"
   $Host.UI.RawUI.BackgroundColor = "Black"
   clear-host
   }
else
   {
   # Relaunch as administrator
   start-process powershell -verb runas

   # Exit from the current, unelevated, process
   exit
   }
 
Write-Host -NoNewLine "Running as Administrator..."
}

# Get the ID and security principal of the current user account
$myWindowsID=[System.Security.Principal.WindowsIdentity]::GetCurrent()
$myWindowsPrincipal=new-object System.Security.Principal.WindowsPrincipal($myWindowsID)
 
# Get the security principal for the Administrator role
$adminRole=[System.Security.Principal.WindowsBuiltInRole]::Administrator
 
# Check to see if we are currently running "as Administrator"
if ($myWindowsPrincipal.IsInRole($adminRole))
   {
   # We are running "as Administrator" - so change the title and background color to indicate this
   $Host.UI.RawUI.WindowTitle = $myInvocation.MyCommand.Definition + "(Elevated)"
   $Host.UI.RawUI.BackgroundColor = "Black"
   clear-host
   }
else
   {
   # We are not running "as Administrator" - so relaunch as administrator
   # Create a new process object that starts PowerShell
   $newProcess = new-object System.Diagnostics.ProcessStartInfo "PowerShell";
   
   # Specify the current script path and name as a parameter
   $newProcess.Arguments = $myInvocation.MyCommand.Definition;
   
   # Indicate that the process should be elevated
   $newProcess.Verb = "runas";
   
   # Start the new process
   [System.Diagnostics.Process]::Start($newProcess);

   # Exit from the current, unelevated, process
   exit
   }
 
Write-Host -NoNewLine "Running as Administrator..."
################################## Excuting Program as an Administrator ####################################

function cleanupWindows{

    ## Variables Declaration ####
    $userAppDataTempFolders = (get-ChildItem "env:\TEMP").Value
    $windowsTemp = "$env:SystemDrive\Windows\Temp\*";
    $homeFolders=(dir "$env:SystemDrive\Users").FullName
    $userDownloadFolders=$homeFolders|%{"$env:SystemDrive\$_\Downloads\*"}
    $prefetchData="$env:SystemDrive\Windows\Prefetch\*"
    $cbs="$env:SystemDrive\Windows\Logs\CBS\*"   
    $swtools="$env:SystemDrive\swtools\*"  
    $drivers="$env:SystemDrive\drivers\*"  
    $swsetup="$env:SystemDrive\swsetup\*" 
    $softwareDistribution="$env:SystemDrive\Windows\SoftwareDistribution\Download\*"
    $recyclebin = (New-Object -ComObject Shell.Application).Namespace(0xA)

    # Performing cleanup tasks

    function cleanup{
        param($item)
        if ($item.Substring($item.Length - 2) -ne "\*"){
            if($item.Substring($item.Length - 1) -ne "\"){$item+="\*"}else{$item+="*"}            
            }
        Remove-Item $item -Force -Recurse -ea SilentlyContinue -Confirm:$false
    }
        
    $myWindowsID=[System.Security.Principal.WindowsIdentity]::GetCurrent()
    $myWindowsPrincipal=new-object System.Security.Principal.WindowsPrincipal($myWindowsID)
 
    # Get the security principal for the Administrator role
    $adminRole=[System.Security.Principal.WindowsBuiltInRole]::Administrator
    if ($myWindowsPrincipal.IsInRole($adminRole)){
    "Clear Windows Update Cache..."
    #Dism.exe /online /Cleanup-Image /spsuperseded #remove any backup components needed for uninstallation of the service pack
    Dism.exe /online /Cleanup-Image /startcomponentcleanup /resetbase #removes all superseded versions of every component in the component store.

    write-Host "Delete files in Temp directories..."
    $userAppDataTempFolders|%{cleanup $_}
    cleanup  $windowsTemp    
    cleanup "C:\Temp"

    write-Host "Cleanup Downloads..."
    $userDownloadFolders|%{cleanup $_}

    write-Host "Clean prefetch data..."
    cleanup  $prefetchData

    write-Host "Clean CBS logs..."
    $windowsUpdateStopped=net stop wuauserv
    if ($windowsUpdateStopped){
        cleanup $cbs
        net start wuauserv
        }
    
    write-Host "Clean swtools data..."
    cleanup  $swtools
    
    write-Host "Clean drivers data..."
    cleanup  $drivers
    
    write-Host "Clean swsetup data..."
    cleanup  $swsetup    
    
    write-Host "Clean softwareDistribution data..."
    cleanup  $softwareDistribution

    write-Host "Emptying Recycle Bin." -ForegroundColor Yellow      
    $Recyclebin.items() | %{cleanup $_.path} 

    "Performing Disk Cleanup..."
    $HKLM = [UInt32] "0x80000002"
    $strKeyPath = "SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\VolumeCaches"
    $strValueName = "StateFlags0065"
    $subkeys = gci -Path HKLM:\$strKeyPath -Name
    ForEach ($subkey in $subkeys) {
            New-ItemProperty -Path HKLM:\$strKeyPath\$subkey -Name $strValueName -PropertyType DWord -Value 2 -ErrorAction SilentlyContinue| Out-Null
            Start-Process cleanmgr -ArgumentList "/sagerun:65" -Wait -NoNewWindow -ErrorAction SilentlyContinue -WarningAction SilentlyContinue
        }
    ForEach ($subkey in $subkeys) {
            Remove-ItemProperty -Path HKLM:\$strKeyPath\$subkey -Name $strValueName | Out-Null
    }   
 
    #"Prune Event Logs..."
    #wevtutil el | Foreach-Object {wevtutil cl "$_"}

    write-Host "**Clean Up completed**" 
    }else{
        write-host "Need to run 'elevate' function to relaunch as Administrator prior to retrying 'cleanupWindows'..."
        }     
}
cleanupWindows;

# Verify volumes utilization after performing cleanup routines 
$volumes = (gwmi -Class win32_volume -Filter "DriveType!=5" -ea stop| ?{$_.DriveLetter -ne $isnull}|`
            Select-object @{Name="Letter";Expression={$_.DriveLetter}},`
            @{Name="Label";Expression={$_.Label}},`
            @{Name="Capacity";Expression={"{0:N2} GiB" -f ($_.Capacity/1073741824)}},`
            @{Name = "Available"; Expression = {"{0:N2} GiB" -f ($_.FreeSpace/1073741824)}},`
            @{Name = "Utilization"; Expression = {"{0:N2} %" -f  ((($_.Capacity-$_.FreeSpace) / $_.Capacity)*100)}}`
            | ft -autosize | Out-String).Trim()
write-host $volumes

Error:

Clear Windows Update Cache...

Deployment Image Servicing and Management tool
Version: 6.3.9600.19408

Image Version: 6.3.9600.19397

[==========================100.0%==========================]

Error: 14098

The component store has been corrupted.

The DISM log file can be found at C:\Windows\Logs\DISM\dism.log
Delete files in Temp directories...
Cleanup Downloads...
Clean prefetch data...
Clean CBS logs...
The Windows Update service is starting.
The Windows Update service was started successfully.

Resolve:

function resetWindowsUpdate{
# Source: https://docs.microsoft.com/en-us/windows/deployment/update/windows-update-resources
net stop wuauserv /y
net stop cryptSvc /y
net stop bits /y
net stop msiserver /y
Ren "$env:systemroot\SoftwareDistribution" SoftwareDistribution.old
Ren "$env:systemroot\System32\catroot2" Catroot2.old
netsh winsock reset
net start wuauserv
net start cryptSvc
net start bits
bitsadmin.exe /reset /allusers
net start msiserver
DISM.exe /Online /Cleanup-image /Restorehealth
}
resetWindowsUpdate


Leave a Reply

Your email address will not be published. Required fields are marked *