powershelldirectoryis-emptysubtreedelete-directory

PowerShell: Iteratively remove all empty subfolders from a folder subtree


I wrote the following script to recursively remove any folders that are empty. I have tested this in a sandbox and it appears to be safe. That is, it will only remove a folder if it is empty and it will only navigate within subfolders within the starting parent folder and won't inadvertently go further up in the directory.

So, if you could take a quick look at my script and tell me if you see any dangers, I would appreciate. Thank you!

$isEmpty=1
$iteration=0
while ($isEmpty) {
    $isEmpty=0
    $iteration++
    
    get-childitem -Directory -Force -recurse | ForEach-Object {
        $count=(Get-ChildItem -Path $_.FullName -Force).count
        if ($count -eq 0) {
            $isEmpty=1
            Write-Host "$iteration`t$count`t$_"
            $path="\\?\"+$_.FullName
            $folder= Get-item -Path $path
            $folder.Attributes = $folder.Attributes -band -bnot [System.IO.FileAttributes]::ReadOnly
            $folder.Attributes = $folder.Attributes -band -bnot [System.IO.FileAttributes]::Hidden

            Remove-Item -Force -LiteralPath $path
        }
    }
    
}

Solution

  • $isEmpty=1, $isEmpty=0

    While 1 and 0 do work as implicit Boolean values, it's better to use Booleans explicitly, i.e. $true and $false: $isEmpty = $true, $isEmpty = $false


    Get-ChildItem -Path $_.FullName

    If you know paths to be literal (verbatim) paths rather than wildcard expressions, use -LiteralPath instead of -Path.


    Get-Item -Path $path

    The -LiteralPath recommendation applies equally, but, more importantly:


    $folder.Attributes = $folder.Attributes -band -bnot [System.IO.FileAttributes]::ReadOnly [...]

    You do not need to explicitly clear the Hidden and ReadOnly attributes from file-system items in order for Remove-Item to remove them - using -Force is sufficient.


    Taking a step back:

    You can avoid multiple traversals of your folder subtree if you process directories (folders) bottom up, i.e. if you start with the leaf directories in the directory subtree and iteratively traverse upward:

    Get-ChildItem -Directory -Force -Recurse | 
      Sort-Object -Descending { ($_.FullName -split '[\\/]').Count } |
      Where-Object { 
        if (-not ($_ | Get-ChildItem -Force | Select-Object -First 1)) {
          $_ | Remove-Object -Force -WhatIf
        }
      }
    

    Note: