#Requires -Version 2.0

<#
.SYNOPSIS
This script will programatically set the sageset values for cleanmgr and clean the computer using the settings defined herein.

.DESCRIPTION
Settings are taken from Windows 7 SP1, 8.1, and 10. The way the settings are applied should allow this script to work on any Windows version.

.PARAMETER NoSettings
This parameter will not write any changes to the registry. It will attempt to clean the computer using existing SageSet values in the registry. If the SageSetNumber doesn't already have cleanup items defined for it, this script simply won't clean anything.

.PARAMETER NoCleaning
Will only make changes to the registry and will not clean the computer with those settings. Note: You may want to also use -KeepSettings, otherwise the settings will be created then deleted

.PARAMETER DeleteSettings
Will remove the registry settings after cleaning. This option implies -NoCleaning

.PARAMETER User
This will clean files in the user space (not necessarily related to the currently logged in user)

.PARAMETER System
This will clean files in the system space

.PARAMETER WindowsUpdate
This will clean files related to Windows Update and Windows Upgrade (but not previous versions)

.PARAMETER WindowsPreviousVersions
This will clean files related to previous versions of Windows. This will prevent the computer from reverting back to an earlier version of Windows

.PARAMETER Invasive
This will clean files that could impact system functionality. Such as Windows ESD Installation files - removing these prevents Windows 10 from being able to Refresh or Reset

.PARAMETER Misc
This will clean files that don't fit into the other categories

.PARAMETER All
This will clean files in all categories

.PARAMETER iTunesBackups
This will remove any iTunes backups from each user's profile

.PARAMETER OlderThan
Parameter for iTunesBackups`n`rThis is the number of days back to delete iTunes backups. For example: Specifying '-OlderThan 30' will delete all iTunes backups that have not been modified in 30 days

.INPUTS
This script does not accept any input from the pipeline.

.OUTPUTS
This script produces no output.

.NOTES
This script requires an administrative token because it writes to HKLM.

.LINK
https://support.microsoft.com/en-us/help/315246/how-to-automate-the-disk-cleanup-tool-in-windows-xp-and-windows-7

#>

param (
    [switch]$NoSettings,
    [switch]$NoCleaning,
    [switch]$DeleteSettings,
    [switch]$User,
    [switch]$System,
    [switch]$WindowsUpdate,
    [switch]$WindowsPreviousVersions,
    [switch]$Invasive,
    [switch]$Misc,
    [switch]$All,
    [switch]$iTunesBackups,
    [int]$OlderThan=0
)

## DeleteSettings implies NoCleaning
If ( $DeleteSettings ) { $NoCleaning = $true }

## Below is series of hash tables containing all the settings that can be cleaned in each grouping
## To stop an item from being cleaned, simply set it's value to $false
## The comments above each setting include the setting's display name and description in cleanmgr
## Important Note: There are more cleaning options available in the registry
##  but for the sake of time, safety, and Microsoft's documentation, I've mostly included the ones listed in the cleanmgr.exe GUI

## Each list of configuration items will have a variable above it for that list's SageSetNumber
## This number will be used to clean the items in the corresponding list
## This number can be anything between 1 and 65535

## These items likely fall within the 'user space' but are not necessarily related to the currently logged in user
$UserItemsSageSetNumber = 10100
$UserItems = @{
    ## Display Name: Downloaded Program Files
    ## Description: Downloaded Program Files are ActiveX controls and Java applets downloaded automatically from the
    ##  Internet when you view certain pages. They are temporarily stored in the Downloaded Program Files folder on
    ##  your hard disk.
    "Downloaded Program Files" = $true;

    ## Display Name: Temporary Internet Files
    ## Description: The Temporary Internet Files folder contains Web pages stored on your hard disk for quick viewing.
    ##  Your personalized settings for Web pages will be left intact.
    "Internet Cache Files" = $true;

    ## Display Name: Offline Web Pages
    ## Description: Offline pages are Web pages that are stored on your computer so you can view them without being
    ##  connected to the Internet.  If you delete these pages now, you can still view your favorites offline later by
    ##  synchronizing them.  Your personalized settings for Web pages will be left intact.
    "Offline Pages Files" = $true;

    ## Display Name: Recycle Bin
    ## Description: The Recycle Bin contains files you have deleted from your computer. These files are not permanently
    ##  removed until you empty the Recycle Bin.
    "Recycle Bin" = $false;

    ## Display Name: Temporary files
    ## Description: Programs sometimes store temporary information in a TEMP folder. Before a program closes, it usually
    ##  deletes this information. You can safely delete temporary files that have not been modified in over a week.
    "Temporary Files" = $true;

    ## Display Name: Thumbnails
    ## Description: Windows keeps a copy of all of your picture, video, and document thumbnails so they can be displayed
    ##  quickly when you open a folder. If you delete these thumbnails, they will be automatically recreated as needed.
    "Thumbnail Cache" = $true;

    ## Display Name: User file history
    ## Description: Windows stores file versions temporarily on this disk before copying them to the designated File
    ##  History disk. If you delete these files, you will lose some file history.
    "User file versions" = $false;
}

