30 December 2008

Get Files Associated with a Build

One of the greatest features of Team Foundation Server is it's extensibility via the TFS Object Model.  A short while back I received a question asking how to retrieve a list of all files included in all the changesets associated with a build.  The intent (of the person asking the question) was to deploy only those files that had been modified in one of the changesets.

The following code example is what I came up with.  I can't say it's the only way, or even the most efficient way, to achieve the desired result, but it's at least one way :-)  I've also posted this example on TFSExamples.com, here.

/// <summary>
/// Gets a list of files included in all changesets associated with the specified build URI.
/// </summary>
/// <param name="tfServerName">The name of the Team Foundation Server server.</param>
/// <param name="buildUri">The URI of the build to retrieve items for.</param>
/// <param name="workspaceName">The name of the workspace that's used to map server items
/// to local items (e.g. to a file on the client machine).</param>
/// <param name="workspaceOwner">The workspace owner.</param>
/// <returns>A list of files included in all changesets associated with the specified
/// build URI.</returns>
/// <remarks>You can specifiy an empty/null <paramref name="workspaceName"/> and/or
/// <paramref name="workspaceOwner"/> if you want a list of server items returned.</remarks>
private List<string> GetFilesAssociatedWithBuild(string tfServerName, Uri buildUri, string workspaceName, string workspaceOwner)
var buildFiles = new List<string>();
Workspace workspace = null;

// Obtain cached instance of TeamFoundationServer (if a match is found). If the current credentials are not
// valid, then a connection dialog will be displayed when EnsureAuthenticated is called below
var tfServer = TeamFoundationServerFactory.GetServer(tfServerName, new UICredentialsProvider());

// Ensure the current user can authenticate with TFS

// Get a reference to the build service
var buildServer = (IBuildServer)tfServer.GetService(typeof(IBuildServer));

// Get a reference to the version control service
var versionControl = (VersionControlServer)tfServer.GetService(typeof(VersionControlServer));

// Get the workspace used to map server items to local items
if (!string.IsNullOrEmpty(workspaceName) && !string.IsNullOrEmpty(workspaceOwner))
workspace = versionControl.GetWorkspace(workspaceName, workspaceOwner);

// Get the build specified by the selected build URI
var build = buildServer.GetBuild(buildUri);
if (build != null)
// Get a list of all changesets associated with the selected build
var changesets = InformationNodeConverters.GetAssociatedChangesets(build);
if (changesets != null)
// Iterate through all changesets associated with the selected build
foreach (var changesetSummary in changesets)
// Get the changeset for the specified ID
var changeset = versionControl.GetChangeset(changesetSummary.ChangesetId);

if (changeset.Changes != null)
// Add each file associated with the current changeset
foreach (var changesetItem in changeset.Changes)
if (workspace != null)
// Since a workspace is available, map the server item to a local item
item = workspace.GetLocalItemForServerItem(changesetItem.Item.ServerItem);
// A workspace was not provided, so return the server item
item = changesetItem.Item.ServerItem;

// Do not add duplicate filenames
if (!buildFiles.Contains(item))
return buildFiles;

04 December 2008

Microsoft Learning & Hands-On Labs

If you've never checked out the Microsoft Learning site I would recommend giving it a look.  This site provides a great deal of training-related information for various Microsoft products.  You can easily find training for a variety of products based on the learning resource types, technologies, or subjects.

You can also search for a specific exam and get detailed information on what materials are available for use in preparing for the exam.  It will also give you other useful information such as what certifications does the exam apply to.

Another cool feature of the site are the Learning Plans.  There are several pre-defined learning plans that allow you to easily add a group of learning resources to your "My Learning" page.  For example, you can select the Learning Plan for MCPD Certification as a Web Developer and get a list of steps that you can follow to achieve the MCPD Certification as a Web Developer.

The best part of this site is that a lot of the content is offered for free (who can resist free on-line training? :-).  As of this post, here is a list of the developer-related e-learning modules available for free (or you can view all current free items on-line by clicking here):

Distributed Applications

Windows and Smart Client

.NET 3.0


SharePoint Technologies


Microsoft BizTalk

Microsoft SQL Server

Hands-On Labs

There are also several hands-on labs available for free.  Here is a short list of a few of them - I have no doubt there are others available as well:

Happy learning!

25 November 2008

How To: Skip Actions When Queuing a Build

One of the tasks we commonly build into our Team Build scripts is the ability to run FitNesse tests along with other tests (such as unit tests).  If any of the tests fail, we do not deploy the product for user acceptance testing.

The advantage to this approach is that we find out relatively quickly if we have "broke" the build if we have failing tests.  The down side to this is two-fold: 1) the build takes longer to run (not that big of an issue in our case) and 2) Sometimes we refactor code that should break the FitNesse tests.

In the latter case, it may take somebody several hours (or even sometimes, days) to review the failing tests and get them corrected.  In the meantime, none of our updates get deployed for further testing.

Properties to the Rescue

Some time ago, I wrote a short post explaining how to access the various properties, items, and meta data that you can define and/or make use of in your Team Build scripts.  By making use of a simple property declared within the build script we can allow the developers to queue a new build and override the execution of the FitNesse tests so the build can proceed.  Configuring the build script to achieve this requires three steps:

1. Create a custom property that will be used as a flag to determine whether the desired functionality should be executed or overridden (i.e. skipped).  In my example below, I named the property SkipFitNesse.


