How to recursively remove all empty folders in PowerShell?

前端 未结 13 2687
野趣味
野趣味 2020-12-08 02:23

I need to recursively remove all empty folders for a specific folder in PowerShell (checking folder and sub-folder at any level).

At the moment I am using this scrip

相关标签:
13条回答
  • 2020-12-08 02:54

    I wouldn't take the comments/1st post to heart unless you also want to delete files that are nested more than one folder deep. You are going to end up deleting directories that may contain directories that may contain files. This is better:

    $FP= "C:\Temp\"
    
    $dirs= Get-Childitem -LiteralPath $FP -directory -recurse
    
    $Empty= $dirs | Where-Object {$_.GetFiles().Count -eq 0 **-and** $_.GetDirectories().Count -eq 0} | 
    
    Select-Object FullName
    

    The above checks to make sure the directory is in fact empty whereas the OP only checks to make sure there are no files. That in turn would result in files nexted a few folders deep also being deleted.

    You may need to run the above a few times as it won't delete Dirs that have nested Dirs. So it only deletes the deepest level. So loop it until they're all gone.

    Something else I do not do is use the -force parameter. That is by design. If in fact remove-item hits a dir that is not empty you want to be prompted as an additional safety.

    0 讨论(0)
  • 2020-12-08 02:58
    $files = Get-ChildItem -Path c:\temp -Recurse -Force | where psiscontainer ; [array]::reverse($files)
    

    [Array]::reverse($files) will reverse your items, so you get the lowest files in hierarchy first. I use this to manipulate filenames that have too long filepaths, before I delete them.

    0 讨论(0)
  • 2020-12-08 02:59

    I have adapted the script of RichardHowells. It doesn't delete the folder if there is a thumbs.db.

    ##############
    # Parameters #
    ##############
    param(
        $Chemin = "" ,  # Path to clean
        $log = ""       # Logs path
    )
    
    
    
    
    ###########
    # Process #
    ###########
    
    
    if (($Chemin -eq "") -or ($log-eq "") ){
    
        Write-Error 'Parametres non reseignes - utiliser la syntaxe : -Chemin "Argument"  -log "argument 2" ' -Verbose 
        Exit
    }
    
    
    
    #loging 
    $date = get-date -format g
    Write-Output "begining of cleaning folder : $chemin at $date" >> $log
    Write-Output "------------------------------------------------------------------------------------------------------------" >> $log
    
    
    <########################################################################
        define a script block that will remove empty folders under a root folder, 
        using tail-recursion to ensure that it only walks the folder tree once. 
        -Force is used to be able to process hidden files/folders as well.
    ########################################################################>
    $tailRecursion = {
        param(
            $Path
        )
        foreach ($childDirectory in Get-ChildItem -Force -LiteralPath $Path -Directory) {
            & $tailRecursion -Path $childDirectory.FullName
        }
        $currentChildren = Get-ChildItem -Force -LiteralPath $Path
        Write-Output $childDirectory.FullName
    
    
    
        <# Suppression des fichiers Thumbs.db #>
        Foreach ( $file in $currentchildren )
        {
            if ($file.name -notmatch "Thumbs.db"){break}
            if ($file.name -match "Thumbs.db"){
                Remove-item -force -LiteralPath $file.FullName}
    
        }
    
    
    
        $currentChildren = Get-ChildItem -Force -LiteralPath $Path
        $isEmpty = $currentChildren -eq $null
        if ($isEmpty) {
            $date = get-date -format g
            Write-Output "Removing empty folder at path '${Path}'.  $date" >> $log
            Remove-Item -Force -LiteralPath $Path
        }
    }
    
    # Invocation of the script block
    & $tailRecursion -Path $Chemin
    
    #loging 
    $date = get-date -format g
    Write-Output "End of cleaning folder : $chemin at $date" >> $log
    Write-Output "------------------------------------------------------------------------------------------------------------" >> $log
    
    0 讨论(0)
  • 2020-12-08 03:00

    If you just want to make sure, that you delete only folders that may contain subfolders but no files within itself and its subfolders, this may be an easier an quicker way.

    $Empty = Get-ChildItem $Folder -Directory -Recurse |
    Where-Object {(Get-ChildItem $_.FullName -File -Recurse -Force).Count -eq 0}
    
    Foreach ($Dir in $Empty)
    {
        if (test-path $Dir.FullName)
        {Remove-Item -LiteralPath $Dir.FullName -recurse -force}
    }
    
    0 讨论(0)
  • 2020-12-08 03:01

    This is a simple approach

    dir -Directory | ? { (dir $_).Count -eq 0 } | Remove-Item
    
    0 讨论(0)
  • You need to keep a few key things in mind when looking at a problem like this:

    1. Get-ChildItem -Recurse performs head recursion, meaning it returns folders as soon as it finds them when walking through a tree. Since you want to remove empty folders, and also remove their parent if they are empty after you remove the empty folders, you need to use tail recursion instead, which processes the folders from the deepest child up to the root. By using tail recursion, there will be no need for repeated calls to the code that removes the empty folders -- one call will do it all for you.
    2. Get-ChildItem does not return hidden files or folders by default. As a result you need to take extra steps to ensure that you don't remove folders that appear empty but that contain hidden files or folders. Get-Item and Get-ChildItem both have a -Force parameter which can be used to retrieve hidden files or folders as well as visible files or folders.

    With those points in mind, here is a solution that uses tail recursion and that properly tracks hidden files or folders, making sure to remove hidden folders if they are empty and also making sure to keep folders that may contain one or more hidden files.

    First this is the script block (anonymous function) that does the job:

    # A script block (anonymous function) that will remove empty folders
    # under a root folder, using tail-recursion to ensure that it only
    # walks the folder tree once. -Force is used to be able to process
    # hidden files/folders as well.
    $tailRecursion = {
        param(
            $Path
        )
        foreach ($childDirectory in Get-ChildItem -Force -LiteralPath $Path -Directory) {
            & $tailRecursion -Path $childDirectory.FullName
        }
        $currentChildren = Get-ChildItem -Force -LiteralPath $Path
        $isEmpty = $currentChildren -eq $null
        if ($isEmpty) {
            Write-Verbose "Removing empty folder at path '${Path}'." -Verbose
            Remove-Item -Force -LiteralPath $Path
        }
    }
    

    If you want to test it here's code that will create interesting test data (make sure you don't already have a folder c:\a because it will be deleted):

    # This creates some test data under C:\a (make sure this is not
    # a directory you care about, because this will remove it if it
    # exists). This test data contains a directory that is hidden
    # that should be removed as well as a file that is hidden in a
    # directory that should not be removed.
    Remove-Item -Force -Path C:\a -Recurse
    New-Item -Force -Path C:\a\b\c\d -ItemType Directory > $null
    $hiddenFolder = Get-Item -Force -LiteralPath C:\a\b\c
    $hiddenFolder.Attributes = $hiddenFolder.Attributes -bor [System.IO.FileAttributes]::Hidden
    New-Item -Force -Path C:\a\b\e -ItemType Directory > $null
    New-Item -Force -Path C:\a\f -ItemType Directory > $null
    New-Item -Force -Path C:\a\f\g -ItemType Directory > $null
    New-Item -Force -Path C:\a\f\h -ItemType Directory > $null
    Out-File -Force -FilePath C:\a\f\test.txt -InputObject 'Dummy file'
    Out-File -Force -FilePath C:\a\f\h\hidden.txt -InputObject 'Hidden file'
    $hiddenFile = Get-Item -Force -LiteralPath C:\a\f\h\hidden.txt
    $hiddenFile.Attributes = $hiddenFile.Attributes -bor [System.IO.FileAttributes]::Hidden
    

    Here's how you use it. Note that this will remove the top folder (the C:\a folder in this example, which gets created if you generated the test data using the script above) if that folder winds up being empty after deleting all empty folders under it.

    & $tailRecursion -Path 'C:\a'
    
    0 讨论(0)
提交回复
热议问题