$SystemItemsSageSetNumber = 10200
$SystemItems = @{
    ## Display Name: Temporary Setup Files
    ## Description: These files should no longer be needed. They were originally created by a setup program that is no
    ##  longer running.
    "Active Setup Temp Folders" = $true;

    ## Display Name: BranchCache
    ## Description: Files created by BranchCache service for caching data.
    "BranchCache" = $true;

    ## Display Name: Debug Dump Files
    ## Description: Files created by Windows
    "Memory Dump Files" = $true;

    ## Display Name: Old Chkdsk Files
    ## Description: When Chkdsk checks your disk drive for errors, it might save lost file fragments as files in your
    ##  disk drive's root folder. These files are unnecessary and can be removed.
    "Old ChkDsk Files" = $true;

    ## Display Name: RetailDemo Offline Content
    ## Description: <None>
    "RetailDemo Offline Content" = $true;

    ## Display Name: Temporary files
    ## Description: Programs sometimes store temporary information in a TEMP folder. Before a program closes, it usually
    ##  deletes this information. You can safely delete temporary files that have not been modified in over a week.
    "Temporary Files" = $true;

    ## Display Name: System error memory dump files
    ## Description: Remove system error memory dump files.
    "System error memory dump files" = $true;

    ## Display Name: System error minidump files
    ## Description: Remove system error minidump files.
    "System error minidump files" = $false;

    ## Display Name: Temporary Setup Files
    ## Description: These files should no longer be needed. They were originally created by a setup program that is no
    ##  longer running.
    "Temporary Setup Files" = $true;

    ## Display Name: Windows Defender
    ## Description: Non critical files used by Windows Defender
    "Windows Defender" = $true;

    ## Display Name: Per user archived Windows Error Reporting Files
    ## Description: Files used for error reporting and solution checking.
    "Windows Error Reporting Archive Files" = $true;

    ## Display Name: Per user queued Windows Error Reporting Files
    ## Description: Files used for error reporting and solution checking.
    "Windows Error Reporting Queue Files" = $false;

    ## Display Name: System archived Windows Error Reporting Files
    ## Description: Files used for error reporting and solution checking.
    "Windows Error Reporting System Archive Files" = $true;

    ## Display Name: System queued Windows Error Reporting Files
    ## Description: Files used for error reporting and solution checking.
    "Windows Error Reporting System Queue Files" = $false;

    ## Display Name: System created temporary Windows Error Reporting Files
    ## Description: Temporary files used for error reporting and solution checking.
    "Windows Error Reporting Temp Files" = $true;
}

$WindowsUpdateItemsSageSetNumber = 10300
$WindowsUpdateItems = @{
    ## Display Name: Service Pack Backup Files
    ## Description: Windows saves old versions of files that have been updated by a service pack. If you delete the
    ##  files, you won't be able to uninstall the service pack later.
    "Service Pack Cleanup" = $true;

    ## Display Name: Windows Update Cleanup
    ## Description: Windows keeps copies of all installed updates from Windows Update, even after installing newer
    ##  versions of updates. Windows Update leanup deletes or compresses older versions of updates that are no longer
    ##  needed and taking up space. (You might need to restart your computer.)
    "Update Cleanup" = $true;

    ## Display Name: Files discarded by Windows upgrade
    ## Description: Files from a previous Windows installation. As a precaution, Windows upgrade keeps a copy of any
    ##  files that were not moved to the new version of Windows and were not identified as Windows system files. If you
    ##  are sure that no user's personal files are missing after the upgrade, you can delete these files.
    "Upgrade Discarded Files" = $true;

    ## Display Name: Windows upgrade log files
    ## Windows upgrade log files contain information that can help identify and troubleshoot problems that occur during
    ##  Windows installation, upgrade, or servicing. Deleting these files can make it difficult to troughtshoot
    ##  installation issues.
    "Windows Upgrade Log Files" = $false;
}

$WindowsPreviousVersionsItemsSageSetNumber = 10400
$WindowsPreviousVersionsItems = @{
    ## Display Name: Previous Windows Installation(s)
    ## Description: Files from a previous Windows installation. Files and folders that may conflict with the installation
    ##  of WIndows have been moved to folders named Windows.old. You can access data from the previous WIndows
    ##  installations in this folder.
    "Previous Installations" = $true;

    ## Display Name: Setup Log Files
    ## Description: Files created by Windows.
    "Setup Log Files" = $true;
}

$InvasiveItemsSageSetNumber = 10500
$InvasiveItems = @{
    ## Display Name: Windows ESD installation files
    ## Description: You will need these files to Reset or Refresh your PC.
    "Windows ESD installation files" = $false;
}

$MiscItemsSageSetNumber = 20000
$MiscItems = @{
    ## The following settings exist in the Windows Registry but do not have an option to select them in cleanmgr.
    ## Setting these to $true will probably clean data associated with them, but I haven't tested this - use caution.
    "Content Indexer Cleaner" = $false;
    "Delivery Optimization Files" = $false;
    "Device Driver Packages" = $false;
    "GameNewsFiles" = $false;
    "GameStatisticsFiles" = $false;
    "GameUpdateFiles" = $false;
    "Temporary Sync Files" = $false;
}

