Delete all empty folders in a directory tree - oops, script deletes files too

rated by 0 users
This post has 6 Replies | 4 Followers

Not Ranked
Posts 6
Nonapeptide Posted: 08-12-2011 6:18 PM

I have a large folder that has both empty and full folders. I am using SBS 2008 and PowerShell 2.0. I used the following script (running from within the PowerShell ISE as an administrator) to recursively delete only empty folders:

 

dir 'P:\File Server\Cleanup\' -recurse |

Where { $_.PSIsContainer -and @(dir -Lit $_.Fullname -r | Where {!$_.PSIsContainer}).Length -eq 0 } |

Remove-Item -recurse

 

However, I noticed that before the script ran I had 17,832 folders and 232,343 files. After the script ran I had 12,622 folders and 201,286 files. Oops. Surprise

Furthermore, I saw the following errors in the ISE which puzzled me:

 

 

+ Remove-Item <<<<  -recurse

+ CategoryInfo: PermissionDenied: (desktop.ini:FileInfo) [Remove-Item], IOException

+ FullyQualifiedErrorId : RemoveFileSystemItemUnAuthorizedAccess,Microsoft.PowerShell.Commands.RemoveItemCommand

Remove-Item: Directory P:\path\to\a\folder cannot be removed because it  is not empty.

 

 

Wait, WHAT? It's not supposed to even get to the point of attempting to delete a folder if it's not empty!

 

  1. Why did files get deleted when it appears that the logic should have prevented that?
  2. Why are deletions being attempted on folders with files in them?
Thanks for your help!
P.S. Are there no code blocks on these forums? I noticed that the code snippets look kinda ugly.

 

Not Ranked
Posts 5

Try this instead.

gci "N:\test\" -r | ? {$_.PSIsContainer -eq $True} | ? {$_.GetFiles().Count -eq 0 -and $_.GetDirectories().Count -eq 0} | remove-item

 

Steve

Top 25 Contributor
Posts 296
Microsoft MVP
Top Contributor

One problem is that if a folder contains zero length files the length is still zero but it has content

The problem centres on this snippet

(Get-ChildItem $_.Fullname -Recurse |  where {!$_.PSisContainer}).Length

If the folder is empty the length isn't 0. No measurements can be taken so the length doesn't exist! Compare these two lines

PS> (Get-ChildItem C:\test\test3 -Recurse |  where {!$_.PSisContainer}).Length -eq 0
False


PS> (Get-ChildItem C:\test\test3 -Recurse |  where {!$_.PSisContainer}).Length -eq $null
True

The length of an empty folder is NULL not zero.

If you want to identify empty folders this is a much easier and safer way

$path = "c:\test"
$fso = New-Object -ComObject "Scripting.FileSystemObject"

$folder = $fso.GetFolder($path)

foreach ($subfolder in $folder.SubFolders){
 
 if (($subfolder.Files | Measure-Object).Count -gt 0){continue}
 if (($subFolders.SubFolders  | Measure-Object).Count -gt 0){continue}
 if ($subfolder.Size -eq 0 ){Remove-Item -Path $($subfolder.Path) -Force -WhatIf}

}

BUT this doesn't work recursively so we need a bit of modification

function remove-emptyfolder {
 param ($folder)
 
 foreach ($subfolder in $folder.SubFolders){
 
 $notempty = $false
 if (($subfolder.Files | Measure-Object).Count -gt 0){$notempty = $true}
 if (($subFolders.SubFolders  | Measure-Object).Count -gt 0){$notempty = $true}
 if ($subfolder.Size -eq 0 -and !$notempty){
   Remove-Item -Path $($subfolder.Path) -Force -WhatIf
 }
 else {
  remove-emptyfolder $subfolder
 }

}

}

$path = "c:\test"
$fso = New-Object -ComObject "Scripting.FileSystemObject"

$folder = $fso.GetFolder($path)
remove-emptyfolder $folder

 

Not Ranked
Posts 6

Wooow! Excellent! I'll give that a try when I get a chance. I didn't know that a zero length is different from a null. That makes sense now.

I have much more to learn about PowerShell. =)

 

Thanks for your time and effort!

Not Ranked
Posts 6

Just a quick checkin. When running this script, I receive the notification that "The item at c:\path\to\folder has children and the recurse parameter was not specified.. If you continue all children will be removed"

Interestingly, the folders that are throwing that interrupt have folders in them that are themselves completely empty. When I look through the script, my rudimentary skills seem to understand it as iterating down to the lowest leaves in the filesystem tree until it finds a folder that itself has absolutely nothing in it. When it finds a folder like that, it then removes it and goes up a level.

Certainly I can add the -recurse but I'm just wondering why the recursive function doesn't go down to the lowest levels and then work its way back up. There's definitely something I'm not understanding. Big Smile

Not Ranked
Posts 1

hii have u tried this tool ??

http://longpathtool.com

Not Ranked
Posts 1

I am aware that I'm replying to a rather old post but I just wanted to share my modifications. There is no -WhatIf in my version and it's not tested much so probably don't test it on any real folders...

What mainly differs is the ability to handle nested folders that become empty once their empty subfolder has been removed.

(I also made an attempt to allow passing a path as a string which will then automagically become a FSO folder but it lacks error handling etc)

 

function RemoveEmptyFoldersRecursive {

  param ($folder)

 

  # Check if a string was passed and if so make it a FileSystemObject folder

  if ($folder.GetType().FullName -ne "System.__ComObject")

  {

    $fso = New-Object -ComObject "Scripting.FileSystemObject"

    $folder = $fso.GetFolder($folder)

    RemoveEmptyFoldersRecursive $folder

  }

  else {

    if (($folder.SubFolders | Measure-Object).Count -gt 0) {

      # recurse on subfolders if folder has subfolders

      foreach ($subfolder in $folder.SubFolders) {

        RemoveEmptyFoldersRecursive $subfolder

      }

    }

 

    # check again to see if the folder still contains anything

    if (($folder.SubFolders | Measure-Object).Count -eq 0) {

      if (($folder.Files | Measure-Object).Count -eq 0 -and $folder.Size -eq 0) {

        # remove folder if it is empty

        Write-Host "Removing empty folder " $folder.Path

        Remove-Item -Path $($folder.Path) -Force

      }

    }

  }

}

 

Page 1 of 1 (7 items) | RSS
Copyright 2012 PowerShell.com. All rights reserved.