I’ve had this on my to-do list for a long time, and have finally gotten around to looking into it. We’ve largely migrated off Public Folders (thank goodness), but we still have thousands of empty folders sitting there.
I’d originally thought about writing some sort of crazy tree-traversal script to delete empty folders, but as it turns out, this alternative does the job fine. It allows you to delete batches of empty folders at a time. You could schedule the script to run once every hour or so.
The script does the following:
- Gets the first 500 Public Folders, narrows that down to those that don’t have subfolders
- Filters those down again, to exclude folders that contain items
- Deletes the folders, logging the folder name to c:temppf_delete.log
$folders = Get-PublicFolder -Identity "folder name" -Recurse -ResultSize 500 | Where-Object {$_.HasSubFolders -eq $false} $emptyFolders = $folders | Where-Object -FilterScript {@($_ | Get-PublicFolderItemStatistics).Count -eq 0} $emptyFolders | ForEach-Object {$_.Identity.ToString() | Out-File c:temppf_delete.log -append; Remove-PublicFolder -Identity $_.Identity -Confirm:$False}
I originally used Get-PublicFolderStatistics to determine the item count within the folder, but that was really slow. I ended up using @(Get-PublicFolderItemStatistics).Count instead, as that was much faster. The latter takes 1 second per folder, as opposed to 21 seconds per folder for the former.
An alternate method would be to loop over the above routine several times, each time retrieving less items. This will clean up nested folders from the top of the tree a little faster:
(1..5) | % { $folders = Get-PublicFolder -Identity "folder name" -Recurse -ResultSize 100 | Where-Object {$_.HasSubFolders -eq $false} $emptyFolders = $folders | Where-Object -FilterScript {@($_ | Get-PublicFolderItemStatistics).Count -eq 0} $emptyFolders | ForEach-Object {$_.Identity.ToString() | Out-File c:temppf_delete.log -append; Remove-PublicFolder -Identity $_.Identity -Confirm:$False} }
Obviously, you need to test this thoroughly before running it in a production environment. Run at your own risk.
Hi,. Thanks for the script, I tried running this script on my exchange 2007 environment and it tells me Get-PublicFolderItemStatistics is not a valid command, SO I tried Get-PublicFolderstatistics instead but it gives me an error that I can’t call a null-valued expression at this step {$_.Identity.ToString()
Any Insight how to get this to work on an exchange 2007 server ?
Thanks
LikeLike
Hi Paulo,
It appears that Get-PublicFolderItemStatistics is only supported on Exchange 2010 and newer.
I don’t have access to an Exchange 2007 install, but you could try replacing the second line with:
$emptyFolders = $folders | Where-Object -FilterScript {@($_ | Get-PublicFolderStatistics).ItemCount -eq 0}
Regards,
Daniel
LikeLike
Hmmm, I get the exact same error at line 3 char 53 |cannot call a method on a null-valued expression
and then a |cannot bind argument to parameter ‘identity’ because it is null
LikeLike
I had this work fine in a number of my subdirectories (Exchange 2010) but now I’m actually getting this same set of errors in a different one. Odd.
LikeLike
Thank you! Your script worked great on my Exchange 2013 server!
LikeLike
You’re welcome, Michael. Good to hear that it worked for you.
LikeLike
This worked beautifully in Exchange 2010 (obviously). Thanks so much for posting it, it saved me SO much time and frustration.
LikeLike
Excellent. That’s great to hear, Meg. Pleased to be of assistance. That’s what this blog is all about.
LikeLike
I mentioned this above – I had this work fine in a number of my subdirectories but now I’m actually getting the same set of errors listed by another commenter in a different one.
“|cannot call a method on a null-valued expression”
and
“|cannot bind argument to parameter ‘identity’ because it is null”
I’m trying out a couple of hunches and will report back if I’m able to bludgeon it into working.
LikeLike
Well, when you’re using it to tidy existing folders, you’ll null out because you don’t have 500 bottom-level folders that are empty after a run or two. So that was silly.
I’m now getting errors regarding accessing the log file as things are deleted, but I can handle that. Thanks again!
LikeLike
Great work thanks for sharing.
I’ve expanded it for use in a large, multiple replica public folder environment. It’s a bit ‘delicate’, and needs hand-holding, but it does what I need it to do.
Bit of an issue if the folder contains 1 item, better described and solved user the Measure/Measure-Object in https://stackoverflow.com/questions/14714284/count-items-in-a-folder-with-powershell.
LikeLike