Disk full alerts don’t arrive politely. They show up at 2:13 a.m., right after a patch window, right before payroll runs, and usually on the one server nobody “owns.”
When that happens, the worst move is installing a random “cleaner” app with a cheerful UI and an un-cheerful EULA. The best move is boring, fast, and auditable: PowerShell. It tells you what’s big, where it lives, who owns it, and how it got there—without guessing, without magic, without turning your incident into a compliance incident.
Why PowerShell beats “cleaner” apps (in production)
Cleaner apps promise “one click.” Operations people should fear “one click.” Not because you’re allergic to convenience, but because production systems demand evidence, repeatability, and a rollback plan. PowerShell gives you all three.
Cleaner apps have three recurring problems
- They optimize for vibes, not forensics. You get a pie chart and a green button. You don’t get an audit trail that satisfies security, change management, or your future self.
- They guess. “Junk” is a subjective category. Your “junk” might be a line-of-business cache that avoids a 40-minute rebuild during business hours.
- They expand your blast radius. Installing third-party binaries onto servers during an outage is how small incidents become week-long investigations.
PowerShell is boring—and boring wins
PowerShell can scan, sort, filter, export, and re-run the same logic next month. You can review a script in code review. You can log output to a ticket. You can explain your decision in plain English: “Top 50 files by size under D:\Logs; deleted files older than 30 days; kept last 7 days of IIS logs; verified free space increased by X.”
Also: PowerShell doesn’t require admin rights to do useful work. On locked-down environments, read-only inventory is often all you need to diagnose the problem and hand the right list to the right owner.
One quote worth keeping on your wall: “Hope is not a strategy.” — Gene Kranz
Joke #1: Cleaner apps are like diet pills—some work, most don’t, and all of them hate your liver. Servers don’t have a liver, but they do have audit logs.
A few facts and history that explain today’s mess
Disk bloat didn’t appear out of nowhere. It’s the predictable result of decades of Windows behavior, enterprise software habits, and storage economics. Here are concrete facts that show up in real environments:
- NTFS has supported alternate data streams since the 1990s. Most tools don’t show them. Most malware authors love them. Most “cleaner” apps ignore them.
- Windows Installer (MSI) caching is deliberate. It keeps copies of installer data in
C:\Windows\Installerso repairs and patches can run later. Deleting it “works” until it doesn’t. - Windows Update’s component store (WinSxS) is not a simple cache. It’s part of servicing. Size on disk is often less than Explorer suggests due to hardlinks.
- Pagefile and hibernation trade disk for stability and speed. Many laptops ship with hibernation enabled; many VMs ship with pagefiles sized for worst-case memory pressure.
- VSS snapshots can quietly consume huge space. Backup products, “Previous Versions,” and app-consistent snapshots use shadow storage that grows until it hits its cap—or your free space.
- “Logs are cheap” became a lie when SSDs got fast. High-throughput logging plus small OS disks is a classic Windows Server failure mode.
- Junction points and reparse points can trick naive scans. If you recurse without care, you can loop into
C:\Users\All Usersstyle redirects and double-count. - USN Change Journal exists for a reason. It tracks filesystem changes for indexing/replication/backup. Some workloads churn it hard; it can grow large on busy volumes.
- Outlook PSTs never stopped happening. Even with modern mail platforms, you’ll still find multi-GB PST archives on file shares—usually in the least-backed-up place possible.
Fast diagnosis playbook: find the bottleneck before you “clean”
Disk alerts often hide the real problem: a runaway process, a failing backup job, a stuck spooler, or a retention policy that never existed. This playbook is what you do when you have 10 minutes and a Slack channel that’s getting loud.
First: verify the symptom and the scope
- Which volume is actually low? Not “the server.” The volume. C: might be fine while a mounted VHDX is drowning.
- Is free space dropping right now? If yes, you’re hunting a writer (logs, dumps, temp). If no, you’re hunting accumulation (retention, backups, installers).
- Is it one machine or many? Many machines points to policy, patching, or an app rollout. One machine points to local workload or corruption.
Second: decide whether you need “who is writing” or “what is big”
- Free space dropping fast: look at event logs, running processes, and directories that grow (logs, temp, spool, crash dumps).
- Free space stable but low: inventory the largest directories and files; focus on human-owned data and app caches.
Third: identify the “do not touch” zones
Most incidents are made worse by deleting the wrong thing. Before you delete anything, tag these as “handle with care”:
C:\Windowsand especiallyC:\Windows\InstallerC:\Windows\WinSxS- Hyper-V/VMware disk files (
.vhdx,.vmdk) - Database data/log paths (SQL, Exchange, etc.)
- Backup repositories and shadow copy storage
Fourth: pick the lowest-risk relief valve
If you need immediate space to stop outages, the lowest-risk options are usually:
- Rotate/compress logs (app logs, IIS logs) with known retention
- Clear
%TEMP%for the relevant service account (carefully) - Remove old crash dumps if you already captured what you need
- Move large, known data sets to a bigger volume (with owners notified)
Practical tasks (commands, output meaning, and decisions)
Below are real tasks you can run on Windows hosts. The commands are shown as if you’re on a shell prompt; the important part is the PowerShell you execute. Each task includes: command, what the output means, and what decision to make from it.
Task 1: Confirm which volumes are actually low
cr0x@server:~$ powershell -NoProfile -Command "Get-Volume | Sort-Object -Property DriveLetter | Select DriveLetter,FileSystemLabel,FileSystem,SizeRemaining,Size | Format-Table -AutoSize"
DriveLetter FileSystemLabel FileSystem SizeRemaining Size
----------- -------------- ---------- ------------- ----
C OS NTFS 8.21 GB 127.87 GB
D Data NTFS 412.50 GB 931.51 GB
E Logs NTFS 900.12 MB 50.00 GB
What it means: E: is the fire. C: is not. This prevents the classic mistake: cleaning the wrong drive because someone said “the server is full.”
Decision: Focus scans on E:\. If E: is meant for logs, check retention and writers.
Task 2: See if free space is dropping in real time (quick check)
cr0x@server:~$ powershell -NoProfile -Command "$d='E'; 1..5 | ForEach-Object { Get-Volume -DriveLetter $d | Select DriveLetter,SizeRemaining; Start-Sleep -Seconds 3 }"
DriveLetter SizeRemaining
----------- -------------
E 900.12 MB
E 892.44 MB
E 881.03 MB
E 870.77 MB
E 861.65 MB
What it means: You’re actively losing space. That’s a writer, not a historical accumulation.
Decision: Prioritize “what is growing right now” directories (logs/temp/spool) and recent file timestamps.
Task 3: Find the top 50 largest files under a path
cr0x@server:~$ powershell -NoProfile -Command "Get-ChildItem -LiteralPath 'E:\' -File -Recurse -ErrorAction SilentlyContinue | Sort-Object Length -Descending | Select-Object -First 50 FullName, @{n='GB';e={[math]::Round($_.Length/1GB,2)}}, LastWriteTime | Format-Table -AutoSize"
FullName GB LastWriteTime
-------- -- -------------
E:\Logs\app\trace-2026-02-05.log 9.8 2/5/2026 2:10:12 AM
E:\Dumps\serviceA_2026_02_05_0211.dmp 4.2 2/5/2026 2:11:43 AM
E:\Logs\iis\W3SVC1\u_ex260205.log 1.1 2/5/2026 2:05:01 AM
What it means: Big offenders are obvious: a trace log and crash dumps are eating the disk.
Decision: Stop or reconfigure the writer before deleting, or you’ll be doing the same cleanup every 10 minutes.
Task 4: Find the largest directories (fast-ish, no extra modules)
cr0x@server:~$ powershell -NoProfile -Command "Get-ChildItem -LiteralPath 'E:\' -Directory -Force | ForEach-Object { $size=(Get-ChildItem -LiteralPath $_.FullName -File -Recurse -Force -ErrorAction SilentlyContinue | Measure-Object Length -Sum).Sum; [pscustomobject]@{Path=$_.FullName; GB=[math]::Round($size/1GB,2)} } | Sort-Object GB -Descending | Select-Object -First 15 | Format-Table -AutoSize"
Path GB
---- --
E:\Logs 38.44
E:\Dumps 10.21
E:\Temp 1.02
What it means: Confirms “big areas” so you don’t waste time in tiny directories.
Decision: Drill into the top 1–2 directories; ignore the rest until you’ve reclaimed enough space.
Task 5: Identify recent growth (largest files written in last 24 hours)
cr0x@server:~$ powershell -NoProfile -Command "$since=(Get-Date).AddHours(-24); Get-ChildItem -LiteralPath 'E:\' -File -Recurse -ErrorAction SilentlyContinue | Where-Object LastWriteTime -ge $since | Sort-Object Length -Descending | Select-Object -First 30 FullName, @{n='MB';e={[math]::Round($_.Length/1MB,1)}}, LastWriteTime | Format-Table -AutoSize"
FullName MB LastWriteTime
-------- -- -------------
E:\Logs\app\trace-2026-02-05.log 10032.0 2/5/2026 2:10:12 AM
E:\Dumps\serviceA_2026_02_05_0211.dmp 4300.4 2/5/2026 2:11:43 AM
What it means: Confirms these are fresh. If the biggest files are old, the problem is retention. If they’re new, it’s a live incident.
Decision: Escalate to app owner with evidence: exact paths and timestamps.
Task 6: Show file types consuming space (group by extension)
cr0x@server:~$ powershell -NoProfile -Command "Get-ChildItem -LiteralPath 'E:\' -File -Recurse -ErrorAction SilentlyContinue | Group-Object Extension | ForEach-Object { $sum=($_.Group | Measure-Object Length -Sum).Sum; [pscustomobject]@{Ext=$_.Name; Count=$_.Count; GB=[math]::Round($sum/1GB,2)} } | Sort-Object GB -Descending | Select-Object -First 15 | Format-Table -AutoSize"
Ext Count GB
--- ----- --
.log 1242 29.10
.dmp 14 10.21
.zip 188 3.44
What it means: Your space is mostly logs and dumps. That’s operationally solvable.
Decision: Implement rotation/compression for .log, and configure dump retention or move dumps to a larger volume.
Task 7: Find huge files owned by “Users” paths (often human-caused)
cr0x@server:~$ powershell -NoProfile -Command "Get-ChildItem -LiteralPath 'C:\Users' -File -Recurse -ErrorAction SilentlyContinue | Where-Object Length -gt 2GB | Sort-Object Length -Descending | Select FullName, @{n='GB';e={[math]::Round($_.Length/1GB,2)}}, LastWriteTime | Format-Table -AutoSize"
FullName GB LastWriteTime
-------- -- -------------
C:\Users\jdoe\Downloads\vm-image.vhdx 22.5 1/12/2026 4:44:02 PM
C:\Users\jdoe\AppData\Local\Temp\installer-cache.bin 3.1 2/4/2026 9:01:15 AM
What it means: A user profile is hosting something that belongs on a data drive, not the OS disk.
Decision: Move it (not delete) if it’s legitimate, or enforce profile cleanup policies if it’s junk.
Task 8: Check Recycle Bin size (surprisingly effective on shared hosts)
cr0x@server:~$ powershell -NoProfile -Command "Get-ChildItem -LiteralPath 'C:\$Recycle.Bin' -Force -ErrorAction SilentlyContinue | Select Name,FullName | Format-Table -AutoSize"
Name FullName
---- --------
S-1-5-21-2222222222-3333333333-4444444444-1001 C:\$Recycle.Bin\S-1-5-21-2222222222-3333333333-4444444444-1001
cr0x@server:~$ powershell -NoProfile -Command "Get-ChildItem -LiteralPath 'C:\$Recycle.Bin' -Force -Recurse -ErrorAction SilentlyContinue | Measure-Object Length -Sum | Select @{n='GB';e={[math]::Round($_.Sum/1GB,2)}}"
GB
--
14.72
What it means: Deleted files still consume disk. On RDS hosts and shared servers, this can be a silent killer.
Decision: Empty recycle bins via policy or targeted cleanup—after confirming the host’s user-data expectations.
Task 9: Inspect shadow copy storage (VSS) usage
cr0x@server:~$ powershell -NoProfile -Command "vssadmin list shadowstorage"
vssadmin 1.1 - Volume Shadow Copy Service administrative command-line tool
(C) Copyright 2013 Microsoft Corp.
Shadow Copy Storage association
For volume: (E:)\\?\Volume{11111111-2222-3333-4444-555555555555}\
Shadow Copy Storage volume: (E:)\\?\Volume{11111111-2222-3333-4444-555555555555}\
Used Shadow Copy Storage space: 18.432 GB (36%)
Allocated Shadow Copy Storage space: 20.000 GB (40%)
Maximum Shadow Copy Storage space: 20.000 GB (40%)
What it means: VSS has claimed 20 GB. On a 50 GB log volume, that’s aggressive.
Decision: If VSS isn’t required for that volume, reduce max size or relocate it. Coordinate with backup/restore owners first.
Task 10: Identify Windows Error Reporting dumps and crash artifacts
cr0x@server:~$ powershell -NoProfile -Command "Get-ChildItem -LiteralPath 'C:\ProgramData\Microsoft\Windows\WER' -Recurse -File -ErrorAction SilentlyContinue | Sort-Object Length -Descending | Select-Object -First 20 FullName,@{n='MB';e={[math]::Round($_.Length/1MB,1)}},LastWriteTime | Format-Table -AutoSize"
FullName MB LastWriteTime
-------- -- -------------
C:\ProgramData\Microsoft\Windows\WER\ReportArchive\AppCrash_serviceA... 950.2 2/5/2026 1:58:03 AM
What it means: Crashes are leaving evidence. Good for debugging, bad for tiny disks.
Decision: If the incident is ongoing, keep the newest artifacts and purge older ones after you’ve captured them for engineering.
Task 11: Check IIS logs size and apply retention safely
cr0x@server:~$ powershell -NoProfile -Command "$p='C:\inetpub\logs\LogFiles'; Get-ChildItem -LiteralPath $p -File -Recurse -ErrorAction SilentlyContinue | Measure-Object Length -Sum | Select @{n='GB';e={[math]::Round($_.Sum/1GB,2)}}"
GB
--
33.87
cr0x@server:~$ powershell -NoProfile -Command "$p='C:\inetpub\logs\LogFiles'; $cut=(Get-Date).AddDays(-30); Get-ChildItem -LiteralPath $p -File -Recurse -ErrorAction SilentlyContinue | Where-Object LastWriteTime -lt $cut | Select-Object -First 5 FullName,LastWriteTime | Format-Table -AutoSize"
FullName LastWriteTime
-------- -------------
C:\inetpub\logs\LogFiles\W3SVC1\u_ex251201.log 12/1/2025 12:00:00 AM
C:\inetpub\logs\LogFiles\W3SVC1\u_ex251202.log 12/2/2025 12:00:00 AM
What it means: You can reclaim space by removing logs older than retention. The preview shows which files would be affected.
Decision: If 30 days is acceptable for your org, delete those older logs (or compress them). Always preview first.
Task 12: Export an inventory for audit and escalation
cr0x@server:~$ powershell -NoProfile -Command "$root='E:\'; Get-ChildItem -LiteralPath $root -File -Recurse -ErrorAction SilentlyContinue | Sort-Object Length -Descending | Select-Object FullName,Length,LastWriteTime | Select-Object -First 500 | Export-Csv -NoTypeInformation -Path 'C:\Temp\top500-files.csv'; Get-Item 'C:\Temp\top500-files.csv' | Select Name,Length"
Name Length
---- ------
top500-files.csv 189432
What it means: You now have a shareable artifact: evidence for tickets, approvals, and follow-up.
Decision: Attach the CSV to the incident. Make ownership someone else’s problem with data, not vibes.
Task 13: Find files bigger than a threshold (surgical targeting)
cr0x@server:~$ powershell -NoProfile -Command "Get-ChildItem -LiteralPath 'E:\' -File -Recurse -ErrorAction SilentlyContinue | Where-Object Length -gt 1GB | Sort-Object Length -Descending | Select FullName, @{n='GB';e={[math]::Round($_.Length/1GB,2)}}, LastWriteTime | Format-Table -AutoSize"
FullName GB LastWriteTime
-------- -- -------------
E:\Logs\app\trace-2026-02-05.log 9.8 2/5/2026 2:10:12 AM
E:\Dumps\serviceA_2026_02_05_0211.dmp 4.2 2/5/2026 2:11:43 AM
What it means: A short list of “worth arguing about” files.
Decision: For each file: keep, move, compress, or delete—with an owner and a reason.
Task 14: Find directories with huge counts of small files (performance and backup pain)
cr0x@server:~$ powershell -NoProfile -Command "$p='E:\Logs'; Get-ChildItem -LiteralPath $p -Directory -Recurse -ErrorAction SilentlyContinue | ForEach-Object { $c=(Get-ChildItem -LiteralPath $_.FullName -File -ErrorAction SilentlyContinue).Count; if($c -gt 5000){ [pscustomobject]@{Path=$_.FullName; FileCount=$c} } } | Sort-Object FileCount -Descending | Select-Object -First 10 | Format-Table -AutoSize"
Path FileCount
---- ---------
E:\Logs\app\debug-archive 18234
What it means: It’s not always “big files.” Massive file counts slow scans, backups, and antivirus.
Decision: Rotate, compress into archives, or redesign logging. For “archive” folders, consider monthly ZIPs and deletion of originals after verification.
Task 15: Detect reparse points/junctions to avoid double-counting
cr0x@server:~$ powershell -NoProfile -Command "Get-ChildItem -LiteralPath 'C:\' -Directory -Force -ErrorAction SilentlyContinue | Where-Object { $_.Attributes -match 'ReparsePoint' } | Select FullName,Attributes | Format-Table -AutoSize"
FullName Attributes
-------- ----------
C:\Documents and Settings Directory, ReparsePoint
What it means: Recursing blindly can loop or re-traverse redirected paths.
Decision: Exclude or handle reparse points explicitly in deep scans on OS volumes.
Task 16: Check whether a network share scan is even sane (latency first)
cr0x@server:~$ powershell -NoProfile -Command "Test-Path '\\fileserver01\deptshare'; (Get-Date); Get-ChildItem '\\fileserver01\deptshare' -ErrorAction Stop | Select-Object -First 5 Name | Format-Table -AutoSize; (Get-Date)"
True
02/05/2026 02:20:01
Name
----
Accounting
Engineering
Legal
Marketing
Projects
02/05/2026 02:20:03
What it means: Basic listing takes ~2 seconds. That’s workable; if it took 30–60 seconds, a recursive scan would be misery.
Decision: If the share is slow, scan off-hours, scan top-level first, or run the scan on the file server locally.
Joke #2: Disk cleanup tools love to say “Found 38 GB of junk.” If it were truly junk, it wouldn’t be sitting on your most expensive storage.
Three corporate mini-stories from the disk-space trenches
Mini-story 1: The incident caused by a wrong assumption
A team inherited a Windows Server VM that ran a customer-facing API. The alert was simple: “C: under 5% free.” The on-call engineer did what many of us have done under pressure: opened Explorer, right-clicked C:, and clicked “Disk Cleanup.” It freed a little space, and the alert quieted down. For an hour.
The alert came back, harsher. This time the service started timing out. The engineer assumed “logs are growing” and deleted a handful of .log files from an application folder. The service recovered again—briefly. Then it fell over completely.
The real culprit wasn’t the app logs. It was a new diagnostic setting that enabled verbose request tracing into C:\Windows\Temp under a service account. The service wrote huge trace files continuously. Deleting files treated the symptom, not the disease.
Once they used PowerShell to list “largest files written in the last hour,” the pattern was obvious: gigabytes of fresh temp traces. They disabled the setting, moved the trace path to a larger data volume, and added retention.
The wrong assumption was “this is standard disk bloat.” It was an active write-amplification incident. In production, the direction of time matters: is the disk filling now, or did it fill over months?
Mini-story 2: The optimization that backfired
A different company had a file server where users complained about slow search and slow folder browsing. Someone proposed an “optimization”: deduplicate storage by archiving old directories into ZIPs and moving them into a single \Archive share. Less clutter, fewer files, fewer problems—on paper.
They ran a script that zipped everything older than 180 days. It did reduce file count. It also created a new failure mode: giant ZIPs that changed whenever a single file was added, causing backups to re-copy multi-gigabyte archives repeatedly. The backup window expanded and started colliding with business hours.
Worse, antivirus scanning had to crack open huge archives, causing CPU spikes. A “cleanup” also became a performance regression. Users were not impressed by the concept of “compressed efficiency” when Explorer froze.
The fix wasn’t to abandon cleanup. It was to do it correctly: archive immutably (monthly, closed sets), keep archives read-only, and use retention policies aligned with backup strategy. PowerShell helped them quantify the change: file count, total size, and “files modified in last N days” to avoid churning archives.
Optimization backfires when it ignores downstream systems: backups, AV, indexing, and restores. Disk space is never just disk space.
Mini-story 3: The boring but correct practice that saved the day
In a regulated environment, a Windows application server handled batch imports every night. The team had a dull practice: every deployment included a disk-usage report attached to the change ticket. It wasn’t fancy. It was a small PowerShell script that exported top directories and file types to CSV.
One night, free space dipped faster than usual. The on-call engineer didn’t guess. They pulled the last three CSVs and compared them. A new folder appeared under D:\Data\Import\Staging with a sharp increase in .tmp files. The timestamps aligned with a newly deployed importer.
The developer on call initially argued it “couldn’t be us” because the importer cleans up temporary files. The report didn’t care. It showed 120,000 temp files created during the job and never removed when the job crashed mid-stream.
Because the team already had a routine report, the incident response was surgical: delete temp files older than 7 days, fix the importer to clean on failure paths, and cap staging space. No frantic clicking, no mystery tools, no accidental deletion of installers or system files.
This is why boring practices win. They create baselines. Baselines turn arguments into fixes.
Common mistakes: symptom → root cause → fix
1) “Explorer says WinSxS is huge”
Symptom: You see a giant C:\Windows\WinSxS folder in Explorer and panic.
Root cause: Explorer overstates size because it doesn’t account for servicing hardlinks the way you think it does.
Fix: Don’t delete files in WinSxS. Use supported servicing cleanup methods (and coordinate patch windows). Use PowerShell scans to find non-system bloat first.
2) “We deleted stuff but the disk fills again immediately”
Symptom: You free 10 GB; it’s gone in 15 minutes.
Root cause: Active writer (verbose logging, runaway dump generation, temp files on loop, stuck queue).
Fix: Identify recent writes (LastWriteTime), then stop/reconfigure the writer. Deleting without fixing is just donating your sleep to entropy.
3) “Cleaner app freed space, then updates broke”
Symptom: After “cleanup,” patching or app repair fails with missing installer resources.
Root cause: Someone deleted MSI cache or system installer files (C:\Windows\Installer).
Fix: Restore from backup if possible; otherwise reinstall affected apps. Going forward: treat system directories as read-only unless you have a vendor-approved procedure.
4) “Disk usage scan takes forever or loops”
Symptom: Recursive scans never end, show duplicates, or spike CPU.
Root cause: Following reparse points/junctions; scanning network shares over slow links; antivirus interference.
Fix: Detect reparse points, scan from the server side, and start at top-level directories before deep recursion.
5) “Backups suddenly got huge after cleanup”
Symptom: Backup jobs start transferring far more data.
Root cause: Archiving/compressing changed many files or created monolithic archives that churn.
Fix: Use immutable archive boundaries, avoid re-writing large archives, and coordinate backup strategy with cleanup.
6) “We deleted log files and the app stopped logging”
Symptom: After deletion, app can’t write logs or behaves oddly.
Root cause: App had an open handle; deletion caused log rotation confusion; permissions/ACL inheritance broke; app expects path to exist.
Fix: Prefer truncation/rotation mechanisms, preserve directory structure, restart services if needed, and set explicit retention policies.
Checklists / step-by-step plan
Checklist A: “We are low on disk right now” (incident mode)
- Identify the volume (Task 1). Write it in the ticket.
- Check if space is dropping (Task 2). If yes, treat as active writer.
- Get top largest recent files (Task 5). Capture top 30 and timestamps.
- Find top file types (Task 6). Logs/dumps/temp are common.
- Choose the lowest-risk relief: old logs, old dumps, temp older than a window.
- Export evidence (Task 12) before deleting anything significant.
- Fix the writer: config change, rotation, path relocation, retention, or bug fix.
- Verify recovery: free space stable; services healthy; monitoring quiet.
Checklist B: “We keep running out of disk every month” (engineering mode)
- Baseline disk usage weekly with scripted exports (top dirs, top file types).
- Separate log volumes from OS volumes where possible. Tiny C: drives and chatty apps don’t coexist peacefully.
- Define retention per log type (security logs differ from debug logs).
- Enforce caps: VSS shadow storage, staging folders, spool directories.
- Make owners visible: map top paths to teams or applications; publish a simple ownership table.
- Automate cleanup only after you can prove it’s safe with previews and dry runs.
Checklist C: “We need to scan a huge file share” (sanity mode)
- Run the scan from the file server if possible (reduces network noise).
- Start at top-level directories only; don’t recurse everywhere first.
- Measure basic directory listing latency (Task 16). If it’s slow, schedule off-hours.
- Export results to CSV and let data owners decide what gets deleted.
FAQ
1) Why not just use a GUI tool like WinDirStat or TreeSize?
On a workstation, fine. On a server during an incident, PowerShell wins because it’s native, scriptable, reviewable, and easy to run remotely. Also: you can export evidence.
2) Is PowerShell scanning safe on production servers?
Read-only scans are generally safe, but they can be I/O heavy on busy volumes. Start targeted (top-level directories, recent writes) and avoid scanning entire network shares in peak hours.
3) What’s the fastest way to find “what changed”?
Filter by LastWriteTime (Task 5) and sort by size. It tells you what grew recently and is usually enough to identify the writer.
4) Can I delete files directly from PowerShell?
Yes, but do it only after a preview and an export. Deleting is easy; explaining it later is the hard part. Use retention rules (older than X days) and keep a record.
5) Why does my scan miss some files?
Permissions and locked directories are common. Use -ErrorAction SilentlyContinue for inventory, but if you need completeness, run with appropriate rights and log errors.
6) Why does “folder size” disagree between tools?
Hardlinks, reparse points, and tool differences in what they count. Also, some tools count allocated size vs logical size. For decisions, focus on “big files by path” and “what is growing.”
7) How do I handle VSS taking space on a volume?
First confirm it’s supposed to exist for that volume (Task 9). If it isn’t, reduce the maximum or move shadow storage—after coordinating with backup/restore requirements.
8) How do I scan a network share without making everyone hate me?
Run the scan on the file server, limit recursion depth initially, and schedule deep scans off-hours. Export results and let owners decide what’s deletable.
9) What’s the single biggest “don’t do this” in Windows disk cleanup?
Don’t delete random things under C:\Windows (especially Installer and WinSxS) because some blog told you it’s “safe.” Use supported servicing tools and clean application data instead.
10) How do I make this repeatable for my team?
Turn Tasks 1, 3/4, 5, 6, and 12 into a small script that writes CSVs to a known location and attach it to incident runbooks. Repeatability is the whole point.
Conclusion: next steps that won’t haunt you
Cleaner apps sell a story: disk usage is a mystery and only their magic button can fix it. Production is the opposite. Disk usage is knowable. It’s just files, timestamps, and ownership. PowerShell turns “we’re out of space” into a list you can act on.
Do this next
- Pick one host that routinely fills up and run Tasks 1, 4, 6, and 12. Save the CSV.
- Identify the top 3 offenders (directories or file types) and assign owners.
- Implement one retention policy (logs, dumps, temp) with a preview workflow.
- Re-run the same commands next week and compare. If the same offender comes back, you didn’t fix the writer—only the evidence.
- Write it into your runbook: “When disk low: run these commands, export this CSV, contact these owners.” Make it boring on purpose.
If you want a system that stays clean, stop buying “clean.” Start buying “measured.” PowerShell is the measuring stick you already have.