Automatic Cleanup of Downloads and Desktop in Kiosk Mode

This PowerShell script is intended for kiosk environments deployed using Windows Autopilot and Microsoft Intune.

📌 What This Script Does

The script automatically empties all standard user libraries for a specified kiosk user (default: kioskuser0):

  • Downloads
  • Desktop
  • Documents
  • Pictures
  • Music
  • Videos

It is designed to work reliably even in offline, restricted, or library/public kiosk environments where cloud-based or user-scoped cleanup policies may fail.

🛡️ Key Capabilities (Summary)

  • A dedicated cleanup script is stored in C:\ProgramData
  • A scheduled task runs daily at 20:30 as SYSTEM
  • All cleanup actions are logged for traceability
  • Supports simulation mode (WhatIf), install-only, and manual execution

⚠️ Purpose

The purpose of this script is to ensure that all common user libraries are cleared regularly on kiosk devices, preventing data accumulation, protecting user privacy, and maintaining a clean and predictable kiosk experience.

Below is the script exactly as used in the deployment.

PowerShell – Local Kiosk Wallpaper Manager

# ================================
#  KioskCleanup - Tömningsschema för flera mappar
#  Mappar: Downloads, Desktop, Documents, Pictures, Music, Videos
#  Användare: kioskuser0 (kan ändras via -UserName)
# ================================

param(
    [string]$UserName = "kioskuser0",
    [switch]$InstallOnly,     # Skapar/uppdaterar bara schemat, kör ej städning nu
    [switch]$RunNow,          # Kör städning direkt efter skapad uppgift
    [switch]$WhatIf           # Kör i simuleringsläge
)

$taskName   = "KioskCleanup-AllUserLibraries"
$scriptPath = "C:\ProgramData\KioskCleanup-AllUserLibraries.ps1"
$logDir     = "C:\ProgramData\KioskDownloadsCleanup"

# Säkerställ loggmapp
New-Item -ItemType Directory -Path $logDir -Force | Out-Null

# ----------------
# Själva rensningsskriptet (sparas till disk och anropas av schemalagd uppgift)
# ----------------
$cleanupScript = @'
param(
    [string]$UserName = "kioskuser0",
    [switch]$WhatIf
)

$ErrorActionPreference = "Continue"

function Write-Log([string]$msg) {
    $global:LogPath = "C:\ProgramData\KioskDownloadsCleanup"
    New-Item -ItemType Directory -Path $global:LogPath -Force -ErrorAction SilentlyContinue | Out-Null
    $log = Join-Path $global:LogPath ("Cleanup_{0:yyyyMMdd_HHmmss}.log" -f (Get-Date))
    $msg | Tee-Object -FilePath $log -Append
}

function Clear-FolderContent {
    param(
        [Parameter(Mandatory=$true)][string]$Path,
        [switch]$WhatIf
    )
    if (-not (Test-Path -LiteralPath $Path)) {
        Write-Log "Saknas/otillgänglig: $Path (hoppar över)"
        return
    }

    # Rensa filer först
    Get-ChildItem -LiteralPath $Path -File -Force -Recurse -ErrorAction SilentlyContinue |
        Remove-Item -Force -ErrorAction SilentlyContinue -WhatIf:$WhatIf.IsPresent

    # Rensa mappar (innerst först)
    Get-ChildItem -LiteralPath $Path -Directory -Force -Recurse -ErrorAction SilentlyContinue |
        Sort-Object FullName -Descending |
        ForEach-Object {
            try {
                # Undvik att jaga junctions/reparse-points
                if (($_.Attributes -band [IO.FileAttributes]::ReparsePoint)) {
                    Write-Log "Hoppar över reparse/junction: $($_.FullName)"
                } else {
                    Remove-Item -LiteralPath $_.FullName -Force -ErrorAction SilentlyContinue -Recurse `
                        -WhatIf:$WhatIf.IsPresent
                }
            } catch {
                Write-Log "Fel vid borttagning: $($_.FullName) - $($_.Exception.Message)"
            }
        }
}

try {
    $profilePath = Join-Path -Path "C:\Users" -ChildPath $UserName

    $targets = @(
        (Join-Path $profilePath "Downloads"),
        (Join-Path $profilePath "Desktop"),
        (Join-Path $profilePath "Documents"),
        (Join-Path $profilePath "Pictures"),
        (Join-Path $profilePath "Music"),
        (Join-Path $profilePath "Videos")
    )

    Write-Log "=== KioskCleanup startar för användare: $UserName ==="

    foreach ($t in $targets) {
        Write-Log "Rensar: $t"
        Clear-FolderContent -Path $t -WhatIf:$WhatIf.IsPresent
    }

    Write-Log "Rensning klar."
    exit 0
}
catch {
    Write-Log "Fel vid rensning: $($_.Exception.Message)"
    exit 1
}
'@

# Skriv ned rensningsskriptet till disk
$cleanupScript | Set-Content -Path $scriptPath -Encoding UTF8 -Force

if ($InstallOnly) {
    Write-Host "Endast installerat rensningsskriptet på $scriptPath"
    exit 0
}

# ----------------
# Skapa/uppdatera schemalagd uppgift (dagligen 20:30 som SYSTEM)
# ----------------
# Ta bort ev. tidigare version för samma namn
if (Get-ScheduledTask -TaskName $taskName -ErrorAction SilentlyContinue) {
    Unregister-ScheduledTask -TaskName $taskName -Confirm:$false
}

$action = New-ScheduledTaskAction `
    -Execute "powershell.exe" `
    -Argument "-NoLogo -NonInteractive -WindowStyle Hidden -ExecutionPolicy Bypass -File `"$scriptPath`" -UserName $UserName"

$trigger   = New-ScheduledTaskTrigger -Daily -At 20:30
$principal = New-ScheduledTaskPrincipal -UserId "SYSTEM" -RunLevel Highest
$settings  = New-ScheduledTaskSettingsSet -StartWhenAvailable -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries

Register-ScheduledTask `
    -Action $action `
    -Trigger $trigger `
    -Principal $principal `
    -Settings $settings `
    -TaskName $taskName `
    -Description "Tömmer Downloads, Desktop, Documents, Pictures, Music, Videos för $UserName dagligen kl. 20:30"

Write-Host "Schemalagd uppgift '$taskName' skapad/uppdaterad."
Write-Host "Rensningsskript: $scriptPath"
Write-Host "Loggmapp: $logDir"

if ($RunNow) {
    Start-ScheduledTask -TaskName $taskName
    Write-Host "Startade rensning direkt (RunNow)."
}>

Kommentarer

Populära inlägg i den här bloggen

🚀 Force Reinstallation of an Intune App

🔵Troubleshooting Intune Device Enrollments: Understanding GUIDs, Registry Paths, and EnterpriseMgmt Tasks

🚀 Windows Autopilot Self-Deploying Mode — Zero-Touch Setup That Feels Like Magic