PowerShell Problem Solver: Delete Empty Folders with PowerShell

Managing files and folders is a never ending task, where I frequently see a common question on how to delete empty folders. Actually deleting a folder is very easy in PowerShell. The real question is how do I identify empty folders?

Let’s take a look. First, we’ll assume you are searching for folders from a given root.

$root = "C:\Work"

Beginning with PowerShell 3.0, you can easily filter files or folders. This will get all of the root or top-level folders.

dir $root -Directory

Grabbing a list of top-level file folder. (Image Credit: Jeff Hicks)
Grabbing a list of top-level file folder. (Image Credit: Jeff Hicks)

 
Or I can get all directories.

dir $root –Directory –recurse | Select Fullname

Filtering for all directories in Windows PowerShell. (Image Credit: Jeff Hicks)
Filtering for all directories in Windows PowerShell. (Image Credit: Jeff Hicks)

 
Now that I know the directories, all I need to do is find directories that contain files. I am going to assume that if a folder contains an empty subfolder, then both can be deleted. The easy way to identify if a folder contains a file is to list files. A folder object has a GetFiles() method. If the method returns any files, I can interpret that as True.

dir $root -Directory -recurse | where { $_.GetFiles()} |  Select Fullname

Thus, these folders are not empty.

Testing if folders contain an item with GetFiles() in Windows PowerShell. (Image Credit: Jeff Hicks)
Testing if folders contain an item with GetFiles() in Windows PowerShell. (Image Credit: Jeff Hicks)

 
To turn this around all I need to do is use the –Not operator.

dir $root -Directory -recurse | where { -NOT $_.GetFiles()} |  Select Fullname

Using the reverse logic from the previous example. (Image Credit: Jeff Hicks)
Using the reverse logic from the previous example. (Image Credit: Jeff Hicks)

 
But there is a challenge here. Look at the Demo2 subfolder.
Demo4 doesn't contain a file and is a subfolder, but Demo3 contains a file. (Image Credit: Jeff Hicks)
Demo4 doesn’t contain a file and is a subfolder, but Demo3 contains a file. (Image Credit: Jeff Hicks)

 
There is an empty subfolder Demo4, but Demo3 contains a file. There are also no files in the root of Demo2. I can’t delete Demo2 because that will remove Demo3 and the file. But I do want to remove Demo4.

This won’t be apparent to you, but let’s revisit the GetFiles() method I used to identify folders with files. This is a .NET method and often there are several ways to invoke methods.

(get-item $root).getfiles.OverloadDefinitions

GetFiles() method in Windows PowerShell. (Image Credit: Jeff Hicks)
GetFiles() method in Windows PowerShell. (Image Credit: Jeff Hicks)

 
The SearchOption looks promising. I’m guessing it is a way to telling PowerShell how far to search. In my experience a value like this is an enumeration.

[enum]::GetValues([system.io.searchoption])

Using GetValues and its SearchOption in Windows PowerShell. (Image Credit: Jeff Hicks)
Using GetValues and its SearchOption in Windows PowerShell. (Image Credit: Jeff Hicks)

 
This probably means that I can search for a file recursively.

dir $root -Directory -recurse | where { $_.GetFiles("*","AllDirectories")} |  Select Fullname

And sure enough, these are the folders that contain at least one file somewhere in the path.

Using GetFiles() to search for files recursively in Windows PowerShell. (Image Credit: Jeff Hicks)
Using GetFiles() to search for files recursively in Windows PowerShell. (Image Credit: Jeff Hicks)

 
These are files I do not want to remove. So adding –NOT should give a list of truly empty folders.

dir $root -Directory -recurse | where {-NOT $_.GetFiles("*","AllDirectories")} |  Select Fullname

Using a -NOT operator to find a true list of empty folders. (Image Credit: Jeff Hicks)
Using a -NOT operator to find a true list of empty folders. (Image Credit: Jeff Hicks)

 
I can verify by attempting to get a directory listing of these files.

dir $root -Directory -recurse | where {-NOT $_.GetFiles("*","AllDirectories")} | dir

But all I get is the directory entry.

Directory entry in Windows PowerShell. (Image Credit: Jeff Hicks)
Directory entry in Windows PowerShell. (Image Credit: Jeff Hicks)

 
These folders should be safe to remove.

dir $root -Directory -recurse | where {-NOT $_.GetFiles("*","AllDirectories")} | del -recurse -whatif

Performing the operation 'Remove Directory' on the target directory. (Image Credit: Jeff Hicks)
Performing the operation ‘Remove Directory’ on the target directory. (Image Credit: Jeff Hicks)

 
I’m using –recurse because some of the folders contain a hierarchy of empty folders. If I didn’t include –Recurse PowerShell would prompt me. I can run the command without –Whatif and all of the empty folders are removed.

Even though I was testing this locally, you should be able to use the same techniques on a remote computer as well. You should be able to use remoting. First, you might want to identify empty folders.

invoke-command -scriptblock { dir c:\shared -Directory -recurse | where {-NOT $_.GetFiles("*","AllDirectories")} |  Select Fullname} -ComputerName CHI-FP02

I’m using the same command except it is running in a remote session on CHI-FP02.

Demonstrating how to run the operation on a remote computer. (Image Credit: Jeff Hicks)
Demonstrating how to run the operation on a remote computer. (Image Credit: Jeff Hicks)

 
All I need to do is delete the folders when I’m ready.

invoke-command -scriptblock { dir c:\shared -Directory -recurse | where {-NOT $_.GetFiles("*","AllDirectories")} |  del -recurse -whatif } -ComputerName CHI-FP02

Deleting the file folders in Windows PowerShell. (Image Credit: Jeff Hicks)
Deleting the file folders in Windows PowerShell. (Image Credit: Jeff Hicks)

 
If you find this is going to be a common task, you might turn all of this into a function. Just be sure to include SupportsShouldProcess so that you can use –Whatif.
So the next time you come across a PowerShell problem to solve, take a step back and consider what the real challenge might be. If you get stuck, I encourage you to use the PowerShell forum on the site.