ANAVEM
Languagefr
Remediation Testedv1.0 2 scripts

Intune Remediation — Disk Cleanup

Automated Intune remediation script that detects and cleans temporary files, Windows Update cache, user temp folders, and Recycle Bin across all local drives. Triggers cleanup when cleanable space exceeds 1 GB.

Evan MaelEvan Mael
4 April 2026 4 min

Overview

This Intune Proactive Remediation package automatically identifies and removes unnecessary files consuming disk space on Windows endpoints. It follows the standard Detect → Remediate pattern used by Microsoft Intune.

What It Cleans

  • Windows Temp%WINDIR%\Temp
  • Windows Update Cache%WINDIR%\SoftwareDistribution\Download
  • User Temp FoldersC:\Users\*\AppData\Local\Temp (excludes system/default profiles)
  • Recycle Bin$Recycle.Bin on all local fixed drives

How It Works

Detection Script

The detection script scans all target paths and calculates the total cleanable size. If the total exceeds the 1 GB threshold, it returns exit code 1 (remediation required). Otherwise, it returns 0 (compliant).

Threshold Configuration: You can adjust the $ThresholdBytes variable in the detection script. Default is 1GB. Increase it for servers or decrease it for thin clients.

Remediation Script

When triggered, the remediation script removes all files from the targeted folders. It gracefully handles locked files and access-denied errors — files in use are simply skipped without causing failures.

After cleanup, the script reports the total freed space and remaining cleanable space in the Intune console output.

Deployment in Intune

  1. Go to Devices → Remediations in the Intune admin center
  2. Create a new remediation script package
  3. Upload the Detection script and Remediation script
  4. Set Run this script using the logged-on credentials: No
  5. Set Run script in 64-bit PowerShell: Yes
  6. Assign to a device group and set a schedule (daily or weekly recommended)
Verification: After deployment, check the remediation output in Intune. You should see messages like REMEDIATE: completed | freed=2.45 GB | remaining=0.12 GB

Excluded Profiles

The following user profiles are excluded from temp folder cleanup to avoid interfering with system accounts:

  • All Users, Default, Default User, Public
  • defaultuser0, WDAGUtilityAccount, Administrator
Important: Both scripts must run as SYSTEM (not as the logged-on user) to access all user temp folders and the Windows Update cache.

Output Format

Both scripts produce structured one-line output for easy parsing in Intune reports:

  • Detection: DETECT: remediation required | cleanable=2.45 GB | threshold=1 GB
  • Remediation: REMEDIATE: completed | freed=2.45 GB | remaining=0.12 GB
Source Code

Script Code

Detection — Disk Cleanup
Detect-DiskCleanup.ps1PowerShell
<#
.TITLE
    Detect - PR - Windows - Disk Cleanup

.SYNOPSIS
    Detects whether a Windows device has more cleanable disk space than the configured threshold.

.DESCRIPTION
    Measures cleanable content in:
    - Windows Temp
    - Windows Update download cache
    - Per-user Temp folders
    - Recycle Bin folders on local fixed disks

    Exit codes:
    0 = No remediation required
    1 = Remediation required

.NOTES
    Intended for Microsoft Intune Remediations.
    Run as SYSTEM in 64-bit PowerShell.
    Keep output short for Intune reporting.
#>

$ErrorActionPreference = 'Stop'

[int64]$ThresholdBytes = 1GB

$ExcludedProfiles = @(
    'All Users',
    'Default',
    'Default User',
    'Public',
    'defaultuser0',
    'WDAGUtilityAccount',
    'Administrator'
)

function Get-SafeFolderSizeBytes {
    param(
        [Parameter(Mandatory = $true)]
        [string]$Path
    )

    if (-not (Test-Path -LiteralPath $Path)) {
        return [int64]0
    }

    try {
        $sum = Get-ChildItem -LiteralPath $Path -Recurse -Force -File -ErrorAction SilentlyContinue |
            Measure-Object -Property Length -Sum |
            Select-Object -ExpandProperty Sum

        if ($null -eq $sum) {
            return [int64]0
        }

        return [int64]$sum
    }
    catch {
        return [int64]0
    }
}

function Get-UserTempPaths {
    if (-not (Test-Path -LiteralPath 'C:\Users')) {
        return @()
    }

    return Get-ChildItem -LiteralPath 'C:\Users' -Directory -Force -ErrorAction SilentlyContinue |
        Where-Object { $_.Name -notin $ExcludedProfiles } |
        ForEach-Object { Join-Path $_.FullName 'AppData\Local\Temp' }
}

function Get-RecycleBinPaths {
    $paths = @()

    try {
        $drives = Get-CimInstance Win32_LogicalDisk -ErrorAction SilentlyContinue |
            Where-Object { $_.DriveType -eq 3 -and $_.DeviceID }

        foreach ($drive in $drives) {
            $candidate = Join-Path $drive.DeviceID '$Recycle.Bin'
            if (Test-Path -LiteralPath $candidate) {
                $paths += $candidate
            }
        }
    }
    catch { }

    return $paths
}

