Category: TFS

TFPT TreeClean tamed with PowerShell

Update: Philip Kelley from Microsoft, creator of TFPT, has kindly informed me that the July 2008 release of the TFS Power Tools is now available for download. This new version includes enhancements to TFPT TreeClean that allow you to specify which files to include or exclude and as such solves the main problem my TreeClean PowerShell script was created for. The output format of the new TreeClean also renders this script incompatible but the general concepts used by the script may still be useful.


I like the Team Foundation Server 2008 Power Tools, there are some great additions in there. One particular utility, TreeClean, has a great concept but is a little overzealous for my tastes.

The purpose of TreeClean is to find all local files in your workspace folders that do not exist in source control and then allow you to delete all of them. The problem is that it includes *.user files in its find results and the delete option is all or nothing. The list of files can also be rather overwhelming.

Thankfully we can get some more control by piping the results through PowerShell, starting with a simple script like this:

$ProgFiles = $Env:ProgramFiles ;
$ProgFiles32 = (Get-Item “Env:ProgramFiles(x86)”).Value ;
if (-not [String]::IsNullOrEmpty($ProgFiles32)) { $ProgFiles = $ProgFiles32 ; }

$TFPTEXE = Join-Path -Path $ProgFiles `
-ChildPath “Microsoft Team Foundation Server 2008 Power Tools\TFPT.exe” ;
if (-not (Test-Path -Path $TFPTEXE)) { throw “TFPT.EXE not found.” ; }

[string]$Root = Resolve-Path -Path (Get-Location) ;

& $TFPTEXE treeclean `
| Where-Object { $_ -like ($Root + “*”) } `
| Get-Item -Force ;

Once we have this script saved we can get more information from the results. For example, we can get count and list rogue files by extension:

TreeClean.ps1 | group Extension

We can exclude directories:

TreeClean.ps1 | ? { -not $_.PSIsContainer }

And finally we can delete everything but *.user files:

TreeClean.ps1 | ? { $_.Extension -ne “.user” } | Remove-Item

Now I can clean all the junk from my workspace but keep all my user-level project settings. However, while sorting through the extension-grouped report, looking for files to check-in before cleaning, there was a lot of noise from the build outputs. My quick solution:

gci -inc *.sln -rec | % { MSBuild /t:Clean $_ }

It also has the nice side effect of significantly reducing your workspace folder size if you want to zip it up and send it somewhere.

Custom TFS Check In Policy Responsiveness

I’ve used several third party Check In Policies for Team Foundation Server with both TFS2005 and 2008 and I’ve dabbled in writing my own too. One thing I noticed with most of them, is that they don’t appear to respond to actions in the VS Pending Changes window as readily as the standard Microsoft policies.

I recently followed Jim’s example Option Strict Check In Policy to write my own policy to prevent checking in code with the DataSet Designer ConnectionState Bug. The policy would always correctly evaluate when clicking the Check In button but the Policy Warnings tab didn’t always update automatically when Source Files list changed.

I decided it was time to dig deeper and find out why the standard policies work nicely when compared to the custom ones. After a few minutes with Reflector I discovered there were a few more things to do beyond the instructions in the MSDN article to create a responsive custom policy.

The PolicyBase class, from which your custom policy should inherit, gets passed an instance of IPendingCheckin to its Initialize method which it persists and is made available to your subclass via a protected PendingCheckin property. The IPendingCheckin instance exposes several other objects with events that you can handle to be notified when changes relevant to your policy occur.

The methodology that worked for me was to override Initialize and register the event handler and override Dispose also to remove the handler at the end. All the handler does, after checking the base class isn’t disposed, is to call the custom policy’s Evaluate function and raise the base’s PolicyStateChanged event.

Sample code for a policy dependent on the Source Files list, like the Option Strict policy and the ConnectionState Bug policy, follows:

Public Overrides Sub Initialize(ByVal pendingCheckin As IPendingCheckin)
MyBase.Initialize(pendingCheckin)
AddHandler MyBase.PendingCheckin.PendingChanges.CheckedPendingChangesChanged, _
AddressOf CheckedPendingChangesChanged
End Sub

Private Sub CheckedPendingChangesChanged(ByVal sender As Object, ByVal e As EventArgs)
If Not MyBase.Disposed Then
Dim failures = Evaluate()
MyBase.OnPolicyStateChanged(failures)
End If
End Sub

Public Overrides Sub Dispose()
RemoveHandler MyBase.PendingCheckin.PendingChanges.CheckedPendingChangesChanged, _
AddressOf CheckedPendingChangesChanged
MyBase.Dispose()
End Sub

Upgrading to Team Foundation Server 2008 Workgroup Edition

This week I took upon myself the challenge to upgrade our TFS 2005 SP1 single-server installation to the newly released 2008 version. When I was first introduced to our Team Foundation server it was running Beta 3 of TFS 2005. Since then it has mysteriously become my duty to upgrade to 2005 RTM, 2005 SP1, and now 2008 RTM.

I have gathered much needed experience on my previous upgrades to know how hard it would probably be. Beta 3 was originally running on SQL Server 2005 Developer Edition and the TFS beta wasn’t the Workgroup Edition. Needing to upgrade the beta database structures, switch the edition of SQL Server, and even migrate the whole lot to another physical machine has given me the confidence to deal with any TFS install.

I prepared for the 2008 upgrade by backing everything up, running the Best Practices Analyzer, then following the pre-upgrade checklist to the letter. So far everything is great. I inserted the TFS 2008 media, and began the setup. The setup prescan said everything was ok. It detected the existing installation, asked me for a few more settings (account passwords and mail server) then performed the upgrade.

Smooth. No errors. Database schema upgrade succeeded. And it was quick too. Again, I followed all the post-upgrade checklist items one-by-one and I was almost giddy at how easy it all was. I went back to my developer workstation and played around with work items and checked out and in some files. Perfect! I was so happy I went and upgraded our build servers too.

The next day my work colleague tried to undo a pending change and received a nasty error. The undo was failing and crashing the version control component on the server. I chased it down to the prc_iiUndoPendingChanges stored procedure experiencing a collation mismatch. The proc is encrypted but with SQL Profiler I was able to verify that it was a clashing collation between the TfsVersionControl database and SQL’s tempdb database.

How do you change the collation on the tempdb database to match the others? You don’t… you change the collation on the master database. How do you change the collation on the master database? You drop all your databases, rebuild the master using setup.exe on the SQL install media, then put all your databases back.

Still not that easy though. TFS 2008 requires SQL Server SP1. If you rebuild the master database with the RTM media you get an RTM master database. You can’t get or make SP1 slipstreamed install media and you can’t reapply SP1 after rebuilding master because all the other parts of SQL are already patched.

So, in the end you backup all your databases, uninstall all of SQL Server, reinstall it with the right collation, reapply the service pack, restore all your databases, rebuild the data warehouse and generally do all the rest of the necessary steps.

It was almost the perfect upgrade. Unfortunately collation settings were missed by the TFS team on one of their temp table definitions, it wasn’t picked up by testing, dogfooding, or the beta program, and I get all this hassle.

Still, all the new features in TFS 2008 make it worth it and I’d do it again. And will probably have to.

Code Camp SA: Mitch Denny

Mitch‘s presentation about “TFS Virtualization and Advanced Build Techniques” was my highlight for day one of Code Camp SA.

Mitch suggested that one of the major benefits of virtualizing Team Foundation Server was the ability to rollback the whole server at any point. While that is certainly helpful if the service packs don’t install right the first time, the benefit I’ve found personally is being able to pick up the whole VHD and drop it on another Virtual Server machine without any reconfiguration. Great for hardware failures.

Mitch also suggested getting a *big* server to host the virtual TFS and use the slack space to host additional virtual build servers. We toyed with a build server once and based on performance I figured a physical machine would be best but Mitch demonstrated a great idea combining multiple virtual build servers with a false TFS build agent to auto-redirect to a free, pre-cleaned build server.

In fact, the Readify team have some great TFS tools available to get the most from the system:

Mitch showed how, with these tools and some PowerShell glue, you can have a complete, automated process to go from a check-in, automatic build, to update dependencies, rebuild those, deploy for QA, then deploy to production. Nice.

With a lot of VB in our production code we’ve been held back from a CI system by the MSBuild secondary reference issue but a quick chat with Mitch after the presentation cleared that up:

Me: “Doctor, it hurts when I do this.”

Mitch: “Well, don’t do that.”