2. Place the task(s) to be executed into a custom target specifying a condition.  For example:

<Target Name="RunFitNesseTests" Condition="'$(SkipFitNesse)' == 'false'">
  < tasks go here... />

Notice that the property name, SkipFitNesse, is used in the condition.  As long as it remains set to its default value (in this case, false) the target will execute.

3.  Call the target at the desired point from within the build script.  In the example below, I am calling the target to run the FitNesse tests in the <AfterCompile> target.

<Target Name="AfterCompile" Condition="'$(IsDesktopBuild)'!='true'"> 
   <!-- Run FitNesse tests for Risk Rating -->
  <CallTarget Targets="RunFitNesseTests"/>

Now that the build script is setup, you can manually override the execution of the FitNesse tests when you queue a new build by entering the following text into the command-line arguments field:


For example:


With this approach, the developers on our team now have a quick and simple method for skipping the execution of FitNesse tests if they are known to be in a "non-passing" condition and we want the build to continue.  This is only one example of how you might override the value of a property on the queue build dialog.  There are undoubtedly countless uses for this technique.

Also, if you're interested in seeing how we execute FitNesse tests as part of our builds, check out this post.

Omaha Team System User Group

After having to postpone the session from September due to scheduling conflicts we had a great turnout for the Omaha Team System User Group meeting last week.  The speaker for our November meeting was Russ Wagner, an Enterprise Applications Architect at Farm Credit Services of America.

After having some tasty pizza and enjoying a little socializing, Russ presented on the TFS command line utilities and TFS Power Tools related to Team Foundation Server.  The presentation went very well (despite some pre-demonstration glitches) and proved to be very informative.  Although I've had the opportunity to use the majority of the command line tools and TFS Power Tools, it was nice to see them all covered in a single presentation.

Once the presentation was over, we raffled off some books and had some great Q & A with a few of the attendees.  As always, I'm looking forward to our next meeting after the start of the new year.

Click here to download the presentation in PowerPoint 2007 format.

27 October 2008

VSTS 2010 + .NET Framework 4.0 CTP

Microsoft Visual Studio 2010 and .NET Framework 4.0 Community Technology Preview (CTP) has been made available for download (as of 26 Oct 2008).  You can get the latest bits here.

It is about a 7.5 GB download so be prepared for it to take a little while, especially since it was just released.

There is a ton of new functionality in VSTS 2010, far too much to enumerate in this post.  However, you can check this previous post of mine as a starting point for getting more details.

Download VSTS 2010 .NET 4.0 CTP

17 October 2008

VSLive! Las Vegas - Day 3

Well, the "regular" conference sessions are now over.  All that is left is the post-conference session which includes an all-day hands on lab for LINQ.  I will spend part of the day in this session until it's time to head to the airport.

Once again, I spent the last session day in ALM sessions related to Team Foundation Server.

The first session of the day was mine, "Using Team Foundation Build in the "Real" World".  I thought the session went very well (I suppose the feedback will tell the real story :-).  There was great attendance and a lot of great questions being asked.  I really enjoyed presenting at VSLive! and hope to do it again in the future.

The remaining sessions covered implementing cross platform/language builds using TFS, migration vs. integration of TFS, and programming the TFS object model.

Although the sessions were great, I enjoyed talking to the other attendees and speakers the most.  It's always nice to meet other people facing the same issues as you and that have the same interests.  Because of the sessions I attend and the people I talked to, I have a lot of new information, techniques, and practices that I can take back with me and apply to my daily work.