try {
    [int64]$totalBytes = 0

    $basePaths = @(
        "$env:WINDIR\Temp",
        "$env:WINDIR\SoftwareDistribution\Download"
    )

    foreach ($path in $basePaths) {
        $totalBytes += Get-SafeFolderSizeBytes -Path $path
    }

    foreach ($path in (Get-UserTempPaths)) {
        $totalBytes += Get-SafeFolderSizeBytes -Path $path
    }

    foreach ($path in (Get-RecycleBinPaths)) {
        $totalBytes += Get-SafeFolderSizeBytes -Path $path
    }

    $totalGB = [math]::Round(($totalBytes / 1GB), 2)

    if ($totalBytes -ge $ThresholdBytes) {
        Write-Output "DETECT: remediation required | cleanable=$totalGB GB | threshold=1 GB"
        exit 1
    }

    Write-Output "DETECT: compliant | cleanable=$totalGB GB | threshold=1 GB"
    exit 0
}
catch {
    Write-Output "DETECT: error | $($_.Exception.Message)"
    exit 0
}

Scans Windows Temp, Update cache, user Temp folders, and Recycle Bin. Returns exit code 1 if cleanable space exceeds 1 GB threshold.

Remediation — Disk Cleanup
Remediate-DiskCleanup.ps1PowerShell
<#
.TITLE
    Remediate - PR - Windows - Disk Cleanup

.SYNOPSIS
    Cleans temporary files and recycle bin content on Windows devices.

.DESCRIPTION
    Removes content from:
    - Windows Temp
    - Windows Update download cache
    - Per-user Temp folders
    - Recycle Bin folders on local fixed disks

    The script ignores files in use and continues processing.

.NOTES
    Intended for Microsoft Intune Remediations.
    Run as SYSTEM in 64-bit PowerShell.
    Keep output short for Intune reporting.
#>

$ErrorActionPreference = 'Stop'

$ExcludedProfiles = @(
    'All Users',
    'Default',
    'Default User',
    'Public',
    'defaultuser0',
    'WDAGUtilityAccount',
    'Administrator'
)

function Get-SafeFolderSizeBytes {
    param(
        [Parameter(Mandatory = $true)]
        [string]$Path
    )

    if (-not (Test-Path -LiteralPath $Path)) {
        return [int64]0
    }

    try {
        $sum = Get-ChildItem -LiteralPath $Path -Recurse -Force -File -ErrorAction SilentlyContinue |
            Measure-Object -Property Length -Sum |
            Select-Object -ExpandProperty Sum

        if ($null -eq $sum) {
            return [int64]0
        }

        return [int64]$sum
    }
    catch {
        return [int64]0
    }
}

function Clear-SafeFolderContent {
    param(
        [Parameter(Mandatory = $true)]
        [string]$Path
    )

    if (-not (Test-Path -LiteralPath $Path)) {
        return
    }

    Get-ChildItem -LiteralPath $Path -Force -ErrorAction SilentlyContinue | ForEach-Object {
        try {
            Remove-Item -LiteralPath $_.FullName -Recurse -Force -ErrorAction Stop
        }
        catch {
            # Ignore locked files, access denied items, and transient errors
        }
    }
}

function Get-UserTempPaths {
    if (-not (Test-Path -LiteralPath 'C:\Users')) {
        return @()
    }

    return Get-ChildItem -LiteralPath 'C:\Users' -Directory -Force -ErrorAction SilentlyContinue |
        Where-Object { $_.Name -notin $ExcludedProfiles } |
        ForEach-Object { Join-Path $_.FullName 'AppData\Local\Temp' }
}

function Get-RecycleBinPaths {
    $paths = @()

    try {
        $drives = Get-CimInstance Win32_LogicalDisk -ErrorAction SilentlyContinue |
            Where-Object { $_.DriveType -eq 3 -and $_.DeviceID }

        foreach ($drive in $drives) {
            $candidate = Join-Path $drive.DeviceID '$Recycle.Bin'
            if (Test-Path -LiteralPath $candidate) {
                $paths += $candidate
            }
        }
    }
    catch { }

    return $paths
}

try {
    $pathsToClean = @(
        "$env:WINDIR\Temp",
        "$env:WINDIR\SoftwareDistribution\Download"
    )

    $pathsToClean += Get-UserTempPaths
    $pathsToClean += Get-RecycleBinPaths
    $pathsToClean = $pathsToClean | Where-Object { $_ } | Select-Object -Unique

    [int64]$beforeBytes = 0
    foreach ($path in $pathsToClean) {
        $beforeBytes += Get-SafeFolderSizeBytes -Path $path
    }

    foreach ($path in $pathsToClean) {
        Clear-SafeFolderContent -Path $path
    }

    Start-Sleep -Seconds 2

    [int64]$afterBytes = 0
    foreach ($path in $pathsToClean) {
        $afterBytes += Get-SafeFolderSizeBytes -Path $path
    }

    [int64]$freedBytes = $beforeBytes - $afterBytes
    if ($freedBytes -lt 0) {
        $freedBytes = 0
    }

    $freedGB = [math]::Round(($freedBytes / 1GB), 2)
    $remainingGB = [math]::Round(($afterBytes / 1GB), 2)

    Write-Output "REMEDIATE: completed | freed=$freedGB GB | remaining=$remainingGB GB"
    exit 0
}
catch {
    Write-Output "REMEDIATE: error | $($_.Exception.Message)"
    exit 1
}

Removes temporary files and Recycle Bin content from all targeted paths. Reports freed and remaining space in Intune-compatible output.

Evan Mael
Written by

Evan Mael

Microsoft MCSA-certified Cloud Architect | Fortinet-focused. I modernize cloud, hybrid & on-prem infrastructure for reliability, security, performance and cost control - sharing field-tested ops & troubleshooting.

Discussion

Share your thoughts and insights

Sign in to join the discussion