get-tfs.ps1 – example of adding properties to make interactive life easier


One of the things I noticed while working inside PowerShell was wanting to make a quick TFS object model (OM) call (for instance, to VersionControlServer) and slice/data/inspect the results.  The OM calls to get an instance of TeamFoundationServer aren’t bad (first load the assembly, then just call the ctor or use the factory class), and getting the VersionControlServer from there isn’t bad (load the assembly, then GetService the type), but they weren’t “very” scripting-friendly, so here’s a simple wrapper for them.

Currently it just adds 4 properties to the TeamFoundationServer instance, for a little easier access to the particular interfaces I find myself using the most.  Of course, you can add/remove entries from these (or just not add them at all, of course).  For each of them, it generates the script block to execute for that property, then uses add-member to attach it.  Of course, we’re not really changing the TeamFoundationServer type on the fly, but the PsObject mechanics make it look like that, which is really slick and useful :)


With this script, I can fetch an instance with “$tfs = get-tfs http://tkbgitvstfat01:8080” (substitute your server name or URL, of course) and then make OM calls easily.  Since we’re in PowerShell, I can take the output of these calls and do lots of fun filtering and inspection.  Here are a few simple examples – hopefully it’s clear that this is far easier than having to call tf.exe and do the cut/awk/sed/grep/findstr kinds of work you normally would deal with in a cmd/bash/whatever world.


Note that the actual useful functionality (Version Control, Work Item Tracking, etc.) was always there, of course, the only real thing this script does it make it a little easier to get at it.  Also, there are far more useful services offered by TeamFoundationServer than just these 4, but I wanted to keep the example simple, but still useful.


Use VersionControlServer (VCS) to find the top-level folder with the longest name




C:\> $tfs.vcs.GetItems(‘$/*’).Items | sort -desc { $_.serveritem.length } | select -first 1 | fl serveritem,checkindate,changesetid

ServerItem : $/Developer Division Product Scope
CheckinDate : 5/30/2006 1:08:36 PM
ChangesetId : 74756

Use CommonStructureService (CSS) to show all the team projects that have ‘VSTS’ in the name



C:\> $tfs.css.listallprojects() | ?{ $_.Name -match ‘VSTS’ } | fl

Uri : vstfs:///Classification/TeamProject/180e1e5d-bbe8-418a-b9a4-152026964fb4
Name : VSTS V2 Plans
Status : WellFormed

Uri : vstfs:///Classification/TeamProject/365f4f53-9e05-4ded-9c21-52e9d9de978a
Name : VSTS Architecture Group
Status : Deleting

Uri : vstfs:///Classification/TeamProject/7c0d0a50-e31a-4bed-8e48-a99bc95def95
Name : VSTS Dogfood
Status : WellFormed

Uri : vstfs:///Classification/TeamProject/76a10abd-b3be-4803-9efc-d2a9d219885a
Name : VSTS Community
Status : WellFormed

Use WIT to check out the links from a work item and who created it when


C:\> $tfs.wit.getworkitem(99000) | fl links,CreatedBy,CreatedDate


Links : {100701, 99473, 95514}
CreatedBy : Doug Mortensen
CreatedDate : 5/22/2006 7:26:09 PM

Use GSS to look up my display name and email address

C:\> $tfs.gss.ReadIdentity(‘accountname’, ‘NORTHAMERICA\jmanning’, ‘none’) | fl displayname,mailaddress

DisplayName : James Manning
MailAddress : james.manning@microsoft.com

Use GSS to count the number of direct members in a security group

C:\> $tfs.gss.ReadIdentity(‘accountname’, ‘REDMOND\burtonall’, ‘direct’).members.count
6


 

param(
[string] $serverName = $(throw ‘serverName is required’)
)

begin
{
# load the required dll
[void][System.Reflection.Assembly]::LoadWithPartialName(“Microsoft.TeamFoundation.Client”)

$propertiesToAdd = (
(‘VCS’, ‘Microsoft.TeamFoundation.VersionControl.Client’, ‘Microsoft.TeamFoundation.VersionControl.Client.VersionControlServer’),
(‘WIT’, ‘Microsoft.TeamFoundation.WorkItemTracking.Client’, ‘Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItemStore’),
(‘CSS’, ‘Microsoft.TeamFoundation’, ‘Microsoft.TeamFoundation.Server.ICommonStructureService’),
(‘GSS’, ‘Microsoft.TeamFoundation’, ‘Microsoft.TeamFoundation.Server.IGroupSecurityService’)
)
}

process
{
# fetch the TFS instance, but add some useful properties to make life easier
# Make sure to “promote” it to a psobject now to make later modification easier
[psobject] $tfs = [Microsoft.TeamFoundation.Client.TeamFoundationServerFactory]::GetServer($serverName)
foreach ($entry in $propertiesToAdd) {
$scriptBlock = ‘
[System.Reflection.Assembly]::LoadWithPartialName(“{0}”) > $null
$this.GetService([{1}])
‘ -f $entry[1],$entry[2]
$tfs | add-member scriptproperty $entry[0] $ExecutionContext.InvokeCommand.NewScriptBlock($scriptBlock)
}
return $tfs
}

get-tfs.ps1


Comments (9)

  1. GrantH says:

    Great stuff James!

    Very useful.

  2. Along with easier TeamFoundationServer access, one of the things I found myself wanting was easier access…

  3. Did a little script this week that updates one work item (the "feature") based on summing values in other

  4. I was trying to modify a work item today and put in, apparently, too much text into a field I really

  5. [note: all my scripts are now zip’d up together on this page ] This particular script probably isn’t

  6. One thing that’s missing from PowerShell is the ability to import foreign namespaces into the current

  7. Geek Noise says:

    Fun with PowerShell and TFS Work Items