All in all, it's been a great week at VSLive! Las Vegas.  I may have even set some kind of world record while being here - I'm not much of a gambler and, in fact, I may be the first person ever to stay in Las Vegas for five days without gambling a single cent :-)  I did enjoy a lot of other attractions while here in Las Vegas, however.  I attended a show (the Phantom of the Opera), spent time swimming (don't get a chance to do that much at home), walked the "strip" countless times, watched a battle between two pirate ships, and spent an average of $20-$25 on just about every meal I ate :-)  Speaking of food, the lunch meals provided during the conference were second to none.

If you're interested in the slides from my presentation, you can get them here.

TFSInfo Updated for TFS 2008 SP1

The TFSInfo utility has been updated for TFS 2008 Service Pack 1.  This update includes the following changes:

  • UPDATE: TFSInfo will correctly report TFS 2008 SP1 when it is installed.
  • UPDATE: TFSInfo now displays the TFS installation folder.
  • FIX: TFSInfo now finds the TFS installation folder when it has been installed in a non-default location.


You can see from the screen shot which information is displayed.  In case you can't see the image, the following information is displayed by TFSInfo:

  • AT Server Name
  • AT Version
  • AT Edition (e.g. Standard, Workgroup, or Trial)
  • TFS Installation Folder
  • DT Server Name
  • DT Server Version (not available for TFS 2008)
  • SQL Server Version
  • Reporting Server URL
  • TFS Installation Date
  • TFS Product ID

You'll notice in the list above that the Data Tier schema version is not available for TFS 2008.  This is because the column that's used to determine the schema version in TFS 2005 does not exist in TFS 2008.  I haven't had any luck locating the schema version in any other table in the set of TFS 2008 databases.  If I am able to determine how that information is stored (assuming it is) I will release an update.  Another update will be released shortly following the next Visual Studio 2010 CTP (due out in the next couple of weeks during the PDC).

The new version can be downloaded here.

NOTE: The Team Explorer Client 2005 or 2008 needs to be installed for TFSInfo to work.

Click here to view the original post.

16 October 2008

VSLive! Las Vegas - Day 2

Day 2 is now a wrap and the conference continues to go strong.  As you may have suspected, I spent my time in the ALM sessions around the subjects of TFS Work Item Tracking, Team System Add-Ons, and Branching Strategies.  All the sessions I attended were very good although I didn't attend every session because I spent a little time polishing up my slides and demos for my talk on Thursday morning (Using Team Build in the "Real" World).

I would have to say my favorite talk of the day was the one on Branching Strategies by Jeff Levinson.  There was definitely some good information coming out of this presentation that can be applied today on our projects.  I'll be picking Jeff's brain over the next few months attempting to learn everything he knows about branching (if that's possible :-)

15 October 2008

VSLive! Las Vegas - Day 1

The first day of VSLive! Las Vegas is now in the books.  This is my first time attending a VSLive! conference so I wasn't sure what to expect.

The keynote was given by Stephanie Saad, the Group Program Manager for Visual Studio Team Foundation Server.  She discussed the use of Team Foundation Server throughout Microsoft and some of the challenges they ran into while using the product.  The scale at which they make use of Team Foundation Server is somewhat staggering in comparison to the seven developer teams at the company I work for.  Along with one of her co-workers, I don't recall the name (sorry), they also presented some of the new features that will be available in VSTS 2010 - mostly around the tracking and reporting of project-related data in Microsoft Excel.

I spent most of the rest of my time in TFS-related sessions with speakers such as Benjamin Day and Brian Randell.  All in all, it was a great start to the conference.  So far, based on the size of the conference rooms, the number of attendees, and the speakers, I would have to say it's relatively comparable to the Heartland Developers Conference.

Being in Las Vegas for the first time, I decided I had to check out at least one show.  So, I decided to go to the Phantom of the Opera at The Venetian.  I've seen Andrew Lloyd Webber's Phantom of the Opera in Des Moines and Omaha and thought I could use those shows as a basis for comparison.  I must admit, the show at The Venetian pretty much blew the others away!  In all fairness, the show at The Venetian has a dedicated stage and auditorium built solely for the purpose of The Phantom of the Opera.  This allows the effect to be top notch.  Although I'm not sure who was playing the parts of the Phantom, Christine, etc. the singing was phenomenal.  If the other shows in Las Vegas are of this caliber of quality, then there are indeed a lot of great shows in this town :-)

14 October 2008

Visual Studio 2010 Links

There has been a lot of information coming out over the past couple of weeks regarding Visual Studio 2010 so I thought I'd consolidate a list of links that provide some information about what may be included in the next release:

Informational Posts

PodCasts and Videos


There are a lot more blogs related to Team System than these listed below.  However, these are some of the blogs I read more often:

There is no doubt a lot of other information out there but this should help you get started if you're just now starting to take a look at what's coming down the road with Visual Studio 2010.

Team Foundation Build 2010

I just finished watching a great video from Jim Lamb on Channel 9 covering some of the new features for Team Foundation Build 2010.  The video is about 35 minutes long and is well worth the watch.  Here's a quick synopsis of what's covered in the video:

  • Team Foundation Build 2010 will support Windows Workflow 4.0.  This feature alone would make a worthy upgrade to Team Foundation Build.  The new Workflow UI being designed for the .NET Framework 4.0 will be included in the build type editor within VS 2010 providing a fantastic user experience for modifying build types (can you say "XML - not for me, thank you" :-).  There will be several Team Foundation Build-related Workflow Activities included out of the box with VS 2010 and I would imagine several 3rd party/open source activities will appear on the scene shortly after its release.
  • "Gated" check-ins will be supported.  This feature, when turned on, will ensure that a given build type successfully runs before any artifacts are checked into version control.  This will be a great enhancement for teams making use of continuous integration within Team Foundation Server.
  • "Private/Buddy" check-ins will be supported.  This feature is very much like "Gated" check-ins except that the check-in, and resulting build, are treated as a separate, private build associated only with the user who initiated the build.  You can even set distinct retention policies for "Private" builds.
  • Support for Symbol Server Integration.  With the integration of Symbol Server into Team Foundation Build, the debugger within Visual Studio will know how to navigate to the correct source code within TFS Version Control.
  • Build Controllers.  You will have the ability to configure "pools" of build agents which can then be associated with a build type.  The build server can then utilize the least active build agent when starting a new build.
  • Build Agent Tags.  You will be able to associate tags with build agents.  For example, you may tag a build server as "SQL Server 2008", meaning that SQL Server 2008 has been installed on that server.  Another build agent may be tagged with "MOSS 2007", etc.
  • "All Inclusive" Build Agent.  There is a desire to have the build services include support for MSTest and DBPro without having to install the Test or DBPro SKUs.  This will be a great convenience and something that I believe that should have been included from the first version.
  • Log Enhancements.  The Build Log has been improved tremendously and is much easier to read and navigate.  You can now, for example, click a link on an error in the build log and be taken to the exact location within source code where the error occurred.
  • Build Deletion Control.  When deleting build types, you will now have the ability to be more specific as to what gets deleted.  For example, you can choose one or more of the following (all are selected by default): Details, Drop, Test Results, Label, Symbols, or Build.  This can be done manually and/or specified within the retention policy settings.

The video goes into a little more detail about each of the above items as well as a few others that I haven't mentioned.  It is really nice to see that Team Foundation Build is getting some attention.  I think the current product is good but there is a lot of room for improvement and it appears that is the direction it's heading.

01 October 2008

Presentations, Races, and MVP!

Lately, I've been quiet because I've been busy working on my presentation for this month's VSLive! Las Vegas conference.  I'm looking forward to presenting on Team Build and meeting a lot of new people as well as catching up with some old acquaintances.  This will be my first time to Vegas so it should be a great time all around.

Along with that, I was also preparing for my first ever adventure race - the Berryman Adventure.  The race was held this past weekend, September 27th, and took us just under 13 hours to complete.  The disciplines included hiking/running, some swimming, canoeing, and mountain biking through the Ozarks in southern Missouri.  We did not come close to winning the race but we did complete it, which was a big accomplishment since it was our first race.  We enjoyed it so much that we plan on participating in as many as we can next year.

To top everything off, I received a message today informing me that I have been selected for Microsoft MVP - Team System!  Needless to say, I am excited, honored, and humbled all at the same time.  I've always enjoyed sharing knowledge and ideas with the developer community and now I have even more incentive than ever before.

13 August 2008

VS 2008 SP1 Tidbits – 1 of X

Sometimes it’s the little things that excite me the most :-)  For instance, in the recently released Visual Studio 2008 Service Pack 1 (VS 2008 SP1), there are a few nice enhancements to the Team Explorer and Source Control Explorer that I find extremely helpful.  These enhancements include:

  • The ability to right-click on a build type within Team Explorer and select “View Configuration Folder”.  This will open the Source Control Explorer pane and take you directly to the folder containing the selected build type.  This is a great time saver – especially now that TFS 2008 supports storing your build types in any folder you choose.

  • Having non-solution files automatically checked out when you start modifying them.  This is especially useful in build type (TFSBuild.proj) files.  How many times have you forgotten to check out a build type file prior to editing it?  This is no longer an issue with SP1.  Nice!
  • The ability to drag-n-drop files directly into the Source Control Explorer pane.  This is a really nice feature and yet another great time saver.
  • One other feature that I really like is the (minor) modification to the Source Location and Local Path within the Source Control Explorer.  The Source Location can now be copied to the clipboard (nice for documentation, e-mail messages, etc.) and the Local Path is now a hyperlink control which will open the mapped folder in Windows Explorer when clicked.

I realize that these enhancements are small in comparison to some of the other enhancements in SP1 but I still find them very useful.  It’s nice to see some of these time savers make it into a service pack release instead of having to wait for the next major release of Visual Studio.

VS/TFS 2008 SP1 – Installation Tips

Well, Visual Studio 2008 Service Pack 1 (VS 2008 SP1) has been out (RTM’d) for about three days now and several tips have materialized across the Visual Studio community that may help save you some time.  These tips are broken out into Team Foundation Server and Visual Studio.

Updating Team Foundation Server 2008

  • When upgrading a Team Foundation Server, Installation order is important (read the installation guide).  As per the guide, “In deployments where the application tier and a client tier component are installed on the same computer, you must install SP1 for Visual Studio 2008 before you install SP1 for Team Foundation Server. Otherwise, you will not be able to install SP1 for Team Foundation Server.
  • If you upgrade from SQL Server 2005 to SQL Server 2008 but do not install SP1 after the upgrade, Team Foundation Server will no longer function.
  • If you have Visual Studio 2008 installed on your application-tier server and you want to install SP1 for Visual Studio 2008 you must also install TFS 2008 SP1.  If you install only one service pack, you will create an unsupported configuration.
  • If you have a standby application-tier server, you must install SP1 on the standby application-tier server if you install it on the primary server.
  • In order to update client components such as Team Explorer, you must install SP1 for Visual Studio 2008 – SP1 for Team Foundation Server 2008 includes only server updates and does not update Team Explorer.

Updating Visual Studio 2008


  • If you’re having issues downloading VS 2008 SP1 on a network that uses Microsoft ISA Server, take a look at this post.
  • As per this post:
    • If you get a Windows Update prompt to reboot during the installation of SP1, ignore it.  Wait until the SP1 installation is complete and then reboot.
    • If you have a pre-release of the Team System for Database Development GDR (that supports SQL Server 2008) installed, you will need to uninstall and reinstall after upgrading to SP1.
    • You can’t create the admin mode/slipstream TFS installer when running on a 64-bit OS.  TFS will be supported on 64-bit operating systems with the “Rosario” release.

11 August 2008

VS 2008 & .NET 3.5 SP1 Released

Visual Studio 2008 Service Pack 1 and .NET Framework 3.5 Service Pack 1 have been released.  You can read the details of what’s included as well as download the service pack here.

You can also read this post and this post from Brian Harry that covers some of the features in detail.

07 August 2008

VS 2008 & .NET 3.5 SP1 Almost Here

A while back I posted about Visual Studio 2008 & .NET 3.5 Service Pack 1 (Beta).  This was on May 14th.  Based on the download text for SQL Server 2008 RTM, Service Pack 1 is a required dependency and will be available after August, 11th.


Also, the .NET Rocks PodCast #365 announces that SP1 is already available so the show must have been released a few days earlier than expected :-)  The description on the web site for this PodCast states that SP1 will ship around August 11th as well.

At any rate, it appears that SP1 will be available within the next week.

28 July 2008

VSLive! Las Vegas

Several weeks ago I was informed that I had been selected to present at this year’s VSLive! in Las Vegas.  Although I have presented at other conferences in the past (e.g. Heartland Developers Conference and Tulsa TechFest) this will be the largest conference I’ve presented at to date.  I have to admit, I’m pretty excited about it all.

I will be presenting on Using Team Build in the “Real” World on Thursday, October 16th at 08:30.

VSLive! Schedule Snippet

I’m looking forward to meeting new people and learning new things.  So, if you’re planning on attending VSLive! in Las Vegas this year and have an interest in Team Build (or Team Foundation Server in general) be sure to look me up.

24 July 2008

Omaha Team System User Group

We’ve had yet another successful gathering of the Omaha Team System User Group.  After moderating one of the Birds of a Feather sessions at last month’s Tech-Ed conference, I decided to try something similar with this month’s user group meeting format.

Rather than schedule a speaker for this meeting I decided that we would open the floor up for any Team System-related topics for discussion amongst the group.  Being the middle of the summer and having changed the format to not include a speaker I didn’t expect the same turnout that we typically get at other meetings.  We ended up with a total of 15 attendees which was perfect for sitting around a few tables and having some conversation.

Some of the topics we discussed included:

  • Certifications – are they important (i.e. do they really matter)?
  • Training – what types of training resources are available for Team System.
  • Gotchas – what kind of “gotchas” have other group members ran across while working with Team System.
  • APIs – what type of experience do other group members have with working with the TFS Object Model.
  • How is it being used – i.e. how is Team System being used throughout the community.
  • FinalBuilder – just bringing an awareness to the group that FinalBuilder has some great TFS support.
  • Etc.

We all had some great discussion for about an hour and a half and I think everyone in the room, especially myself, left with having learned something new.

The meeting format seemed to work out great so I believe this is something we’ll do at least once per year.

23 July 2008


A few days ago a fellow co-worker asked me if I could create a simple build task that would allow anyone on their team the opportunity to cancel a build, once it has been queued, before the build actually did anything.  The idea was simple:

  1. A new build gets queued.
  2. The build sends out an e-mail notification (via a custom task) informing the recipients that a new build has been queued.  The e-mail message also has a link that, when clicked, will cancel the build.
  3. The build waits a pre-determined amount of time (e.g. 5 minutes) giving the e-mail recipients a chance to cancel the build before it continues.
  4. If the build is not canceled, the build will proceed as usual once the delay has expired.

The driving reason behind this request was to allow any active testing to continue without being interrupted by a new build – i.e. the testers have the ability to cancel a build.

Building the custom task was pretty simple – it basically just sends out an e-mail message (based on a customizable HTML template) and then waits for the specified number of seconds (the default is 300 seconds).

The more interesting piece of the puzzle was creating a simple, one-page web site that, when called, will cancel a build.  The web page takes the build URI as its only parameter and utilizes the Team Foundation Server web services API to cancel the build.

All in all it worked out nicely.  If this sounds like something that may benefit your team, you can check it out on the MSDN Code Gallery here.  The source code as well as the binaries are available for download.

The next challenge (that was presented to me today) is to also include a link in the e-mail notification message that, when clicked, will instruct the build to continue immediately.  This one will take a little more thought…

Click here for more information on the DelayedBuildTask.

16 July 2008

TFS Power Tools – July 2008 Release

The July 2008 release of the Visual Studio Team System 2008 Team Foundation Server Power Tools has just been released.  Here is a summarized list of what is included with the tools:

  • Command line tool (TFPT.EXE)
  • Team Explorer IDE menu additions
  • Build Notification tool
  • TFS Best Practices Analyzer
  • Process Template Editor
  • Work Item Templates
  • Custom check-in policies
  • TFS Server Manager
  • TFS Users tool
  • Alert Editor

One of the more exciting changes, from my point of view, is the new user interface for managing TFS Alerts.  It is going to be nice having this capability available directly from within the IDE.

For a more detailed look at what’s included, take a look at this post from Brian Harry.

Click here to be taken to the download site.

15 July 2008

Cleaning Up Old Team Projects

A few days ago a co-worker sent out an e-mail asking if any of several team projects were still in use; if not, then they would be removed from Team Foundation Server.

Looking at the list it was easy enough to recognize a few active projects but others would take more investigation.  After sending my feedback I thought a custom utility might be helpful in the future for the next round of potential deletion candidates.  So, I decided to put the TFS Object Model (TFSOM) to use and created TFSunset (see screen shot below).

TFSunset uses the TFSOM to query the version control system and work item store for activity within a specified time range (e.g. the last 30 days).  All team projects for a given team foundation server are searched.  If no changesets have been created and no work items have been created/modified within the last 30 days (or whatever count you specify) then that team project will be listed.

Here is a screen shot showing the results of one search:


In the above example, the team project WalkingPage has not had any changeset or work item activity within the past two weeks.

Keep in mind that just because a team project is listed by this utility, that is no guarantee it has gone the way of OS/2 – you still need to perform your due diligence before deleting it from TFS.  However, this utility should be able to help narrow down the list.

I am planning on posting the source code to the MSDN Code Gallery in the near future.  For now, you can download the executable here.

Note: you will need to have Team Explorer 2008 installed prior to running this utility.

30 June 2008

Creating Team Build Types

I was answering a question related to programmatically creating team build types today and realized there weren’t too many examples on the web.  I didn’t see any examples that included all the details I was looking for – for example:

  • Adding the solution to be built to the new build type
  • Turning on/off test execution
  • Turning on/off code analysis

An example containing these details may exist, I just didn’t come across it during my initial search.

So, with that said, I decided to post the main part of the example application I put together to test out some concepts.  The items listed above are included in the example code below.

The example code includes two methods:

  • CreateBuildType – this method accepts six arguments that can be used to programmatically create a new build type.
  • VersionControlItemExists – this is a helper method that determines whether an item already exists in version control.

Although the example below can be used to create a new build type “as is”, there is always room for improvement.  For example:

  • Add a parameter to specify the default build agent.  Currently, the first build agent returned is used as the default when creating the build type.
  • Add a parameter to control the exact placement of the build type in version control (a common pattern is used in the example below).
  • Throw exceptions instead of displaying message boxes when exceptional conditions arise.  The message boxes were used for example purposes only.

With that said, here is the source code…

using System;
using System.Windows.Forms;
using Microsoft.TeamFoundation.Build.Client;
using Microsoft.TeamFoundation.Build.Common;
using Microsoft.TeamFoundation.Client;
using Microsoft.TeamFoundation.VersionControl.Client;
using Microsoft.TeamFoundation.VersionControl.Common;

private static bool CreateBuildType(string serverName, string teamProject, string buildName, string solutionPath, string dropFolder, bool runTests)
// Get a connection to Team Foundation Server
TeamFoundationServer tfServer = TeamFoundationServerFactory.GetServer(serverName, new UICredentialsProvider());

// Get a reference to a build service
IBuildServer buildServer = (IBuildServer)tfServer.GetService(typeof(IBuildServer));

// Get a list of build agents associated with the specified team project
IBuildAgent[] buildAgents = buildServer.QueryBuildAgents(teamProject);

if (buildAgents.Length == 0)
@"The specified Team Project does not have any build agents associated with it. Please create at least one build agent.",
"No Default Build Agent Found",
MessageBoxButtons.OK, MessageBoxIcon.Warning);

