# 📂 Organize Downloads (PowerShell 7.5)

A robust utility script designed to declutter your Downloads folder by automatically sorting files into categorized subdirectories. Updated for PowerShell 7.5.

## 📋 Overview

This script scans a target directory (defaulting to your user Downloads folder) and moves files into an `Organized` subfolder, sorting them into categories like **Documents**, **Images**, **Dev-Scripts**, and **Installers**.

It includes safety features like a **Dry Run** mode to preview changes and a **Types Scanner** to analyze the contents before cleaning.

## 🚀 Usage

### 1. Standard Cleanup
Organizes the default Downloads folder immediately.
```powershell
.\Organize-Downloads.ps1
```

### 2. Dry Run (Safety Mode)
Simulates the organization process without moving any files. It creates a log file showing exactly what would happen and opens it automatically.
```powershell
.\Organize-Downloads.ps1 -Dry
```

### 3. Analyze File Types
Scans the folder and displays a table of file extensions and their counts. Does not move any files.
```powershell
.\Organize-Downloads.ps1 -Types
```

### 4. Custom Path
Organize a specific folder other than Downloads.
```powershell
.\Organize-Downloads.ps1 -Path "C:\Users\Name\Desktop\MessyFolder"
```

## ⚙️ Categories

The script sorts files into the following subdirectories inside `\Organized`:

| Category | Extensions |
| :--- | :--- |
| **Documents** | .pdf, .docx, .txt, .xlsx, .pptx, .csv, .eml |
| **Images** | .jpg, .png, .gif, .webp, .svg, .avif |
| **Design** | .psd, .ai, .excalidraw |
| **Dev-Web** | .php, .js, .json, .html, .css, .xml |
| **Dev-Scripts** | .ps1, .py, .md, .log |
| **Installers** | .exe, .msi, .sys, .cab |
| **Archives** | .zip, .rar, .7z, .gz |
| **Media** | .mp3, .wav, .mp4, .mkv, .mov |
| **Other** | Anything not matching the above |

## 📝 Logging

*   Logs are saved to a `Logs` folder in the parent directory of the target (e.g., `C:\Users\You\Logs`).
*   Log filenames follow the format: `ManualRunLog_yyyy-MM-dd.txt`.

## ⚠️ Requirements

*   **PowerShell 7.5** or later.

```PowerShell
[CmdletBinding()]
param (
    [switch]$Dry,
    [switch]$Types,
    [string]$Path = "$env:USERPROFILE\Downloads"
)

# --- Configuration ---
$DownloadsFolder = $Path
$Files = Get-ChildItem -Path $DownloadsFolder -File
# --- New Functionality: Types Scanner ---
if ($Types) {
    Write-Host "Scanning file types in: $DownloadsFolder" -ForegroundColor Yellow
    
    # Group files by extension and sort by count
    $ExtensionGroups = $Files | Group-Object Extension | Sort-Object Count -Descending
    
    if ($ExtensionGroups.Count -eq 0) {
        Write-Host "No files found in the directory." -ForegroundColor Gray
    } else {
        $ExtensionGroups | Select-Object @{Name="Extension"; Expression={$_.Name}}, Count | Format-Table -AutoSize
    }
    
    exit # Stop the script here so it doesn't proceed to organize
}

$OrganizedFolder = Join-Path $DownloadsFolder "Organized"
$LogsFolder      = Join-Path (Split-Path $DownloadsFolder) "Logs"
$LogFile         = Join-Path $LogsFolder ("ManualRunLog_" + (Get-Date -format "yyyy-MM-dd") + ".txt")

$SubFolders = [ordered]@{
    "Documents"   = ".pdf", ".docx", ".txt", ".xlsx", ".pptx", ".doc", ".ppt", ".csv", ".eml"
    "Images"      = ".jpg", ".jpeg", ".png", ".gif", ".bmp", ".webp", ".svg", ".ico", ".avif"
    "Design"      = ".psd", ".ai", ".excalidraw"
    "Dev-Web"     = ".php", ".js", ".json", ".html", ".htm", ".css", ".xml", ".woff2"
    "Dev-Scripts" = ".ps1", ".py", ".md", ".log"
    "Installers"  = ".exe", ".msi", ".sys", ".cab"
    "Archives"    = ".zip", ".rar", ".7z", ".gz", ".xz", ".wpress"
    "Music"       = ".mp3", ".wav", ".flac"
    "Videos"      = ".mp4", ".avi", ".mov", ".mkv"
    "Other"       = "*" 
}

# --- Preparation ---
if (!(Test-Path $OrganizedFolder)) {
    Write-Verbose "Creating organized folder: $OrganizedFolder"
    New-Item -ItemType Directory -Path $OrganizedFolder | Out-Null
}
if (!(Test-Path $LogsFolder)) {
    New-Item -ItemType Directory -Path $LogsFolder | Out-Null
}

# --- Core Logic ---
Write-Host "Starting manual organization of: $DownloadsFolder" -ForegroundColor Yellow
if ($Dry) { Write-Host "!!! DRY RUN ENABLED - No files will be moved !!!" -ForegroundColor Magent }


foreach ($File in $Files) {
    foreach ($Category in $SubFolders.Keys) {
        $Extensions = $SubFolders[$Category]
        
        # Check for extension match or the catch-all wildcard
        if ($Extensions -contains $File.Extension -or $Extensions -contains "*") {
            $DestinationFolder = Join-Path $OrganizedFolder $Category
            $DestinationPath   = Join-Path $DestinationFolder $File.Name

            if (!(Test-Path $DestinationFolder)) {
                New-Item -ItemType Directory -Path $DestinationFolder | Out-Null
            }

            $Timestamp = (Get-Date).ToString("yyyy-MM-dd HH:mm:ss")
            
            if ($Dry) {
                $LogMsg = "$Timestamp - [DRY RUN] Would move '$($File.Name)' to '$Category'"
                Write-Host $LogMsg -ForegroundColor Gray
                $LogMsg | Out-File -Append -FilePath $LogFile
            } else {
                $LogMsg = "$Timestamp - Moved '$($File.Name)' to '$Category'"
                try {
                    Move-Item -Path $File.FullName -Destination $DestinationPath -Force
                    Write-Host $LogMsg -ForegroundColor Cyan
                    $LogMsg | Out-File -Append -FilePath $LogFile
                } catch {
                    $ErrorMsg = "$Timestamp - ERROR: Could not move '$($File.Name)': $($_.Exception.Message)"
                    Write-Host $ErrorMsg -ForegroundColor Red
                    $ErrorMsg | Out-File -Append -FilePath $LogFile
                }
            }
            
            # This break exits the $Category loop and moves to the next $File
            break 
        }
    }
}

Write-Host "Organization complete." -ForegroundColor Green
if ($Dry) { Invoke-Item $LogFile }
```