Recursively replacing a string in file and directory names and in text files on Windows - PowerShell to the rescue image 33

Recursively replacing a string in file and directory names and in text files on Windows – PowerShell to the rescue

A simple enough requirement: we want to create a template project, a set of directories and files that we can use as a starting point for a new type of project. The names of the directories and files and some of the template’s files’ contents contains placeholder names – say DomainX and ModuleY. When we start a new project based on the template, we want to copy the template project structure and very easily replace all placeholders in file names, directory name and in file contents. Simply put:

image

All occurrences of DomainX and ModuleY should be replaced with the actual Domain and Module names. This should be automated as much as possible – to reduce human effort and even more to reduce human error. It does not have to be extremely fast – we will do this only a few dozens times in total, over the course of many months. And – it has to be done on Windows. (well, at least that is where the directory structure will be used in the end; it could of course be extracted from a zip-file that is prepared on a different platform). We are looking for a very simple, lightweight, quick approach (a custom Maven archetype for example could have been a solution but is too heavy handed by far).

What I did not know: as of Windows 7, the Windows Powershell is included in every Windows distribution. And is therefore available to us. A little web searching  mainly StackOverflow – quickly resulted in a number of script suggestions. The ones I ended up with are:

This first statement to replace ModuleY with the real name of the module – here ModuleInventory – in all filenames and directory names:

Get-ChildItem -Filter “*ModuleY*” -Recurse | Rename-Item -NewName {$_.name -replace ‘ModuleY’ ,’ModuleInventory’ } (case insensitive)

and (case sensitive) using clike and creplace:

Get-ChildItem -r | Where {$_.name -clike “*ModuleY*”} | Rename-Item -NewName {$_.name -creplace ‘ModuleY’, ‘ModuleInventory’ }

Note: On Powershell V2 Windows 7 this will not work because you can’t rename a directory while you’re iterating through it. Upgrade to Powershell 4.0 following these instructions: http://mikefrobbins.com/2015/01/08/how-to-check-the-powershell-version-and-install-a-new-version/ (which requires Windows Management Framework according to these instructions https://www.microsoft.com/en-us/download/details.aspx?id=40855  and the .NET Framework 4.5 which I got from here: https://www.microsoft.com/en-us/download/details.aspx?id=30653 )

The second PowerShell script will also recursively search through all files (not directories this time) in the directory and subdirectories from where this script is run (Powershell V3 or up); it replaces all occurrences in files of string ModuleY with the string ModuleInventory:

Get-ChildItem  -Filter *.* -File -Recurse  | Foreach-Object {       

$c = ($_ | Get-Content)        

If ($c | Select-String -Pattern ‘ModuleY’) {

$c = $c -creplace ‘ModuleY’,’ModuleInventory’       

[IO.File]::WriteAllText($_.FullName, ($c -join “`r`n”)) }

}

or

Get-ChildItem  -Filter *.* -Recurse | where {-not $_.psiscontainer} | Foreach-Object {       
$c = ($_ | Get-Content)        
If ($c | Select-String -Pattern ‘ModuleY’) {
$c = $c -creplace ‘ModuleY’,’ModuleInventory’       
[IO.File]::WriteAllText($_.FullName, ($c -join “`r`n”)) }
}

on older versions of PowerShell (V2) that do not recognize the -File parameter. Note that Get-Content fails when performed on a directory.

The final result is:

image

All occurrences of ModuleX were replaced – in the names of the folders and the files and in the contents of the files.