return false;

// Create the new build type definition
IBuildDefinition buildType = buildServer.CreateBuildDefinition(teamProject);

// Specify the name of the new build type
buildType.Name = buildName;

// Specify where the new build type should be stored in version control
buildType.ConfigurationFolderPath = string.Format(@"$/{0}/TeamBuildTypes/{1}", teamProject, buildName);

// Set the default build agent
buildType.DefaultBuildAgent = buildAgents[0];

// Set the default drop location
buildType.DefaultDropLocation = dropFolder;

if (!VersionControlItemExists(tfServer, buildType.ConfigurationFolderPath))
IProjectFile projectFile = buildType.CreateProjectFile();

// Add a new solution to be built to the project
ISolutionToBuild solution = projectFile.AddSolutionToBuild();

// Set the path of the solution to build
solution.SolutionPath = solutionPath;

// Specify whether tests should be ran or not
projectFile.RunTest = runTests;

// Run code analysis if the project is setup to do so
projectFile.RunCodeAnalysis =

// Save the project file

// Save the new build type
// The specified build type already exists
"The specified Build Type already exists. Please specify a different Build Type name.",
"Build Type Already Exists",
MessageBoxButtons.OK, MessageBoxIcon.Warning);

return false;

return true;

private static bool VersionControlItemExists(TeamFoundationServer tfServer, string itemPath)
string projectFilePath = VersionControlPath.Combine(itemPath, BuildConstants.ProjectFileName);

