Rants, rambles, news and notes from another geek

Fun With PowerShell and TFS Work Items

It all started with me wanting a better burndown chart for my team. That was relatively simple to solve as we’ve got some pretty good ones floating around inside Microsoft. (Apologies in advance but I can’t share my spreadsheet with you at this time.)

Then came the fun… I wanted to be able to pull any given day’s “work done” and “work remaining” data. But for my own reasons, I don’t want this spreadsheet bound to the OLAP cube, I want to be able to mess with it.

Being the PowerShell junkie that I am I was pretty sure I could do this. I found James Manning’s killer “get-tfs.ps1” script which meant I didn’t have to work out that bit myself.

Using it is simple:

   1: $tfs = get-tfs http://mytfs:8080

   2: $wi = $tfs.wit.GetWorkItem(12345)

As you can see, I get the TFS client object via James’s script, and then I pull a WorkItem from it. From there I can ask the $wi object for all the bits of information in the work item. Piping it to get-member showed me the following methods and properties:


   2:    TypeName: Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItem


   4: Name                   MemberType            Definition                                                                

   5: ----                   ----------            ----------                                                                

   6: FieldChanged           Event                 Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItemFieldChangeEve...

   7: Copy                   Method                Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItem Copy(Microsof...

   8: Equals                 Method                bool Equals(System.Object obj)                                            

   9: GetHashCode            Method                int GetHashCode()                                                         

  10: GetNextState           Method                string GetNextState(string action)                                        

  11: GetType                Method                type GetType()                                                            

  12: IsValid                Method                bool IsValid()                                                            

  13: MergeToLatest          Method                System.Void MergeToLatest()                                               

  14: Open                   Method                System.Void Open()                                                        

  15: PartialOpen            Method                System.Void PartialOpen()                                                 

  16: Reset                  Method                System.Void Reset()                                                       

  17: Save                   Method                System.Void Save()                                                        

  18: SyncToLatest           Method                System.Void SyncToLatest()                                                

  19: ToString               Method                string ToString()                                                         

  20: Validate               Method                System.Collections.ArrayList Validate()                                   

  21: Item                   ParameterizedProperty System.Object Item(string name) {get;set;}, System.Object Item(Microsof...

  22: AreaId                 Property              System.Int32 AreaId {get;set;}                                            

  23: AreaPath               Property              System.String AreaPath {get;set;}                                         

  24: AttachedFileCount      Property              System.Int32 AttachedFileCount {get;}                                     

  25: Attachments            Property              Microsoft.TeamFoundation.WorkItemTracking.Client.AttachmentCollection A...

  26: ChangedBy              Property              System.String ChangedBy {get;}                                            

  27: ChangedDate            Property              System.DateTime ChangedDate {get;}                                        

  28: CreatedBy              Property              System.String CreatedBy {get;}                                            

  29: CreatedDate            Property              System.DateTime CreatedDate {get;}                                        

  30: Description            Property              System.String Description {get;set;}                                      

  31: DisplayForm            Property              System.String DisplayForm {get;}                                          

  32: ExternalLinkCount      Property              System.Int32 ExternalLinkCount {get;}                                     

  33: Fields                 Property              Microsoft.TeamFoundation.WorkItemTracking.Client.FieldCollection Fields...

  34: History                Property              System.String History {get;set;}                                          

  35: HyperLinkCount         Property              System.Int32 HyperLinkCount {get;}                                        

  36: Id                     Property              System.Int32 Id {get;}                                                    

  37: IsDirty                Property              System.Boolean IsDirty {get;}                                             

  38: IsNew                  Property              System.Boolean IsNew {get;}                                               

  39: IsOpen                 Property              System.Boolean IsOpen {get;}                                              

  40: IsPartialOpen          Property              System.Boolean IsPartialOpen {get;}                                       

  41: IsReadOnly             Property              System.Boolean IsReadOnly {get;}                                          

  42: IsReadOnlyOpen         Property              System.Boolean IsReadOnlyOpen {get;}                                      

  43: IterationId            Property              System.Int32 IterationId {get;set;}                                       

  44: IterationPath          Property              System.String IterationPath {get;set;}                                    

  45: Links                  Property              Microsoft.TeamFoundation.WorkItemTracking.Client.LinkCollection Links {...

  46: NodeName               Property              System.String NodeName {get;}                                             

  47: Project                Property              Microsoft.TeamFoundation.WorkItemTracking.Client.Project Project {get;}   

  48: Reason                 Property              System.String Reason {get;set;}                                           

  49: RelatedLinkCount       Property              System.Int32 RelatedLinkCount {get;}                                      

  50: Rev                    Property              System.Int32 Rev {get;}                                                   

  51: RevisedDate            Property              System.DateTime RevisedDate {get;}                                        

  52: Revision               Property              System.Int32 Revision {get;}                                              

  53: Revisions              Property              Microsoft.TeamFoundation.WorkItemTracking.Client.RevisionCollection Rev...

  54: State                  Property              System.String State {get;set;}                                            

  55: Store                  Property              Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItemStore Store {g...

  56: TemporaryId            Property              System.Int32 TemporaryId {get;}                                           

  57: Title                  Property              System.String Title {get;set;}                                            

  58: Type                   Property              Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItemType Type {get;} 

  59: Uri                    Property              System.Uri Uri {get;}                                                     

  60: WorkItemLinkHistory    Property              Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItemLinkCollection...

  61: WorkItemLinks          Property              Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItemLinkCollection...

  62: GetCompletedWorkByDate ScriptMethod          System.Object GetCompletedWorkByDate();                                   

  63: GetRemainingWorkByDate ScriptMethod          System.Object GetRemainingWorkByDate();                                   

Lots of great stuff there, but what I really wanted was the work done on any given day and not the current work remaining. Hmmm…

After digging around in the object model (with PowerShell of course), I found the answer. The Revisions collection contains the full history of the Work Item. If I enumerated that, looking at the dates, I should be able to get what I want.

A little while later I had it all worked out, setup as a type extension in PowerShell so it automatically works with every WorkItem type I get. Type extensions are added via a special XML file (more info). Here’s what I added to mine:

   1: <Type>

   2:     <Name>Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItem</Name>

   3:     <Members>

   4:         <ScriptMethod>

   5:             <Name>GetCompletedWorkByDate</Name>

   6:             <Script>


   2:                 $date = [datetime] $args[0]

   3:                 $total = 0

   4:                 $this.Revisions | % {

   5:                     if ($_.Fields['Changed Date'].Value.Date -eq $date) {

   6:                         $work = $_.Fields["Completed Work"]

   7:                         if ($work -ne $null) { $total += ([int] $work.Value) - ([int] $work.OriginalValue) }

   8:                     }

   9:                 }

  10:                 return $total



   7:         </ScriptMethod>

   8:         <ScriptMethod>

   9:             <Name>GetRemainingWorkByDate</Name>

  10:             <Script>


   2:                 $date = [datetime] $args[0]

   3:                 $total = 0

   4:                 $this.Revisions | % {

   5:                     if ($_.Fields['Changed Date'].Value.Date -le $date) {

   6:                         $work = $_.Fields["Remaining Work"]

   7:                         if ($work -ne $null) {

   8:                             $total = ([int] $work.Value)

   9:                         }

  10:                     }

  11:                 }

  12:                 return $total



  11:         </ScriptMethod>

  12:     </Members>

  13: </Type>

What this does is add two new methods to the .NET type Microsoft.TeamFoundation.WorkItemTracking.Client.Workitem. The first method takes a date and returns the sum of the “Completed Work” field for all revisions that occurred on that date. The second method enumerates the same Revisions collection, but this time it process all revisions up through the given date looking for the last one that says anything about the “Remaining Work” field.

Next step… create a script to wrap all this up into an easy to use command I call get-burndowndata.ps1:

   1: param( 

   2:         $deliverable = $(throw "Must provide deliverable ID"),

   3:         $date = [datetime]::Now.Date 

   4: )


   6: $tfs = get-tfs [http://mytfs:8080](http://mytfs:8080)

   7: $deliverable = $tfs.WIT.GetWorkItem($deliverable) 


   9: $result = @()


  11: $deliverable.WorkItemLinks | ? { $_.LinkType.Name -eq "Child" } | % {

  12:     $feature = $tfs.WIT.GetWorkItem($_.TargetId)


  14:     $feature.WorkItemLinks | ? { $_.LinkType.Name -eq "Child" } | % {

  15:         $task = $tfs.WIT.GetWorkItem($_.TargetId)

  16:         $completed = $task.GetCompletedWorkByDate($date)

  17:         $remaining = $task.GetRemainingWorkByDate($date)


  19:         $obj = "" | select-object ID, Title, Completed, Remaining 

  20:         $obj.ID = $task.ID

  21:         $obj.Title = $task.Title

  22:         $obj.Completed = $completed

  23:         $obj.Remaining = $remaining


  25:         $result += $obj

  26:     }

  27: }


  29: $result

Now, getting any given day’s burndown information is as simple as calling that script and opening the result in Excel:

   1: get-burndowndata.ps1 12345 "4/1/2009" | export-csv data_20090401.csv

   2: invoke-item data_20090401.csv

Works like a charm!

**Disclaimer: **The get-burndowndata.ps1 script makes lots of assumptions about your TFS Work Item struction and relationships . It probably won’t work unmodified for anyone outside of DevDiv.

Enterprise Library v5.0 Planning Has Begun!

PAG_Logo_NoText Way back in 2004, sitting in the “delta lounge” team room with Scott, Brian, Ed, T-Shak, Rohit, Prashant and Mani, I never would have believed that almost 5 years later, we’d still be shipping Enterprise Library (aka EntLib) or that we’d be up to version 5.0.

A few days ago, my good friend Grigori Melnik, who is the PM for EntLib over in Patterns & Practices, sent me an email reminding me that they are looking for planning input on the version 5.0 features.

He’s written it all up over on his blog:

If you are a current or past EntLib user, please don’t miss this opportunity to help steer the product. As I tell my wife, “If you don’t tell me what you want, you shouldn’t expect me to get you the right thing.”

Rules of the Road

I was digging through my OneNote today, organizing stuff and reading old notes and whatnot, when I found a page I wrote on 7/13/2006. I don’t know why I wrote it in OneNote, but it is something I’ve talked about to my direct reports, colleagues and others for a long time.

It was simply titled “Rules of the Road” and had the following content:

  1. Don’t stress out about things you can’t control - ignore them
  2. Don’t stress out about things you can control - fix them
  3. Confront someone as soon as you recognize the problem - don’t let it fester!
  4. Help people who sincerely ask for help
  5. Fight for what you believe in
  6. Admit when you are wrong
  7. Reserve the right to change your mind
  8. You do not have to justify saying no to someone

My dad taught my 1-3 when I was growing up. He had ulcer issues as a younger man because he let stress build up too much. Those rules help you get grounded when you feel stressed and show you simple ways out, even when, as in Rule #1, the out is to ignore the issue.

Numbers 4-7 are extensions I’ve added over time to help me guide my life. Help your friends. Fight for what you believe in. Admit when you make a mistake. Do not be afraid to change your mind. Don’t let other people convince you that “flip flopping” in the presence of new information is somehow bad. When you know better, do better.

The final one is the newest addition to the list. Sometimes many people, when presented with a request they has to say no to, will seek a rationalization or a story that they can use to justify saying no. Here’s the thing… you don’t have to justify saying No. You shouldn’t be rude, you should be always polite and respectful, but you can just say, “No, I’m sorry but I can’t,” and leave it at that.

Layer Validation With the VSTS 2010 CTP

VSTS Logo Cameron Skinner has recently made two excellent blog posts that give a great explanation of how to use Layer Diagrams for architecture and design validation in your code. He shows you the basics of creating a layer diagram and binding it to your solution elements. He then shows you how to incorporate that validation right into your build!

Excellent stuff you should certainly go read.

(For all this stuff, you will need to be running the VSTS 2010 CTP.)

Code Generation Made Easy

Visual Studio Logo The Text Template Transformation Toolkit, aka T4 Templates, is getting some press recently. T4 is a code generation and templating system that is built into VS, but not enough people know about it.

In P&P, we used it for almost all of our code generation in our Software Factories, and it will be an important part of how we do code-gen in Visual Studio Team System Architecture Edition.

This recent article in the Redmond Developer News prompted me to blog this, and it is a nice overview of what T4 is all about with quotes from many of the key people involved in the development of the toolkit.

Here are some more recent posts about T4:


Visual Studio Team System 2008 Database Edition GDR - RTM

In case you missed it yesterday, the Visual Studio Team System 2008 Database Edition GDR shipped yesterday!

Here’s a snippet from Gert Drapers’ announcement post on his Data Dude blog:

Although the name “GDR”, which stands for “General Redistribution Release”, implies otherwise, this really is a complete new release, based on a new architecture. We have taken the architectural changes from the Rosario project (Visual Studio Team System 2010) and rolled them forward in time. Rolling forward these changes help us align the GDR release with the upcoming Visual Studio Team System 2010 release and provide numerous new features and extensibility points in this release. If you would compare the GDR release with the “Visual Studio 2005 Team Edition for Database Professionals” or “Visual Studio Team System 2008 Database Edition” you will agree this is a completely new product!

The key architectural changes

  • Model based architecture - Everything underneath the covers is based on a true model representation of the SQL Server schema. This facilitates a true offline declarative database development system where the source code defines the shapes of the schema objects.
  • Models are implemented by Database Schema Providers, DSP’s for short. - The introduction of a provider model enables multiple things at once. First of all the decoupling of release vehicles. For example when SQL Server will release a new version or adds new functionality in a service pack, like they did in SQL Server 2005 SP2 when adding “vardecimal” support, we can simply update an existing provider or provide a new one in case of a new SQL Server release. Overtime we will go to a model where the SQL Server providers will be an integral part of the SQL Server release. The provider model is also a key extensibility point, allowing 3rd parties to extend database project ecosystem and add support for other database platforms in Visual Studio Team System 2010.
  • Tool extensibility - In this release external tool writers have full access to the T-SQL parsers (for SQL Server 2000, 2005 and 2008), the SQL Script DOM and the schema model (when inside Visual Studio). This adds on top of the ability to write extend the tools inside the platform. You can extend T-SQL refactoring by writing your own refactoring types (operations) and refactoring targets; add T-SQL Static Code Analysis rules, data generators, data distributions and test conditions. Database Projects (.dbproj) now provide a truly extensible declarative database development platform.
  • Separation of BUILD and DEPLOY. - The separation of build & deploy makes it possible to deploy the output of your database project to many different targets and different points in time. Build now produces a single artifact file hat describes the schema inside your database, called a .DBSCHEMA file. This file is used by the deployment engine to deploy your schema.
  • Standalone Deployment Engine. - The inclusion of a standalone and redistributable deployment engine makes it possible to deploy the output of your database projects (.DBSCHEMA files) to a target database without the need of having Visual Studio Team System Database Edition installed. This enables key scenarios like the inclusion of database schema deployment as part of your application installation.

All these architectural changes enable many new usage scenarios and interesting new features.

Many, many congrats to the team!

Hyper-V Management Console on Vista X64

logo-ms-ws08-v After a great time in Los Angeles last week for PDC2008, I returned to Redmond this week to re-deliver my talk “Architecture Without Big-Design-Up-Front” for the _patterns & practices _Summit this morning.

I’ve been doing my demos for this talk using the new Visual Studio 2010 CTP and have it running on by under-the-desk machine (more power than my laptop). But since the Summit is in a different building than my demo machine, I wanted to reach into it from my laptop using the Hyper-V Management Console from Windows Vista.

After getting my machine up to SP1 (one of my prereqs had failed) I was able to install it. But for some reason, I couldn’t get it to connect. I could connect with Remote Desktop, but I couldn’t connect with the Hyper-V Console.

After a bit of digging, I found a WONDEFUL set of posts by John Howard, a PM from the Hyper-V team. In there he shows you all the security and firewall connections you should check if you have issues connecting to the Hyper-V server.

It turns out that all of my settings from Part 1 were correct, but one setting in Part 2 was wrong (WHY??). I didn’t need Parts 3-5, but I’m including them here for completeness.

Thanks John! You saved my ass.

PS. Now that PDC is behind me, I’m planning a bunch of blog content to share all that great stuff with the rest of you. Stay tuned!

Crazy Times Ahead - PDC, P&P Summit, Tech Ed EMEA

I don’t know how I get myself into these things, but it looks like I’m hitting three conferences in three weeks, only two weeks after moving my family into a new house.

Foolish? Hell yeah. Fun? You bet!

[ ] (http://www.microsoftpdc.com/)

I’m very fortunate this year to be one of the folks representing Visual Studio Team System Architecture Edition at the Microsoft Professional Developer’s Conference (PDC) in Los Angeles. PDC is always a special conference, because this is where we get to tell you what we’ve got coming up for developers. What is the next cool thing? Only one way to find out and that is come to PDC.

My talk at PDC is called “Architecture Without Big Design Up Front”. It is a mix of agile development, architecture tooling, a little process, a real world problem to solve with real code (so made up samples here) and hopefully some fun.

The week after PDC I fly up to Redmond to kill two birds with one stone: my monthly visit to my team in Building 25 on campus and a stop off at the P&P Summit to talk again. I always love the P&P Summit as a speaking gig. The audience is small, but not too small. The talks can be very interactive and you always get to talk about interesting things.

The following week, I’ll be in Barcelona Spain for Tech Ed EMEA. I’ll be repeating my PDC talk there for people who couldn’t make it to LA, and I’ll also be doing my classic “Agile Talk on Agility”. (Thanks again to Brian Button from whom I stole this talk years ago). My wonderful, amazing wife Emily is coming along on this one (she never lets me go on trips like this solo), and it just happens to coincide with our 8th Anniversary, so we’re going to do a little vacation while we’re there.

Hopefully I’ll bump into some of you on the road this tour. Please if you see me walking the hallways or in the hotel lobby or at one of the many social events, feel free to walk up and introduce yourself.

See you there!

ArcCast.TV – What’s Coming for Architects in Visual Studio Team System

Somehow this slipped past me, but a couple of weeks ago a webcast that I did with local Architect Evangelist Joe Shirey posted up on Channel9.

Here’s the official description:

ARCast.TV - Peter Provost on what’s coming for Architects in Visual Studio Team System

The upcoming version of Visual Studio Team System (code named Rosario) has a number of new features and functions for Architects. Senior Program Manager of Visual Studio Team System for Architects Edition, Peter Provost, sits down with Joe Shirey to discuss what investments Microsoft has made into the product and how it will potentially improve the lives of Architects.

In addition to that, a number of other great webcasts have been going up by my team mates and other VSTS folks. We’ve created a special section on Channel9 for all of this great content at http://channel9.msdn.com/VisualStudio/ so please go check it out!