SOLVED: The Ultimate Script To Clean Up Junk in User Profiles

If you work with most companies there will come a time when you will need to clean out user profiles that have just too much temporary file junk in them.

Earlier this month we spent a few hours developing the script below that deletes:

  1. all of the common temp files in a user’s profile
    • “AppData\Local\Temp”,
      “AppData\Local\Microsoft\Windows\INetCache”,
      “AppData\Local\Microsoft\Windows\INetCookies”,
      “AppData\Local\Microsoft\Windows\Temporary Internet Files”,
      “AppData\Local\Microsoft\Windows\Explorer”,
      “AppData\Local\Temp\Low”,
      “AppData\Local\Google\Chrome\User Data\Default\Cache”,
      “AppData\Local\Mozilla\Firefox\Profiles\*\cache2” # Firefox cache
      “AppData\Local\Microsoft\Edge\User Data\Default\Cache”, # Edge cache
      “AppData\Local\Microsoft\Edge\User Data\Default\Code Cache”, # Edge code cache
      “AppData\Local\Microsoft\Edge\User Data\Default\GPUCache” # Edge GPU cache
  2. any files in their DOWNLOADS folder that are older than 8 days
  3. all RECYCLE BINs
powershell script to clean up user profilespowershell script to clean up user profiles

Just run this script in an elevated Power Shell and you may get back a considerable amount of disk space as well as clearing up many odd user problems:


# Log off disconnected users
Get-WmiObject -Class Win32_LogonSession | Where-Object { $_.LogonType -eq 10 } | ForEach-Object {
    logoff $_.LogonId
}

# Get the current user
$currentUser = [System.Security.Principal.WindowsIdentity]::GetCurrent().Name

# Get all user profiles except the default profile
$profiles = Get-WmiObject -Class Win32_UserProfile | Where-Object { $_.Special -eq $false }

# Grant access to each user profile
foreach ($profile in $profiles) {
    $profilePath = $profile.LocalPath
    Write-Host "Granting access to $profilePath for $currentUser"
    $acl = Get-Acl $profilePath
    $accessRule = New-Object System.Security.AccessControl.FileSystemAccessRule($currentUser, "FullControl", "ContainerInherit,ObjectInherit", "None", "Allow")
    $acl.SetAccessRule($accessRule)
    Set-Acl $profilePath $acl
}

Write-Host "Access granted to all user profiles for $currentUser"

# Initialize total recovered space variable
$totalRecoveredSpace = 0

# Delete temp folders and old downloads for each user profile, and calculate recovered space
$tempFolders = @(
    "AppData\Local\Temp",
    "AppData\Local\Microsoft\Windows\INetCache",
    "AppData\Local\Microsoft\Windows\INetCookies",
    "AppData\Local\Microsoft\Windows\Temporary Internet Files",
    "AppData\Local\Microsoft\Windows\Explorer",
    "AppData\Local\Temp\Low",
    "AppData\Local\Google\Chrome\User Data\Default\Cache",
    "AppData\Local\Mozilla\Firefox\Profiles\*\cache2" # Firefox cache
    "AppData\Local\Microsoft\Edge\User Data\Default\Cache", # Edge cache
    "AppData\Local\Microsoft\Edge\User Data\Default\Code Cache", # Edge code cache
    "AppData\Local\Microsoft\Edge\User Data\Default\GPUCache" # Edge GPU cache
)

foreach ($profile in $profiles) {
    $profilePath = $profile.LocalPath
    $userName = [System.IO.Path]::GetFileName($profilePath) # Extract the username from the profile path
    $userRecoveredSpace = 0
    Write-Host "Processing user: $userName"

    foreach ($folder in $tempFolders) {
        $fullPath = Join-Path -Path $profilePath -ChildPath $folder
        if (Test-Path $fullPath) {
            $folderItems = Get-ChildItem -Path $fullPath -Recurse -Force -ErrorAction SilentlyContinue
            $fileItems = $folderItems | Where-Object { -not $_.PsIsContainer }
            $folderSizeBefore = ($fileItems | Measure-Object -Property Length -Sum).Sum
            $folderItems | Remove-Item -Recurse -Force -ErrorAction SilentlyContinue
            $folderSizeAfter = (Get-ChildItem -Path $fullPath -File -Recurse -Force -ErrorAction SilentlyContinue | Measure-Object -Property Length -Sum).Sum
            $recoveredSpace = $folderSizeBefore - $folderSizeAfter
            $userRecoveredSpace += $recoveredSpace
            $totalRecoveredSpace += $recoveredSpace
        }
    }

    # Delete old files and folders in the Downloads folder
    $downloadsPath = Join-Path -Path $profilePath -ChildPath "Downloads"
    if (Test-Path $downloadsPath) {
        $oldItems = Get-ChildItem -Path $downloadsPath -Recurse -Force -ErrorAction SilentlyContinue | Where-Object { $_.LastWriteTime -lt (Get-Date).AddDays(-8) }
        $downloadsSizeBefore = ($oldItems | Measure-Object -Property Length -Sum).Sum
        $oldItems | Remove-Item -Recurse -Force -ErrorAction SilentlyContinue
        $downloadsSizeAfter = (Get-ChildItem -Path $downloadsPath -File -Recurse -Force -ErrorAction SilentlyContinue | Measure-Object -Property Length -Sum).Sum
        $downloadsRecoveredSpace = $downloadsSizeBefore - $downloadsSizeAfter
        $userRecoveredSpace += $downloadsRecoveredSpace
        $totalRecoveredSpace += $downloadsRecoveredSpace
    }

    Write-Host "User ${userName}: Recovered space: ${userRecoveredSpace} bytes"
}

# Empty all users' recycle bins
$recycleBinPath = "C:\$RECYCLE.BIN"
if (Test-Path $recycleBinPath) {
    Get-ChildItem -Path $recycleBinPath -Recurse -Force -ErrorAction SilentlyContinue | Remove-Item -Recurse -Force -ErrorAction SilentlyContinue
    Write-Host "Emptied all users' recycle bins"
}

# Report total recovered space
Write-Host "Total recovered space: ${totalRecoveredSpace} bytes"

Published by
Ian Matthews