return ((VersionControlServer)tfServer.GetService(typeof(VersionControlServer))).ServerItemExists(
projectFilePath, VersionSpec.Latest, DeletedState.NonDeleted, ItemType.File);

17 June 2008

TFSExamples.com – A New Site

As of late, I’ve started working on several Team Foundation Server API-based examples (some of which are starting to show up as blog postings).  Although the Team Foundation Server SDK does include some examples, it’s not always easy to locate the example you need (assuming it’s even there).  There are several blogs containing various TFS API examples, but again, the full details may be spread across several postings or even separate sites.

Several months ago, Grant Holliday created the TFSBuild.com site dedicated to MSBuild and Team Foundation Build recipes.  I decided to take a similar approach and registered the site TFSExamples.com.  I utilized the same ScrewTurn wiki software and customized it to the needs of the new site.  The intent is to compile a library of Team Foundation Server API examples making it simple to get started with a project based on the TFS object model.

There are only a couple of examples on the site at the moment but I plan on adding several more over the next few days.  I also hope that others will come across the site and add their own examples.

Some of the current functionality on TFSExamples.com includes:

  • Add New Example – displays instructions on adding a new example to the wiki
  • Browse All – displays a list of all pages in the wiki
  • Browse Categories – displays a list of all categories in the wiki
  • Request Example – allows you to request a specific example be added to the site

