guidox / PC

Find and Delete Empty Folders Recursively

TL;DR

List candidates with **Get-ChildItem -Directory -Recurse**, then delete with **Remove-Item**. Run a **-WhatIf** pass first and repeat until the count stops shrinking.

Before you start

Requirements

  • Windows 11
  • PowerShell
  • 10 minutes
Step by step

Instructions

01

Pick the scope and dry-run the list

A recursive delete on the wrong path is unrecoverable. **-WhatIf** shows the folders that would be removed without touching anything.

$root = 'D:\Archive'
Get-ChildItem $root -Directory -Recurse -Force | Where-Object { -not (Get-ChildItem $_.FullName -Force) } | Measure-Object
Get-ChildItem $root -Directory -Recurse -Force | Where-Object { -not (Get-ChildItem $_.FullName -Force) } | Select-Object -First 10 FullName
02

Understand what counts as empty

A folder with a hidden file is not empty, and a folder holding only an empty folder is not empty until the child goes. That is why one pass is rarely enough.

Get-ChildItem $root -Directory -Recurse -Force | ForEach-Object { $c = (Get-ChildItem $_.FullName -Force | Measure-Object).Count; if ($c -eq 0) { $_.FullName } } | Measure-Object
Get-ChildItem $root -Directory -Recurse -Force -Attributes Hidden | Select-Object -First 5 FullName
03

Delete with a WhatIf first

The same pipeline with **Remove-Item -WhatIf** prints each action. Reading the list before the real run is what prevents deleting a folder that only looks empty.

Get-ChildItem $root -Directory -Recurse -Force | Where-Object { -not (Get-ChildItem $_.FullName -Force) } | Remove-Item -WhatIf
Get-ChildItem $root -Directory -Recurse -Force | Where-Object { -not (Get-ChildItem $_.FullName -Force) } | Remove-Item -Recurse -Force -ErrorAction SilentlyContinue
04

Repeat until the tree stops shrinking

Deleting a child turns its parent into a candidate. Two or three passes usually clear a deep tree; a loop with a stop condition does it cleanly.

do {
  $before = (Get-ChildItem $root -Directory -Recurse -Force | Measure-Object).Count
  Get-ChildItem $root -Directory -Recurse -Force | Where-Object { -not (Get-ChildItem $_.FullName -Force) } | Remove-Item -Recurse -Force -ErrorAction SilentlyContinue
  $after = (Get-ChildItem $root -Directory -Recurse -Force | Measure-Object).Count
  "$before -> $after"
} while ($before -ne $after)
05

Check what was left and why

Folders that survive usually contain a hidden file, a junction or a file locked by a process. That residue is information, not a failure.

Get-ChildItem $root -Directory -Recurse -Force | ForEach-Object { $c = (Get-ChildItem $_.FullName -Force | Measure-Object).Count; if ($c -eq 0) { $_.FullName } } | Select-Object -First 10
Get-ChildItem $root -Directory -Recurse -Force | Where-Object { $_.LinkType } | Select-Object FullName,LinkType,Target
06

Record what you removed

A log of deleted paths makes an accidental deletion investigable. Writing it to a file costs nothing and covers the case where a path mattered.

$log = "$env:USERPROFILE\empty-folders-$(Get-Date -Format yyyyMMdd).txt"
Get-ChildItem $root -Directory -Recurse -Force | Where-Object { -not (Get-ChildItem $_.FullName -Force) } | Select-Object -ExpandProperty FullName | Set-Content $log
Get-Content $log | Measure-Object -Line
Get-ChildItem $root -Directory -Recurse -Force | Measure-Object
Troubleshooting

Common issues

Remove-Item reports access denied

Run the shell as administrator, or the folder is owned by another account. Add -ErrorAction SilentlyContinue and handle the remainder separately.

A folder with a file is deleted

It contained only a zero-byte file that a filter hid from the listing. Check with -Force and list before deleting.

The loop never terminates

A folder is being recreated by an app. Check the parent path and exclude the application's working folders.

Junctions cause an error

Get-ChildItem -Recurse follows them. Add -Attributes !ReparsePoint to skip reparse points.

FAQ

Frequently asked

Does this touch empty files?

No. The filter looks at folders only; empty files stay unless you delete them separately.

Can I undo it?

Only from the log and the Recycle Bin. Remove-Item does not use the bin, which is why the dry run matters.

Is there a GUI for this?

Not built in. The PowerShell pipeline is the reliable path.

How to undo this

Folders cannot be restored automatically. Recreate them from the log with New-Item -ItemType Directory -Path (Get-Content $log) if needed.

Changelog · 1 entry
  1. 2026-11-01
    First version
Interactive version: checklist, feedback, related guides →

Free · no account needed · tracks your progress