Thursday, October 9, 2008

Editing multiple VS2008 project files with PowerShell

I recently needed to change reference paths for multiple project files in a solution. In the past I had done this manually, which was inefficient and frustrating. It occurred to me that PowerShell would alleviate the tediousness of this task.

Did I mention that the project files were under TFS version control? I created the following helper function to check out the files. I didn't create a corresponding function to check in the files because I wanted to eyeball them before check-in.

function CheckOutTfsFile([string] $FilePath)
Write-Host("Attempting to check out " + $FilePath)
$tfsvc = Get-TFSVersionControl
$ws = $tfsvc.GetWorkspace((Get-Item $FilePath).DirectoryName)

So here's the actual code. I needed to alter part of the path to the 'Common' project in 30+ Visual Studio 2008 project files. Specifically, I needed to change every instance of 'Common\Main' to 'Common\Production\' to support a source code branch.

PS H:\> $projectLocation = "C:\Source\Project\Production\"
PS H:\> $files = get-childitem $projectLocation -include *.*proj -recurse |
Select-String -pattern "Common\Main" -SimpleMatch |
Select-Object -Property Path
PS H:\> $files | Foreach-Object { CheckOutTfsFile( $_.Path) }
PS H:\> $match = "Common\\Main"
PS H:\> $replacement = "Common\Production\"
PS H:\> $files | Foreach-Object
{ (Get-Content -Path $_.Path -encoding UTF8 )
-replace $match, $replacement
| Set-Content $_.Path -encoding UTF8 }

It worked out very well for me. All of the files were updated in a few seconds. I compared a few against their previous versions and it all looked good. Checked it into Team Foundation Version Control, started a manual CruiseControl build, and I was done.

There's definitely room for improvement in the name of reusability. I don't expect to have to do this too often, however, so I'm going to defer that for another day.