If you have any examples based on the TFS object model that you would like to publish, please check out TFSExamples.com and add them accordingly.

15 June 2008

Display Connect to Team Foundation Server Dialog

Over the past few days I’ve been working on a simple TFS utility that will provide the ability to import and/or export Areas and Iterations.  The overall intent of this exercise is not only to reinvent the wheel but to also gain some experience in writing Visual Studio Add-ins.  At the same time, I am planning on posting “interesting” tidbits of code along the way.

Currently, I am still in the phase of writing the utility (it will first be a standalone utility and later, a Visual Studio Add-in) and had the desire to display the Connect to Team Foundation Server dialog…

Connect to Team Foundation Server Dialog

I suspected there was an API for this dialog; I only needed to find it – and I did.  Paul Hacker has a nice post that explains the basics for achieving this goal using the DomainProjectPicker class.  His post explains very nicely how to get it to display the dialog in one mode – that of allowing only a single project to be selected from the dialog.  However, there are several variations on what type of functionality is available based upon how you call the API.  The following sections cover the various scenarios for displaying the Connect to Team Foundation Server dialog.

Server Selection Only

This mode allows you to select a Team Foundation Server that has been previously registered and/or allows you to register a new Team Foundation Server.  By default, the resulting dialog looks like this:

Connect to Team Foundation Server Dialog - Server Only Select - Default

