free-automations / windows / tidy-downloads.md Public
tidy-downloads.md
DeviceWindowsCostFreeSetup5 minutes

Tidy your Downloads folder

Every Sunday evening, files older than a week are moved out of the Downloads pile into folders by type: Documents, Images, Videos, Audio, Archives, Installers and Other. Nothing is deleted, and a file with the same name is never overwritten.

1. Save the script

Make a folder called Scripts in your user folder (for example C:\Users\Thandi\Scripts), then save this file into it as tidy-downloads.ps1. Use Download below, or Copy and paste it into Notepad.

tidy-downloads.ps165 lines · 2.6 KB
<#
Tidy the Downloads folder: files older than a number of days are moved into
subfolders by type (Documents, Images, Videos, Audio, Archives, Installers, Other).
It only shows what it would do unless you add -Apply, and it never overwrites or
deletes anything.

  powershell -ExecutionPolicy Bypass -File .\tidy-downloads.ps1            preview only
  powershell -ExecutionPolicy Bypass -File .\tidy-downloads.ps1 -Apply     move the files

Free from Voypelo Solutions, voypelo.co.za. MIT licence.
#>
param(
    [string]$Folder = (Join-Path $env:USERPROFILE 'Downloads'),
    [int]$OlderThanDays = 7,
    [switch]$Apply
)

$types = [ordered]@{
    'Documents'  = @('.pdf', '.doc', '.docx', '.xls', '.xlsx', '.csv', '.ppt', '.pptx', '.txt', '.rtf', '.odt')
    'Images'     = @('.jpg', '.jpeg', '.png', '.gif', '.heic', '.webp', '.bmp', '.svg')
    'Videos'     = @('.mp4', '.mov', '.avi', '.mkv', '.wmv')
    'Audio'      = @('.mp3', '.wav', '.m4a', '.ogg', '.opus')
    'Archives'   = @('.zip', '.rar', '.7z', '.tar', '.gz')
    'Installers' = @('.exe', '.msi')
}
# Files still downloading or used by Windows itself are left alone.
$skip = @('.crdownload', '.part', '.tmp', '.ini', '.lnk')

if (-not (Test-Path -LiteralPath $Folder -PathType Container)) {
    Write-Error "Expected a folder at $Folder, found nothing there"
    exit 1
}
$cutoff = (Get-Date).AddDays(-$OlderThanDays)
$count = 0
Get-ChildItem -LiteralPath $Folder -File |
    Where-Object { $_.LastWriteTime -lt $cutoff -and $skip -notcontains $_.Extension.ToLower() } |
    ForEach-Object {
        $ext = $_.Extension.ToLower()
        $target = 'Other'
        foreach ($name in $types.Keys) {
            if ($types[$name] -contains $ext) { $target = $name; break }
        }
        $destDir = Join-Path $Folder $target
        $dest = Join-Path $destDir $_.Name
        # Never overwrite: a file with the same name gets a number added.
        $n = 1
        while (Test-Path -LiteralPath $dest) {
            $dest = Join-Path $destDir ('{0} ({1}){2}' -f $_.BaseName, $n, $_.Extension)
            $n++
        }
        if ($Apply) {
            New-Item -ItemType Directory -Path $destDir -Force | Out-Null
            Move-Item -LiteralPath $_.FullName -Destination $dest
            Write-Output ('moved       {0}  ->  {1}' -f $_.Name, $target)
        } else {
            Write-Output ('would move  {0}  ->  {1}' -f $_.Name, $target)
        }
        $count++
    }

if ($Apply) {
    Write-Output ('{0} file(s) moved.' -f $count)
} else {
    Write-Output ('{0} file(s) would be moved. Run again with -Apply to move them.' -f $count)
}

2. Try it once

Open Command Prompt and run this. It only shows what it would move:

powershell -ExecutionPolicy Bypass -File "%USERPROFILE%\Scripts\tidy-downloads.ps1"

If the list looks right, run it for real:

powershell -ExecutionPolicy Bypass -File "%USERPROFILE%\Scripts\tidy-downloads.ps1" -Apply

3. Let Windows run it every week

Still in Command Prompt, paste this to run it every Sunday at 18:00:

schtasks /Create /SC WEEKLY /D SUN /ST 18:00 /TN "Tidy Downloads" /TR "powershell -NoProfile -ExecutionPolicy Bypass -File \"%USERPROFILE%\Scripts\tidy-downloads.ps1\" -Apply"

To stop it later: schtasks /Delete /TN "Tidy Downloads".

Why it helps

A tidy Downloads folder means you find last month's invoice in seconds instead of scrolling past 400 files.