## This is just the path to the registry key that contains the settings we want to modify, don't change this value
$RegBasePath = 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\VolumeCaches'

## Set the registry keys according to our selection
## If you don't want to change any settings, call this script with the -NoSettings

## Function to make changes to the registry
Function Write-CleaningItemsToRegistry($RegistryItems,$SageSetNumber) {
    ForEach ($k in $RegistryItems.Keys) {
        $FullRegKeyPath = "${RegBasePath}\${k}"
            ## Test to make sure we should enable cleaning of the property we're working with, and that the property exists.
        If ( $RegistryItems.Item($k) -and ( Test-Path $FullRegKeyPath ) ) {

            ## If the property already exists and has the same SageSetNumber, it will be overwritten.
            New-ItemProperty -Path $FullRegKeyPath -Name "StateFlags${SageSetNumber}" -Value '2' -PropertyType DWORD -Force | Out-Null
        }
    }
}

## Function to delete changes made to the registry
Function Remove-CleaningItemsfromRegistry($RegistryItems,$SageSetNumber) {
    ForEach ( $k in $RegKeys.Keys ) {
        $FullRegKeyPath = "${RegBasePath}\${k}"

        ## We're only testing that the key path and property exists, not if it was previously set to be cleaned.
        ## This means that if the item has ever been set to be cleaned, the property will be deleted,
        ##  but only if it matches the $SageSetNumber
        $PropertyName = "StateFlags${SageSetNumber}"
        If ( (Test-Path -Path $FullRegKeyPath) -and ($(Get-ItemProperty -Path $FullRegKeyPath).$PropertyName) ) {
            Remove-ItemProperty -Path $FullRegKeyPath -Name $PropertyName -Force
        }
    }
}

## Function to clean files
Function Clean-Files($Items,$SageSetNumber) {
    
    ## Write the changes to the registry
    If (! ($NoSettings) ) { Write-CleaningItemsToRegistry $Items $SageSetNumber }

    ## Run the cleanup
    If (! ($NoCleaning) ) { Start-Process "${Env:WinDir}\System32\cleanmgr.exe" -ArgumentList "/sagerun:${SageSetNumber}" }

    ## Remove the changes from the registry
    If ( $DeleteSettings ) { Remove-CleaningItemsfromRegistry $Items $SageSetNumber }
}

## Get the specified cleaning categories and run each one
## Only run if cleanmgr.exe is present on the target endpoint.
If ( Test-Path "${Env:SYSTEMROOT}\System32\cleanmgr.exe" )
{
    If ( $All ) {
        $User = $true
        $System = $true
        $WindowsUpdate = $true
        $WindowsPreviousVersions = $true
        $Invasive = $true
        $Misc = $true
    }
    If ( $User ) { Clean-Files $UserItems $UserItemsSageSetNumber }
    If ( $System ) { Clean-Files $SystemItems $SystemItemsSageSetNumber }
    If ( $WindowsUpdate ) { Clean-Files $WindowsUpdateItems $WindowsUpdateItemsSageSetNumber }
    If ( $WindowsPreviousVersions ) { Clean-Files $WindowsPreviousVersionsItems $WindowsPreviousVersionsItemsSageSetNumber }
    If ( $Invasive ) { Clean-Files $InvasiveItems $InvasiveItemsSageSetNumber }
    If ( $Misc ) { Clean-Files $MiscItems $MiscItemsSageSetNumber }

} Else { Write-Output "cleanmgr.exe does not exist!" }

## Function to delete each iTunes backup directory
Function Delete-iTunesBackups($dir) {

    ## Create a new timespan to compare with last write date of the target directory
    $timedelta = New-TimeSpan -Days $OlderThan

    ## Get each iTunes backup directory
    Foreach ( $d in (Get-ChildItem -Path $dir) ) {

        ## If it's older than the number of days specified, recursively delete the directory
        If ( $d.LastWriteTime -lt ((Get-Date) - $timedelta) ) { Remove-Item $d.FullName -Recurse -Force }

    }
}

## Start processing iTunes backups if the option was specified
If ( $iTunesBackups ) {

    ## List of accounts to exclude
    $ExcludedUsers = @("Public",
                       "All Users",
                       "Administrator")

    ## Empty array to hold the user directories to clean
    $DirectoriesToProcess = @()

    ## Get all user accounts in ${Env:SystemDrive}\Users
    $UsersPath = "${Env:SystemDrive}\Users"
    Get-ChildItem -Path $UsersPath | ForEach-Object {
        $username = $_.Name
        $path = "${UsersPath}\${username}\AppData\Roaming\Apple Computer\MobileSync\Backup"

        ## Make sure the user isn't excluded and that the iTunes backup directory exists
        If ( ($ExcludedUsers -notcontains $username) -and (Test-Path -PathType Container -Path $path) ) {

            ## Make sure there's data in the iTunes backup folder
            If ( (Get-ChildItem $path | Measure-Object).Count -gt 0 ) {
            
                ## Call the Delete-iTunesBackups function for each directory
                Delete-iTunesBackups $path
            }
        }
    }
}