The code to display this dialog is fairly simple:

public void DisplayTfsConnectionDialog()

// Initialize the TFS project picker object
DomainProjectPicker projectPicker = new DomainProjectPicker(DomainProjectPickerMode.None);

// Display the dialog
if (projectPicker.ShowDialog() == System.Windows.Forms.DialogResult.OK)
// Do something...

Notice the argument value passed into the DomainProjectPicker constructor – DomainProjectPickerMode.None.

You can initialize the selected server by setting the project picker’s SelectedServer property. To set a default server, add the following lines of code to the above example somewhere prior to calling the ShowDialog method:

            // Select a default server
TeamFoundationServer defaultServer = TeamFoundationServerFactory.GetServer("tfs-dev");
projectPicker.SelectedServer = defaultServer;

I’ve hard-coded the server name (“tfs-dev”) for example purposes.  When the modified code is ran, the following dialog is displayed:

Connect to Team Foundation Server Dialog - Server Only Select - Initialized

The SelectedServer property returns an instance of TeamFoundationServer for the selected server.

Single Project Selection

This mode allows you to select a team project as well as a server.  In this mode, you can select only one project.  The resulting dialog looks like this:

Connect to Team Foundation Server Dialog - Single-Project Select - Default

You need to make one simple modification to the code example above to display this version of the dialog – change the DomainProjectPicker constructor argument to DomainProjectPickerMode.AllowProjectSelect.  To retrieve the name of the selected project, just check the SelectedProjects property.  This property returns an array (there will be only one element in this case) of ProjectInfo objects.  For example, to display the name of the selected project, modify the above example accordingly:

            // Display the dialog
if (projectPicker.ShowDialog() == System.Windows.Forms.DialogResult.OK)
MessageBox.Show(projectPicker.SelectedProjects[0].Name, "Selected Project");

Multiple Project Selection

This mode is similar to the single project mode above except it allows you to select one or more projects.  In this case, you must combine two values for the DomainProjectPicker constructor argument: DomainProjectPickerMode.AllowProjectSelect | DomainProjectPickerMode.AllowMultiSelect.  This will result in a dialog like this one:

Connect to Team Foundation Server Dialog - Multi-Project Select - Initialized 

You can retrieve the selected project(s) by accessing the SelectedProjects property just like in the example above with the exception that there may be more than one element in the array.

Disabling Server Selection

You can also combine the DomainProjectPicker constructor arguments as listed above with the value DomainProjectPickerMode.DisableServerSelect.  This has the effect of disabling the Server drop-down list and the Servers… button on the dialog.  For example:

Connect to Team Foundation Server Dialog - Single-Project Select - No Server 

Selecting a Default Project

Just as you can select a default Team Foundation Server, you can also select one or more default projects.  There is one caveat - you can only select default projects if you’re using Multiple Project Selection mode.  I really don’t understand why the creators of this particular API chose not to allow a default project selection for Single Selection Mode, but that’s just the way it is.

To set one or more default projects, you must initialize the DefaultSelectedProjects property.  This property is a SortedList where the key is the URL of a specific Team Foundation Server and the value is an ArrayList of projects to be selected for the server defined by the key.  Here is a code example that selects the “Demo” project by default when displaying the connection dialog:

            // Initialize the TFS project picker object
DomainProjectPicker projectPicker = new DomainProjectPicker(DomainProjectPickerMode.AllowProjectSelect | DomainProjectPickerMode.AllowMultiSelect);

// Select a default server
TeamFoundationServer defaultServer = TeamFoundationServerFactory.GetServer("tfs-dev");
projectPicker.SelectedServer = defaultServer;

// Select a default project (in this case, the "Demo" project)
ICommonStructureService css = (ICommonStructureService)defaultServer.GetService(typeof(ICommonStructureService));
SortedList defaultServerList = new SortedList();
ArrayList defaultProjectList = new ArrayList();
defaultServerList.Add(defaultServer.Uri.ToString(), defaultProjectList);
projectPicker.DefaultSelectedProjects = defaultServerList;

// Display the dialog
if (projectPicker.ShowDialog() == System.Windows.Forms.DialogResult.OK)
MessageBox.Show(projectPicker.SelectedProjects[0].Name, "Selected Project");

The following dialog is displayed using the above code example:

Connect to Team Foundation Server Dialog - Multi-Project Select - With Default Selection

That pretty much covers the various scenarios.  Hopefully the above code examples will help out the next person looking for similar functionality.

09 June 2008

Retrieving Areas from TFS

