Patching File System Trees with PowerShell

by Klaus Graefensteiner 8/28/2008 4:59:36 PM

Introduction

While working on a elaborate PowerShell script I needed to find a solution for the following problem: I wanted to do a string replace operation on a file system path name and have the resulting new string be reflected by the file system. For example the path name "C:\dogs\dog food\my favorites\hot dogs\Who let the dogs out.mp3" should be renamed by replacing "dog" with "cat". The resulting path name would be "C:\cats\cat food\my favorites\hot cats\Who let the cats out.mp3". Sounds easy, but how do I move the folders and files that are referred to in the path to their new locations? And even better, how can I do this recursively? This short blog post demonstrates two possible approaches.

Oak tree in inverse colors

Figure 1: Oak tree in inverse colors

.NET and recursion

This approach takes advantage of .NET file system classes and recursion. The following code snippet that I found on the web shows how it could work. Calling a function recursively to walk down the folder tree and modify folder and file names is in my opinion beautiful and scary. It requires your brain to at least think through the call stack with the eye in an eye. Not everybody has this gift. Besides recursion doesn't scale beyond the size of a thread's call stack.

   1: function Move-Stuff($folder)
   2: {
   3:     foreach($sub in [System.IO.Directory]::GetDirectories($folder))
   4:       {
   5:         Move-Stuff $sub
   6:     }
   7:     $new = $folder.Replace("wackytacky", "rollypolly")
   8:     if(!(Test-Path($new)))
   9:     {
  10:         new-item -path $new -type directory
  11:     }
  12:     foreach($file in [System.IO.Directory]::GetFiles($folder))
  13:     {
  14:         $new = $file.Replace("wackytacky", "rollypolly")
  15:         move-item $file $new
  16:     }
  17: }
  18:  
  19: Move-Stuff "$Home\Desktop\Workbench"
  20:  
  21: #This function leaves the old folder structure

Get-ChildItems and hash tables

Using Get-ChildItems on the other side walks through the folder tree and returns a list of file system objects. I am not sure whether it does it recursively or not, but at least I don't have to get my mind tangled up by thinking about it. This simple PowerShell Cmdlet "Get-ChildItems -recurse" does it for me. The task of renaming the tree is done by first getting a list of file system objects, then creating a hash table for moving files, creating the new folder branches using the New-Item Cmdlet and finally filling a hash table for deleting the old folder branches after the file move operations. After analyzing the file system object list that Get-ChildItems returned, the script takes care of the remaining tasks in batches. First it moves all the files, then it deletes all folders that are not longer needed.

   1: cd $home\desktop
   2: Set-PSDebug -Strict
   3:  
   4: cls
   5:  
   6: $ds = $Null
   7: $ds = Get-ChildItem "Workbench" -Recurse
   8:  
   9: $FolderDeleteList = @{}
  10: $FileMoveList = @{}
  11:  
  12: #Create new folders
  13: $ds | ForEach-Object `
  14: {     
  15:     if($_ -is [System.IO.FileInfo])
  16:     {
  17:         "`"$($_.Name)`" is a File"
  18:         $NewPath = $_.FullName.Replace("wackytacky", "simplepimple")
  19:         $FileMoveList[$_.FullName] = $NewPath
  20:         
  21:     }
  22:     if($_ -is [System.IO.DirectoryInfo])
  23:     {
  24:         "`"$($_.Name)`" is a Directory"
  25:         $NewPath  = $_.FullName.Replace("wackytacky", "simplepimple")
  26:         if (!$(Test-Path $NewPath))
  27:         {
  28:             New-Item -Path $NewPath -type Directory
  29:             $Level = $_.FullName.split("\").Count
  30:             $FolderDeleteList[$_.FullName] = $Level
  31:         }
  32:     }
  33: }
  34:  
  35: "Folders to delete ====================================="
  36: $FolderDeleteList
  37: "Files to move ========================================="
  38: $FileMoveList
  39:  
  40: #Move Files
  41: $FileMoveList.GetEnumerator() `
  42:     | ForEach-Object { Move-Item -Path $_.Key -Destination $_.Value }
  43:     
  44: #Delete Folders
  45: $FolderDeleteList.GetEnumerator() `
  46:     | Sort Value -Descending `
  47:     | Foreach-Object {"Deleting folder: `"$($_.Key)`""; 
  48:       Remove-Item -Path $_.Key -Recurse}

Download

The script files and a sample file system tree branch can be downloaded here: RenameFileSystemBranch.zip

Ausblick

The beauty of the PowerShell architecture is that this script can be used, with tiny adjustments, for any PowerShell Navigation Cmdlet Provider, like the Registry or Certification Provider. This type of command would be a very nice enhancement to the standard set of item cmdlets that ships with PowerShell. Curious for what "elaborate" script I am going to use this procedure? Stay tuned! I just say D I U G.

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags: , , , ,

.NET Framework | Photoshop | PowerShell

Powered by BlogEngine.NET 1.3.0.0
Vanilla Theme by Klaus Graefensteiner

About Klaus Graefensteiner

GRAVATAR icon of Klaus Graefensteiner I enjoy the programming of machines.

E-mail me Send mail
Blogroll as OPML OPML LinkedIn Profile View Klaus Graefensteiner's LinkedIn profile

Calendar

<<  September 2008  >>
MoTuWeThFrSaSu
25262728293031
1234567
891011121314
15161718192021
22232425262728
293012345

View posts in large calendar

Recent comments

Disclaimer

The opinions expressed herein are my own personal opinions and do not represent my employer's view in anyway.

© Copyright 2008

Sign in