Switching Visual Studio Environment Tools with Powershell and SlightlyPosher

 

Initially the SlightlyPosher environment configured the VS2008 tools as that was what I need on my project. Pascal was kind enough to send me a patch to use the VS2010 tools instead.

I thought it would be cool to satisfy both users, as not everyone has been lucky enough to switch to VS2010 yet.

In profile.ps1 by default the VS2010 tools are loaded.

Set-VsVars32 2010

image

If you would like to switch this, its as simple as calling:

Set-VsVars32 2008

Now you will have a VS2008 environment and MSBuild 3.5 at your fingertips.

image

The implementation for this is pretty straightforward…

#### Functions Used to Load VS Command Prompt #####
function Get-Batchfile ($file) {
    $cmd = "`"$file`" & set"
    cmd /c $cmd | Foreach-Object {
        $p, $v = $_.split('=')
        Set-Item -path env:$p -value $v
    }
}

function Set-VsVars32($vsYear)
{
   switch ($vsYear)
   {
        2008 {$vstools = $env:VS90COMNTOOLS}
        2010 {$vstools = $env:VS100COMNTOOLS }
   }

   $batchFile = [System.IO.Path]::Combine($vstools, "vsvars32.bat") 
   
   Get-Batchfile -file $batchFile
   
   Write-Host -ForegroundColor 'Yellow' "VsVars has been loaded from: $batchFile"
}

The Get-BatchFile function is provided by many blogs describing how to use the Visual Studio tools with PowerShell. The Set-VsVars32 method takes the year as an argument, and loads the tools for that Visual Studio year.

Run update.bat to get these latest changes. Enjoy!

Finding all projects containing a reference to X assembly using POSH

 

Finding all the projects which reference a specific assembly can be a little tough in visual studio if you have hundreds of projects. NDepend can do this for you, but that requires you’re willing to pay for a licence (you should) if you need it commercially.

I wrote a little bit of POSH to do this for me…

function Get-ContainsReferenceTo($projectFile, $referenceName)
{
    [xml]$s = get-content $projectFile

    $references = $s.Project.ItemGroup | Where-Object { $_.Reference -ne $null }
    
    foreach($reference in $references.ChildNodes)
    { 
        if($reference.Include -ne $null -and $reference.Include.StartsWith($referenceName))
        {
            return $true
        }
    }

    return $false
}

 

After loading the project file into an XmlDocument, we can iterate through each reference and do a string compare against the reference name.

Running this will return “True” or “False” as to whether the file contains the reference or not.

We can then do this for all project files in a directory by doing:

function Get-ProjectsContainingReferenceTo($directory, $referenceName)
{
    Get-ChildItem $directory -include *.csproj,*.vbproj -Recurse | foreach ($_) { 
        if(Get-ContainsReferenceTo $_.fullname $referenceName -eq $true){ $_.fullname }
    }
}

 

Now if any project files match the reference, the full path of the project file will be output to the command window. We can use this to perform batch operations to change references, remove them or anything else we would like.

I hope you find this useful and you can find it bundled with SlightlyPosher.

Using PowerShell to automate setting CopyLocal to false

 

It’s been stressed that CopyLocal is slow and evil, so I wanted to see what the impact was on our codebase.

First we need to load the project file and pull out the references sections.

[xml]$s = get-content $projectFile

$references = $s.Project.ItemGroup | Where-Object { $_.Reference -ne $null }
$projectReferences = $s.Project.ItemGroup | Where-Object { $_.ProjectReference -ne $null }

Next we can iterate through the child nodes, and if they are missing the Private tag, add it in.

foreach($reference in $references.ChildNodes)
{ 
    if($reference.Private -eq $null)
    {
        [System.Xml.XmlElement]$copyLocal = $s.CreateElement("Private", "http://schemas.microsoft.com/developer/msbuild/2003")
        $copyLocal.InnerText = "False"
        [Void]$reference.AppendChild($copyLocal) 
    }
}

We can do a similar thing with the project references if your solution builds into a single folder.

foreach($reference in $projectReferences.ChildNodes)
{ 
    if($reference.Private -eq $null)
    {
        [System.Xml.XmlElement]$copyLocal = $s.CreateElement("Private", "http://schemas.microsoft.com/developer/msbuild/2003")
        $copyLocal.InnerText = "False"
        [Void]$reference.AppendChild($copyLocal) 
    }
}

Then all we need to do is save the file and we are done!

$s.save($projectFile)

If you want to apply this too all the project files in a directory, recursively then you could do:

Get-ChildItem $directory -include *.csproj,*.vbproj -Recurse | foreach ($_) { 
    Set-CopyLocalFalse $_.fullname $true
}

You can find the source for this in the SlightlyPosher distribution, or look at the source for the file.

Preliminary tests on our build time dropped from 6:30 minutes to 3:48 minutes thanks to this!

SlightlyPosher: Console2 settings for PowerShell

 

Pascal has pointed out that out of the box, SlightlyPosher does not integrate Console2 with PowerShell. Oops.

I have committed the settings file for this, so if you run update.bat or download it you will get the changes.

If you would like to override the default configuration, you can do so with Console2.

  1. Right click on the console and go to settings.
  2. Click the Console tab.
  3. Check “Save settings to user directory”

Now when you customise your console, it will not be wiped out when you do an update.

Pascal also highlighted that if you are new to POSH, you might also want to set your environment to allow scripts to run without restriction.

Set-ExecutionPolicy Unrestricted

This should allow the modules to load and run correctly. I will look at adding this to the install.bat asking if new users would like this enabled to simplify the process.

Sorry about these omissions!

Newer Posts Older Posts