As a matter of self-inflicted education I’ve decided to create a simple Visual Studio Add-In for exporting and importing Areas and Iterations.  I’m not sure how much practical use such a utility will receive but it offers several areas for advancing my knowledge and, hopefully, helping a few other people out along the way.

Although I haven’t completed the utility yet, I have completed some of the initial utility code.  I thought I would create a few posts as I progress in case anyone can make use of the examples.  For this post, I am posting the code used to retrieve the list of “areas” from a Team Foundation Server

With that said, here is some example code for saving the list of Areas defined for a given Team Foundation Server and Team Project.  The code is a little verbose but should be relatively simple to follow.

using System;
using System.Collections.Generic;
using System.IO;
using System.Xml;
using Microsoft.TeamFoundation.Client;
using Microsoft.TeamFoundation.Server;

namespace TestConsole
public class ExportAreas
private TeamFoundationServer _teamFoundationServer;
private ICommonStructureService _commonStructureService;

/// <summary>
/// Exports the "areas" defined within the specified team foundation server.
/// </summary>
/// <param name="teamFoundationServer">The team foundation server.</param>
/// <param name="projectName">The name of the team project to export areas from.</param>
/// <param name="filename">The filename to save the exported areas to.</param>
public void Export(string teamFoundationServer, string projectName, string filename)
_teamFoundationServer =

_commonStructureService = (

List<HierarchyNode> nodeList = new List<HierarchyNode>();

// Locate root structure node for "Area"
NodeInfo areaNode = GetAreaRootNode(projectName);

//String node = _commonStructureService.CreateNode("TEST Node...", areaUri);

// Retrieve the Area nodes XML
XmlElement nodes = _commonStructureService.GetNodesXml(new string[] { areaNode.Uri }, true);

// Recursively build out the list of Area nodes
BuildHierarchicalList(nodes.ChildNodes[0], nodeList, 0);

// Save the areas to the designated text file
StreamWriter writer = new StreamWriter(filename, false);

foreach (HierarchyNode node in nodeList)
new string('\t', node.IndentLevel) + node.Name);


/// <summary>
/// Recursively builds a hierarchical list based on the root node passed in.
/// </summary>
/// <param name="rootNode">The root node to start with.</param>
/// <param name="targetList">The target list to add each <see cref="HierarchyNode"/> instance to. This
/// list must be instantaited on the first call.</param>
/// <param name="indentLevel">The indent level - pass in 0 for the initial call.</param>
private void BuildHierarchicalList(XmlNode rootNode, List<HierarchyNode> targetList, int indentLevel)
HierarchyNode listNode;

if (rootNode.Name == "Children")
for (int index = 0; index < rootNode.ChildNodes.Count; index++)
BuildHierarchicalList(rootNode.ChildNodes[index], targetList, indentLevel);
listNode =
new HierarchyNode()
Uri = rootNode.Attributes[
Name = rootNode.Attributes[
ParentUri = GetAttribute(rootNode,
Path = rootNode.Attributes[
ProjectUri = rootNode.Attributes[
StructureType = rootNode.Attributes[
IndentLevel = indentLevel


if (rootNode.HasChildNodes)
for (int index = 0; index < rootNode.ChildNodes.Count; index++)
BuildHierarchicalList(rootNode.ChildNodes[index], targetList, indentLevel + 1);

/// <summary>
/// Gets the specified attribute from <paramref name="node"/>..
/// </summary>
/// <param name="node">The node containing the attribute collection.</param>
/// <param name="attributeName">The name of the attribute to retrieve.</param>
/// <returns>The value of the specified attribute if it exists; otherwise, an empty string is returned.</returns>
private string GetAttribute(XmlNode node, string attributeName)
for (int index = 0; index < node.Attributes.Count; index++)
if (string.Equals(node.Attributes[index].Name, attributeName, StringComparison.InvariantCultureIgnoreCase))
return node.Attributes[index].Value;

return string.Empty;

/// <summary>
/// Gets the area root node.
/// </summary>
/// <param name="projectName">The name of the team project to retrieve the root node from.</param>
/// <returns>A <see cref="NodeInfo"/> object referencing the root area node.</returns>
private NodeInfo GetAreaRootNode(string projectName)
ProjectInfo projectInfo = _commonStructureService.GetProjectFromName(projectName);

return LocateStructureByType(projectInfo.Uri, "ProjectModelHierarchy");

/// <summary>
/// Locates the desired structure based on structure type.
/// </summary>
/// <param name="projectUri">The project URI to retrieve the structure from.</param>
/// <param name="structureType">Type of the structure to retrieve.</param>
/// <returns>A <see cref="NodeInfo"/> object referencing the root of the desired structure.</returns>
private NodeInfo LocateStructureByType(String projectUri, String structureType)
NodeInfo[] nodes = _commonStructureService.ListStructures(projectUri);

foreach (NodeInfo node in nodes)
if (node.StructureType == structureType)
return node;

return null;


/// <summary>
/// This class is used to hold information pertaining to exported areas or iterations.
/// </summary>
class HierarchyNode
public string Uri { get; set; }
public string Name { get; set; }
public string ParentUri { get; set; }
public string Path { get; set; }
public string ProjectUri { get; set; }
public string StructureType { get; set; }
public int IndentLevel { get; set; }

To use the above sample code, just instantiate the ExportAreas class and call the Export method passing in the desired argument values.