Upgrading Visual Studio Solutions with PowerShell

by Matt Milner 9. April 2010 07:20

With the impending release of Visual Studio 2010, I find myself with large numbers of solutions that need be upgraded from VS 2008.  The thought of opening them all manually and running the upgrade wizard was daunting.  Then I considered that I would also need to change the target framework of the projects to .NET 4, and in some cases update the references (why the target framework change didn’t fix that I’m not sure).  So I did what any lazy programmer does, I wrote some code to do it for me. 

At first, I just wanted to upgrade all of my solutions, so I used some PowerShell to find all the solutions and invoke devenv.exe passing in the solution and the /upgrade switch.  This gets a little tricky, as passing command line parameters to executables in PowerShell always seems harder to me than it should be.  But I came up with this one line script that handles it nicely.  I get all the solution files, then do a for each.  The trick was to set variables for the parameters and then invoke it all at once with the variables.  I sleep after so that too many solutions aren’t open at once.  You can play with the sleep time for best results, or remove it if you don’t need it. (Note that I have a 64 bit installation of Windows, so the (x86) in the path)


gci * -include *.sln -recurse | foreach-object {$switchName= "/upgrade"; $slnPath = $_; & 'C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\devenv.exe' $slnPath $switchName; start-sleep -seconds 10}


That got all my solutions upgraded, but the target framework for each was still .NET 2 or .NET 3.5.  So I used a macro from The Visual Studio Blog to retarget all of my applications to .NET Framework 4.  To run the macro, I used a similar approach with PowerShell, but this time using the /command switch and the name of my macro. 

gci * -include *.sln -recurse | foreach-object {$sln = $_; $vs = "c:\program files (x86)\microsoft visual studio 10.0\common7\ide\devenv.exe"; $cmd = "/command"; $cmdparam = "`"Macros.MyMacros.ProjectManagement.SwitchFramework`""; & $vs $sln $cmd $cmdparam }


In this case, I had to wrap the command in quotes, so I used the PowerShell escape character (`). The gotcha with this command is that the IDE stays open after executing the macro.  If you have a lot of solutions, you can run out of resources on your system.  So you may want to break this up and only process a small set of solutions at once.

Finally, I found that when I tried to build my solutions, many of them were referencing the 3.0 version of System.ServiceModel and System.Runtime.Serialization.  I used another macro, and the same PowerShell command, to switch the references.  The macro I used is:


Sub SwapReferences()
        For Each project As EnvDTE.Project In DTE.Solution.Projects
            If project.Kind = PrjKind.prjKindCSharpProject OrElse project.Kind = PrjKind.prjKindVBProject Then
                Dim vp As VSProject = CType(project.Object, VSProject)
                Dim ref As VSLangProj.Reference = vp.References.Find("System.ServiceModel")
                If (Not ref Is Nothing) Then
                End If
                Dim dcref As VSLangProj.Reference = vp.References.Find("System.Runtime.Serialization")
                If (Not dcref Is Nothing) Then
                End If
            End If
    End Sub


Pretty simple and targeted, but it got the job done to replace the references I cared about. 

So, with a few macros, and a little PowerShell, I was able to convert over 30 solutions in a few minutes. 


General Musings