2008-01-26

Prune Directories with PowerShell

I made a backup of all files with a certain pattern files from one directory to another. If the pattern was, say PostScript (*.ps) files, you can use the following PowerShell statement:

Copy-Item -recurse -filter *.ps <source> <destination>

Now I had a new directory with the same structure as the original one, but Copy-Item made many new empty directories because there were files in the source directories but these files were not copied. Just to be tidy, I wanted to prune the empty directories in the destination path. The Remove-Item cmdlet does not have an option to remove empty directories, so I wrote the following short PowerShell script:

     1  function prune-directory {
     2    param ([string]$path)
     3    if ($path.Length -le 0) {
     4      write-host "Empty path."
     5      return
     6    }
     7    if (-not (test-path -literalPath $path)) {
     8      write-host "Invalid path:", $path
     9      return
    10    }
    11    if (@(get-childitem $path).Count -le 0) {
    12      remove-item $path
    13      return
    14    }
    15    get-childitem $path | where-object { $_.PsIsContainer} | foreach { prune-directory $_.FullName }
    16    if (@(get-childitem $path).Count -le 0) {
    17      remove-item $path
    18    }
    19  }

To use it, just enter:

prune-directory <path>

You should verify that the function works the way you expect before using it. Once your directories or files are deleted, they're GONE.

prune-directory() is a recursive function that walks a directory tree and deletes any empty directory it finds. Lines 3-10 check for invalid parameters, lines 11-14 delete the current directory if it is empty and line 18 calls this function for all children which are containers in the current directory. Lines 19-22 are required in case the current directory has no children because they were all deleted by line 15.

In line 11 and 16, we use @(…) to force the result of get-childitem $path to be an array, otherwise we may not be able to count the number of children in a directory. It's a known - uh - nuance in PowerShell that if a cmdlet finds zero or one object, it returns an scalar value rather than an array.

2008-05-15: This change should fix the problem of escape characters in the path string: test-path -literalPath $path.

2 comments:

  1. This chokes on file names containing square brackets
    (like my itunes folder)

    Eg
    "+ if (-not (test-path <<<< $path)) {
    Get-ChildItem : Cannot retrieve the dynamic parameters for the cmdlet. The specified wildcard pattern is not valid: Min
    istry of Sound_ The 2005 Annual [EMI"

    ReplyDelete
  2. In order to avoid troubles with 'strange' folder names you can replace the test test-path $path with [IO.Directory]::exists($path)

    ReplyDelete