Thursday, December 10, 2009

No Web Browser, Need PowerShell

I recently found myself on a Windows Server 2003 machine without a functioning web browser and PowerShell wasn’t installed either.

No problem, I just opened notepad and started typing:

echo class Program { public static void Main() { >"%~dpn0.cs"
echo using (var wc = new System.Net.WebClient()) { >>"%~dpn0.cs"
echo wc.DownloadFile(@"http://download.microsoft.com/download/1/1/7/117FB25C-BB2D-41E1-B01E-0FEB0BC72C30/WindowsServer2003-KB968930-x86-ENG.exe", @"%~dpn0.installer.exe");}}} >>"%~dpn0.cs"
"%systemroot%\microsoft.net\framework\v3.5\csc.exe" /out:"%~dpn0.exe" "%~dpn0.cs"
"%~dpn0.exe"
"%~dpn0.installer.exe"

Saved it as a command script and double-clicked it. PowerShell v2 installer downloads and runs, bam!

This would require tweaking for other processor architectures, other operating system versions, or older .NET installations.

 Tuesday, July 14, 2009

Generic batch file wrapper for PowerShell scripts

Integrating PowerShell scripts into older style processes that are only designed to call out to executables or batch files (or “command scripts” as they have been known since NT4) can be slightly messy primarily due to the argument parsing semantics around double-quotes and file paths with spaces. I often end up writing a simple command script to wrap each PowerShell script to simplify this but it is tedious and repetitive and I’ve finally decided to create a generic script that works for any PowerShell script.

Simply save the following code as a text file and save it with the same name as your PowerShell script but replace the .ps1 extension with a .cmd extension.

@echo off
setlocal
set tempscript=%temp%\%~n0.%random%.ps1
echo $ErrorActionPreference="Stop" >"%tempscript%"
echo ^& "%~dpn0.ps1" %* >>"%tempscript%"
powershell.exe -command "& \"%tempscript%\""
set errlvl=%ERRORLEVEL%
del "%tempscript%"
exit /b %errlvl%

Now if your script is called “Get-Something.ps1”, you can simply run it like this:

Get-Something “c:\some path\some.file” –SecondArg 3.14
 Wednesday, May 20, 2009

PowerShell for Developers

Several weeks ago Richard Banks (@rbanks54) coerced me to find time to present to the Australian Virtual Alt.NET User Group between moving house and deploying a new website to production for my current client.

I agreed and with an absurdly short amount of preparation presented to a small group online using Microsoft Live Meeting and a shared PowerShell console window. You can watch the presentation on the Oz Alt.NET Community Blog.

The “slides” and example scripts can be downloaded here.

 Sunday, March 01, 2009

Code Coverage Delta with Team System and PowerShell

My last post documented my first venture into working with Visual Studio's Code Analysis output with PowerShell to find classes that need more testing. Since then I've taken the idea further to analyse how coverage has changed over a series of builds from TFS.

What resulted is a PowerShell script that takes, as a minimum, the name of a TFS Project and the name of a Build Definition within that project. The script will then, by default, locate the two most recent successful builds, grab the code coverage data from the test runs of each of those builds and output a list of classes whose coverage has changed between those builds, citing the change in the number of blocks not covered.

Additional parameters to the script allow partially successful or failed builds to be considered and also to analyse coverage change over a span of several builds rather just two consecutive builds.

The primary motivator behind developing this script was to be able to identify more accurately where coverage was lost when a new build has an overall coverage percentage lower than the last. This then helps to locate, among other things, where new code has been added without testing or where existing tests have been deleted or disabled.

A code base with a strong commitment to the Single Responsibility Principle should find class-level granularity sufficient but extending the script to support method-level reporting should be trivial given that the Coverage Analysis DataSet already includes all the required information.

The script requires the Team Foundation Server PowerShell Snapin from the TFS October 2008 Power Tools and the Visual Studio Coverage Analysis assemblies presumably available in Visual Studio 2008 Professional or higher. These dependencies only support 32-bit PowerShell so my script unfortunately suffers the same constraint.

Download the script here, and use it something like this:

