Kevin McMahon


Blog Search

Retargeting Visual Studio project files with PowerShell

I originally set out to write this post a little over a year ago. Back then I threw together a script to retarget all the project files from .Net 2.0 to .Net 3.5 for my previous company and recently I found myself having to a similar upgrade from .Net 3.5 to 4.0. I ended up using the same script again so I figured I’d go ahead and publish it.

The upgrade process done by Visual Studio on your current projects and solutions will only migrate the file format to the newest schema and will not retarget the framework to the latest version. That is where the script I’ve included below comes in. It will retarget all the C# project files found under the path provided to version 4.0 of the .Net framework.

C# project files are XML based and navigating the DOM with Linq to XML is a cinch but there are a couple small but important steps that the script needed to include. First, you need to append the namespace to the individual element names or else the elements will not be able to be found. Second, when saving the modified XDocument, a XmlWriterSetting instance needs to be instantiated and the OmitXmlDeclaration property set to true. Setting this property to true will make sure the XML that we save will be considered a valid project file by Visual Studio.

I’ve included the full script below as well as created a gist that can be found here. It is important to note that this script will edit all the csproj files found under the directory specified in the path variable. Make sure you backup these files or have them under source control prior to running the script. Enjoy.

UPDATE: Added change suggested in comments by Jeffery Snover

[Reflection.Assembly]::LoadWithPartialName("System.Xml.Linq") | Out-Null#specify the root of your source tree below$path = "C:\Code\chatsworth"$ns = ""$xname = [System.Xml.Linq.XName]::Get("PropertyGroup",$ns)$tfname = [System.Xml.Linq.XName]::Get("TargetFrameworkVersion",$ns)    $xws = New-Object System.Xml.XmlWriterSettings$xws.OmitXmlDeclaration = $true$xws.Indent = $truefunction updatefx($filename){    #Write-Host $filename $xml = [System.Xml.Linq.XDocument]::Load($filename) $result = $xml.Descendants($xname)        foreach ($i in $result)    {        $fxelem = $i.Element($tfname) if($fxelem)        {            $i.SetElementValue($tfname,"v4.0")        }    }    $xw = [System.Xml.XmlWriter]::Create($filename, $xws) $xml.Save($xw) $xw.Close()}$csprojs = Get-ChildItem $path *.csproj -Recurseforeach ($file in $csprojs){    updatefx $file.FullName}