My Downloads folder has become the Wild West. I have dozens (okay, hundreds) of different files that accumulate on a monthly basis. These include heaps of generically named screenshots, random PDF files, more ZIP archives than I can count, and even a few installers I grabbed but never ran.
I've tried going through the hoard of files every couple of weeks, but it feels like the type of repetitive and tedious task that my computer should just be doing for me. So, I decided to take a half hour and write a PowerShell script that could automate file organization. It's saved me a lot of time ever since, and I even use it on other directories I want to organize.
You can write a script like this in pretty much any language, but it felt natural to reach for PowerShell because it's already built right into Windows. If you've never used PowerShell or built a script, you can still run this one with ease. It's easily modified or extended and may become your springboard to future scripting projects.
6 PowerShell scripts to automate and speed up your workflow
When you work through the CLI you save a lot of time. Here are PowerShell scripts to speed your workflow.
Let PowerShell sort files by type
A solution that's as simple as it sounds
You may have some special way of organizing your files — by year, by project, by author, or whatever works for you. I'd encourage you to translate that structure into your PowerShell script. But for my files, I went with what is probably the simplest way to categorize them: by file type.
This works well because almost all files (barring some special system files) on your computer have a file extension like .txt, .mov, .zip, etc. The file's extension can be read by PowerShell to easily determine what kind of file it's handling and where it should be moved to. If the destination folder doesn't exist yet, the script creates it.
These are the types of files I've programmed my script to handle:
- Images - JPG, PNG, GIF, HEIC, DNG, WEBP, AVIF
- Documents - DOCX, PDF, TXT, XLSX, CSV
- Archives - ZIP, RAR, TAR, GZ, 7Z
- Executables - EXE, MSI
- Audio - FLAC, MP3, WAV, AAC
- Videos - MP4, MOV, MKV, AVI
- Code - PS1, PY, JS, HTML, CSS, SH
- Misc - Everything else
These are the most common file types on my system, especially among those that end up in the Downloads folder. It's trivial to add more types to the script if necessary. The Misc catch-all may not be needed in your structure, but I included it so that no files are left in the root folder when the script is run. I want every file to be neatly packed away into one of those folders.
Steal this script and make it yours
Run it and watch the magic happen
Here's the full script. All you need to do is paste it into a text editor like Notepad or VS Code, and save it with a descriptive file name like FileOrganizer.ps1 (PowerShell script files use .ps1 as an extension).
$targetPath = "$env:USERPROFILE\Downloads"
$categories = @{
Images = "jpg","jpeg","png","gif","heic","dng","webp","avif"
Documents = "docx","pdf","txt","xlsx","csv"
Archives = "zip","rar","tar","gz","7z"
Executables = "exe","msi"
Audio = "flac","mp3","wav","aac"
Videos = "mp4","mov","mkv","avi"
Code = "ps1","py","js","html","css","sh"
}
function Get-Category($ext) {
$ext = $ext.TrimStart(".").ToLower()
foreach ($c in $categories.Keys) {
if ($categories[$c] -contains $ext) { return $c }
}
"Misc"
}
Get-ChildItem $targetPath -File | ForEach-Object {
$category = Get-Category $_.Extension
$destination = Join-Path $targetPath $category
New-Item -ItemType Directory -Path $destination -Force | Out-Null
$destFile = Join-Path $destination $_.Name
if (Test-Path $destFile) {
$timestamp = Get-Date -Format "yyyyMMdd_HHmmss"
$destFile = Join-Path $destination "$($_.BaseName)_$timestamp$($_.Extension)"
}
Move-Item $_.FullName $destFile
}
The script will create the needed directories (e.g., Images, Videos) if they don't already exist. Keep in mind that it only processes files in the top-level directory and won't touch pre-existing directories (no -Recurse flag). As for files with duplicate file names (i.e., the destination folder already contains a file with the same name as the one being moved), it will append a timestamp to the end in order to avoid overwriting.
If you have never run your own PowerShell script before, you will first need to execute this command to tell PowerShell that it's okay to run locally written scripts and those that are signed:
Set-ExecutionPolicy -Scope CurrentUser RemoteSigned
To run the script, open PowerShell from Windows' Start menu, navigate to where you stored the script, and execute it:
cd C:\Scripts
.\FileOrganizer.ps1
Pull up your Downloads folder in Explorer to confirm that the chaos has been tamed.
What else I'd add
More features worth considering
Open up the script in a text editor and make edits if you think of anything you want to change. The category map near the top would be the most obvious thing to tweak. You may want to add more file types, depending on what you usually work with. For example, you could add a 'Books' category that targets EPUB, MOBI, CBZ, CBR, etc.
The script is really easy to extend if you want to add additional features. Here's something you might add if you wanted the script to generate a log file so you have a record of every file-moving action it takes:
# Add this part near the top
$logPath = Join-Path $targetPath "organizer_log.txt"
# Add this part to the bottom of the ForEach-Object loop, after Move-Item
$timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
Add-Content -Path $logPath -Value "$timestamp | $($_.Name) -> $category"
With PowerShell, there are a lot more possibilities. You could make it watch the directory for new files and sort them instantly, or sort things by category first and date second — Documents\2026\March. Plenty of options.
An elegant solution to a common problem
What I like about scripting in PowerShell is that it doesn't require any overhead. There's no third-party apps to download or extra software to install because Windows already has what you need. For a simple automation job like this, PowerShell fits the role perfectly. You can have Task Scheduler run the script on a routine if you want to automate the process even further.
