a·gen·tic a·gil·i·ty

Writing .NET in PowerShell and creating TFS Teams

Learn how to use PowerShell to access .NET objects and automate creating Teams in TFS, including referencing assemblies, handling dialogs, and error management.

Published on
4 minute read
Image
https://nkdagility.com/resources/52GnS0fI67Q
Subscribe

Did you know that you could be writing .NET in PowerShell? PowerShell can be used to instanciate and call any .NET object and that includes the TFS API.

On of my colleagues today suggested that it was harder to create a new Team programmatically in PowerShell than it would in c#. Well I have been playing with PowerShell a lot recently and I decided to give it a go… And do you know what… it is harder… that is.. until you know how.

I have been confused by PowerShell for a while now. I have struggled and struggled to create and run PowerShell until just a few days ago I had an epiphany:

PowerShell is just c# with all of the bad bits taken out. No case sensitivity, no pointless semi-colon at the end of lines and no unnecessary parentheses to tell the compiler something that it should already know.
-Martin Hinshelwood, 2013

Now I am not all there with the syntax and there are a bunch of things I think are really silly and hard, but if you squint at PowerShell just right it is really just the syntax of c# with all of the good bits of VB rolled into a nice code pie.

The first thing that In need to do to create a Team in TFS is to get a hold of a collection object and this resulted in my first problem…

1TfsTeamProjectCollectionFactory.GetTeamProjectCollection(new Uri(CollectionUri));

Not only does the code above (c#) have a static method call, but the object that is called has been shortened by using an Include in the c# code. So how do we both reference an object and ask PowerShell to do something with it.

1[Microsoft.TeamFoundation.Client.TfsTeamProjectCollectionFactory]::GetTeamProjectCollection($CollectionUrlParam)

Interesting… so we just bracket the object and do the old double colon to get that effect. Not what I thought but I have seen this before (not sure where) and I can work with that… so is that the same for an enum?

1[Microsoft.TeamFoundation.Client.TeamProjectPickerMode]::NoProject

So it is…

And thus we hit the second problem that I alluded to earlier… how do we import a namespace to gain access to the classes. We need to reference the DLL in a project so there must be some way to do that here. A little searching around and you will find the Add-Type command that will add any assembly as a reference.

1Add-Type -AssemblyName "Microsoft.TeamFoundation.Client, Version=11.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a",
2                       "Microsoft.TeamFoundation.Common, Version=11.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a",
3                       "Microsoft.TeamFoundation, Version=11.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"

So now we can add assemblies we can do pretty much whatever we like. PowerShell is a little more flexible than .NET directly sometime as you can just quote a type and it will get converted for you. This was especially painful in c#…

So… my final script to add a new Team to TFS looked something like.

 1 Param(
 2       [string] $CollectionUrlParam = $(Read-Host -prompt "Collection"),
 3       [string] $TeamName = $(Read-Host -prompt "Team"),
 4       [string] $project = $(Read-Host -prompt "Project")
 5       )
 6
 7# load the required dlls
 8Add-Type -AssemblyName "Microsoft.TeamFoundation.Client, Version=11.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a",
 9                       "Microsoft.TeamFoundation.Common, Version=11.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a",
10                       "Microsoft.TeamFoundation, Version=11.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
11
12# Get TFS
13$tfs = [Microsoft.TeamFoundation.Client.TfsTeamProjectCollectionFactory]::GetTeamProjectCollection($CollectionUrlParam)
14$tfs.EnsureAuthenticated()
15# Get Team Project
16$cssService = $tfs.GetService("Microsoft.TeamFoundation.Server.ICommonStructureService3")
17$teamProject += $cssService.GetProjectFromName($project)
18# Create Team
19$teamService = $tfs.GetService("Microsoft.TeamFoundation.Client.TfsTeamService")
20$Team = $teamService.CreateTeam($teamProject.Uri, $TeamName, "", $null)
21# Show what we created
22$team

But wait… you must be thinking ‘well what about the other programming constructs’? What I have done able is all fairly simple what if I want to go ahead and call the TFS built in project picker so that I don’t have to do all that variable nonsense. Now we are talking ‘if’ and dialogs…

1$picker = New-Object Microsoft.TeamFoundation.Client.TeamProjectPicker([Microsoft.TeamFoundation.Client.TeamProjectPickerMode]::NoProject, $false)
2$dialogResult = $picker.ShowDialog()
3if ($dialogResult -ne "OK")
4{
5    exit
6}
7$tfs = $picker.SelectedTeamProjectCollection
8$projectList = $picker.SelectedProjects

But what about if you make it mad? YOu can’t just throw a Try Catch in there we would have to do some crazy “On Error” and “GOTO” wouldn’t we?

1try
2{
3    $tfs.EnsureAuthenticated()
4}
5catch
6{
7    Write-Error "Error occurred trying to connect to project collection: $_ "
8    exit 1
9}

Now we begin to get a picture of what is possible inside PowerShell. Would the above be easier if  there were nice easy commands like “Add-Team” or “Add-TeamProject” existed? Well yes it would, but that they don’t is not going to cripple us. We can get buy without them..

In short, anything you can do in code you can do in PowerShell.

Software Development
Subscribe

Related blog

No related videos found.

Connect with Martin Hinshelwood

If you've made it this far, it's worth connecting with our principal consultant and coach, Martin Hinshelwood, for a 30-minute 'ask me anything' call.

Our Happy Clients​

We partner with businesses across diverse industries, including finance, insurance, healthcare, pharmaceuticals, technology, engineering, transportation, hospitality, entertainment, legal, government, and military sectors.​

Higher Education Statistics Agency Logo

Higher Education Statistics Agency

Qualco Logo

Qualco

Microsoft Logo

Microsoft

YearUp.org Logo

YearUp.org

Flowmaster (a Mentor Graphics Company) Logo

Flowmaster (a Mentor Graphics Company)

Boeing Logo

Boeing

SuperControl Logo

SuperControl

Milliman Logo

Milliman

Xceptor - Process and Data Automation Logo

Xceptor - Process and Data Automation

ALS Life Sciences Logo

ALS Life Sciences

Jack Links Logo

Jack Links

Illumina Logo

Illumina

Schlumberger Logo

Schlumberger

Bistech Logo

Bistech

Genus Breeding Ltd Logo

Genus Breeding Ltd

Ericson Logo

Ericson

Slaughter and May Logo

Slaughter and May

Teleplan Logo

Teleplan

Department of Work and Pensions (UK) Logo

Department of Work and Pensions (UK)

Nottingham County Council Logo

Nottingham County Council

Washington Department of Transport Logo

Washington Department of Transport

New Hampshire Supreme Court Logo

New Hampshire Supreme Court

Ghana Police Service Logo

Ghana Police Service

Washington Department of Enterprise Services Logo

Washington Department of Enterprise Services

ProgramUtvikling Logo

ProgramUtvikling

SuperControl Logo

SuperControl

Capita Secure Information Solutions Ltd Logo

Capita Secure Information Solutions Ltd

NIT A/S

MacDonald Humfrey (Automation) Ltd. Logo

MacDonald Humfrey (Automation) Ltd.

DFDS Logo

DFDS