PS C:\TfsWorkspace\> C:\Scripts\Compare-TfsBuildCoverage.ps1 -project Foo -build FooBuild | sort DeltaBlocksNotCovered

 Friday, February 13, 2009

Analyse Code Coverage with PowerShell

Visual Studio 2008 Team System's built-in Code Coverage is nice but the standard results window only allows you to drill down through each assembly, then namespace, class, and finally method. You can't easily find the class with the least blocks covered, something I needed to do the other day.

I found John Cunningham's blog about "off-road" code coverage and was pleased to see that Microsoft had provided an assembly in Visual Studio that can be used to parse the *.coverage file output by a test run. I followed his example to write a PowerShell script to provide basic access to the data.

You can download my script here.

Then you can use it like this:

$CoverageDS = ./Get-CodeCoverageDataSet.ps1 "data.coverage"
$CoverageDS.Class `
  | Sort-Object -Property BlocksNotCovered -Descending `
  | Select-Object `
    -First 25 `
    -Property `
      BlocksNotCovered, `
      @{ 
        Name = "Namespace"; 
        Expression = { 
          $CoverageDS.NamespaceTable.FindByNamespaceKeyName($_.NamespaceKeyName).NamespaceName
        }
      }, `
      ClassName

The coverage file is typically found in the TestResults\[TestRunName]\In\[ComputerName]\ folder. You can easily perform queries over methods or lines rather than classes by using the other tables in the returned dataset. You can also use the ConvertTo-Html cmdlet to easily create a report for your team.

 Tuesday, February 10, 2009

Is -ism me?

In a sad attempt to get blogging again, I am going to start by responding to this blatant prod. I agree with some of Jim's answers but to keep it interesting I've selected a disjoint set and knocked it up a notch.

I am:

Pragmatic about dogmatism.

Practicing consumerism.

Prone to defeatism.

Parodying athleticism.

Proof of determinism.

To keep it going, the same rule applies: if you've read this then follow suit blogging your own answers, even if you are busy writing your own blog engine.

 Tuesday, October 21, 2008

Adelaide Geek Dinner Handover

As I have recently accepted a new job interstate, I will no longer be organising dinners for fellow developers in Adelaide. However, rather than allow such a fun event to disappear, I am passing the awesome responsibility of organising the dinners to my friend and colleague, Jim Burger, whom many of you have met on previous occasions.

I will be giving Jim a hard time to make sure he continues to arrange a dinner at least once each quarter and I believe it will also help to ensure he remembers to attend them himself ;). Names and contact details of previous attendees and people who have registered their interest will be given to Jim so he can send you the next invite but let him or I know if you'd rather be removed from the list.

If you've never been invited to an Adelaide Geek Dinner before but want to be on the list, just contact Jim or I and you'll surely be invited to the next one.

 Tuesday, October 14, 2008

Strongly Typed Windows Forms Data Binding

I was recently inspired by a question about property names in strings on Stack Overflow. The problem is that Windows Forms data binding takes the names of properties to bind as string parameters and if these properties change or are removed, errors won't surface until the bound control is exercised at run-time. So, using Paul's strongly typed property name ideas, I propose this alternative syntax for programmatic data binding in Windows Forms:

nameTextBox.Bind(t => t.Text, aBindingSource, (Customer c) => c.FirstName);
// Binds the Text property on nameTextBox to the FirstName property
// of the current Customer in aBindingSource, no string literals required.

And the following code to implement support for it:

public static class ControlExtensions
{
    public static Binding Bind<TControl, TDataSourceItem>(this TControl control, Expression<Func<TControl, object>> controlProperty, object dataSource, Expression<Func<TDataSourceItem, object>> dataSourceProperty) where TControl: Control
    {
        return control.DataBindings.Add(PropertyName.For(controlProperty), dataSource, PropertyName.For(dataSourceProperty));
    }
}

public static class PropertyName
{
    public static string For<T>(Expression<Func<T, object>> property)
    {
        var member = property.Body as MemberExpression;
        if (null == member)
        {
            var unary = property.Body as UnaryExpression;
            if (null != unary) member = unary.Operand as MemberExpression;
        }
        return null != member ? member.Member.Name : string.Empty;
    }
}

Thoughts? Overkill?