11 July 2014

TFS Equivalent of SVN Export

Here is a little trick to download the latest version of a source control folder from TFS. The idea is to use the Web Access API to retrieve the data.
Basically, you will get a Zip containing the HEAD version of the specified source control folder.

Here is the URL you have to use :


http://tfs-server:port/tfs/Collection/TeamProject/Team/_api/_versioncontrol/itemContentZipped?repositoryId=&path=url-encoded-source-control-path

The yellow parameters are mandatory, the green ones can be omitted.
Replace the parameters as described:
  • tfs-server is the TFS server hostname
  • port is the TFS port (usually 8080)
  • Collection is the name of your team project collection
  • TeamProject is the name of your team project
  • Team is the name of the team
  • url-encoded-source-control-path is the URL encoded source control path (for example, $/Project1/Main/Sources/Folder/SubFolder becomes %24%2FProject1%2FMain%2FSources%2FFolder%2FSubFolder
The main benefit of this URL is that it allows you to retrieve a source control folder without having to create workspaces and mappings (and thus avoiding the manual deletion of the associated $tf folders).

This URL is using Windows Authentication, so if you are using CURL (for example) on a non-Microsoft platform, you have to pass the --ntlm switch together with your windows credentials to retrieve the Zip package.

10 June 2014

About Release Management for TFS Update 2

If you plan on upgrading your Release Management installation from update 1 to update 2, here is a bit of advice:

Do not.

I tried in our internal installation, and everything broke down. The worst part was the TFS integration. It was no longer possible to link a TFS build definition to a release template, rendering them completely useless. And since RM for TFS is all about release template, the whole release infrastructure was absolutely blocked.

I will wait for the next update and hope Microsoft will fix these issues.

As a side note, deploying a brand new Update 2 installation did not fix the TFS issues, so apparently it is not related to the upgrade process.

07 January 2014

Completely remove an application tier from TFS 2012

If you ever wondered if it is possible to completely remove an application tier from the TFS Administration Console, here is an answer for you. Yes, but it is tricky and may result in a broken TFS installation. It involves messing with the catalog in the TFS_Configuration database.

As a disclaimer, this method is absolutely not supported. Not by me, not by my company, not by Microsoft. Use at your own risks.

So if you decide to reproduce the steps I am going to describe, please BACK UP your TFS installation (especially the Tfs_Configuration database).

Now, a little bit of context before starting, TFS uses a set of tables known as the catalog to keep track of the different pieces of your installation. It contains a lot of things including the databases, the servers, the web applications, etc.

Whenever you had a new piece to the installation (app tier, reporting tier, etc.) it goes into the catalog. Our problem is that for the moment there is no way to tell when you completely remove an app tier. So even if you uninstall an app tier, it stays in the catalog and eventually it will go out of sight thanks to the "Filter out machines that have not connected in more than 3 days".

Our goal here is to remove the app tier from the catalog itself. Unfortunately there is quite a bit of steps, and even more things to be aware of.

The first warning is that the steps below will produce the desired output only if you completely remove the server from the installation.

For example, consider a server APP-SERV1 hosting an app tier and another APP-SERV2 hosting an second app tier and SQL Server Analysis Services.

If you want to simply uninstall the app tier from APP-SERV2 but keep the SSAS on it, there is a high chance that this procedure will break your installation.

Actually this procedure removes the server from the catalog including all the other components that could have been part of the TFS installation (databases, reporting, datawarehouse, etc.).

Assuming TFS-APP is the server we'll remove, here is a high level list of the steps we will perform:
  • find the catalog resource for TFS-APP,
  • find the catalog resources for TFS-APP services,
  • find the catalog node for TFS-APP,
  • find the catalog nodes for TFS-APP services,
  • find the properties of TFS-APP,
  • find the catalog node dependencies for TFS-APP and services,
  • remove the items we found.

1. First things first, open a connection to your Tfs_Configuration database.

2. Then we start by looking for our server in the tbl_CatalogResource and tbl_CatalogNode tables:

SELECT 'Resource >'
     , r.*
     , 'Type >'
     , t.*
     , 'Node >'
     , n.*
  FROM [Tfs_Configuration].[dbo].[tbl_CatalogNode] n
  JOIN [Tfs_Configuration].[dbo].[tbl_CatalogResource] r
    ON r.Identifier = n.ResourceIdentifier
  JOIN [Tfs_Configuration].[dbo].[tbl_CatalogResourceType] t
    ON t.Identifier = r.ResourceType
 WHERE r.DisplayName = '{SERVER}' -- Replace with your server name

3. Note the value of the PropertyId, ParentPath, ChildItem, ResourceIdentifier fields. They will be used to identify and then delete the relevant data.

4. Select the properties associated with the catalog resource from the tbl_PropertyValue table.

SELECT * 
  FROM [Tfs_Configuration].[dbo].[tbl_PropertyValue]
 WHERE ArtifactId = '{PropertyId}' -- Replace with the value from step 3

5. Select the relevant items from the tbl_CatalogNodeDependency, we are looking for a) the items TFS-APP depends on, b) the items that depend on TFS-APP and its children:

-- a)
SELECT *
  FROM [Tfs_Configuration].[dbo].[tbl_CatalogNodeDependency]
 WHERE ParentPath = '{ParentPath}' --Replace with value from step 3
    AND ChildItem = '{ChildItem}' -- Replace with value from step 3

-- b)
SELECT *
  FROM [Tfs_Configuration].[dbo].[tbl_CatalogNodeDependency]
 WHERE RequiredParentPath LIKE '{ParentPath}{ChildItem}%' -- Replace with values from step 3

6. The records returned by a) will be removed in the end.

7. From the results returned by b) note the values of the RequiredParentPath and RequiredChilditem

Warning: If the app tier was the only TFS component installed on the server, you should only have the "WebApplication" value  in the AssociationKey field, otherwise it means you had other components like databases or datawarehouse installed on the server. In this case, I recommend you make sure you understand the implications. For example, make sure the reports and warehouse were already migrated to another server (check in the TFS Administration Console).

8. Select the APP-SERVER children:


SELECT 'Resource >'
     , r.*
     , 'Type >'
     , t.*
     , 'Node >'
     , n.*
  FROM [Tfs_Configuration].[dbo].[tbl_CatalogNode] n
  JOIN [Tfs_Configuration].[dbo].[tbl_CatalogResource] r
    ON r.Identifier = n.ResourceIdentifier
  JOIN [Tfs_Configuration].[dbo].[tbl_CatalogResourceType] t
    ON t.Identifier = r.ResourceType
 WHERE r.ParentPath = '{RequiredParentPath}' -- Replace with value from step 7
   AND r.ChildItem = '{RequiredChildItem}' -- Replace with value from step 7

9. Note the values of PropertyId, ParentPath, ChildItem, ResourceIdentifier.

10. We have everything we need to start the actual removal of the server.

-- Delete property values
DELETE FROM [Tfs_Configuration].[dbo].[tbl_PropertyValue] WHERE ArtifactId IN ({PropertyId}) -- Replace with values from steps 3 and 9

-- Delete dependencies for TFS-APP
DELETE FROM [Tfs_Configuration].[dbo].[tbl_CatalogNodeDependency]
 WHERE ParentPath = '{ParentPath}'
   AND ChildItem = '{ChildItem}' -- Replace with values from step 3

-- Delete dependencies to TFS-APP and services (Web application)
DELETE FROM [Tfs_Configuration].[dbo].[tbl_CatalogNodeDependency]

 WHERE RequiredParentPath LIKE '{ParentPath}{ChildItem}%' -- Replace with values from step 3

-- Delete nodes
DELETE FROM [Tfs_Configuration].[dbo].[tbl_CatalogNode]
 WHERE ParentPath = '{ParentPath}'
   AND ChildItem = '{ChildItem}' -- Replace with values from step 3 and 9

-- Delete resources
DELETE FROM [Tfs_Configuration].[dbo].[tbl_CatalogResource]
 WHERE Identifier IN ({ResourceIdentifier}) -- Replace with values from 3 and 9

11. Open the TFS Administration Console, you should now see only the active app tiers in the Application Tiers section even if you uncheck the "Filter out..." checkbox.
If the list is empty, it means the catalog is broken and TFS cannot rebuild the dependencies. This can happen if you forgot to delete a dependency on a deleted node.
To find the source of the problem, open the Event Viewer, you should see some TFS Service errors with the following message:
TF246024: An error occured while attempting to build catalog nodes. A catalog node is missing the following path to its parent: [parent path].

One possible solution would be to find the tbl_CatalogNodeDependency record with the RequiredParentPath set to the value in the error message, and then delete the record.

Error when running the TFS Best Practices Analyzer with an account containing a dollar ($) sign

I recently tried to run the TFS BPA using an account containing a dollar ($) sign. It was something like "user$name".
I ended up with a rather strange error message looking like the following:

Cannot validate the URL provided The scan was generated using the corrected URL "%TFSServerURLValidated%".

A quick look at the "Other reports" section of the scan results, I found that the tool was trying to find files in the following directory:

c:\Users\user\AppData\Roaming\Microsoft\TfsBpa\[...]

The important part is highlighted.
It seems that some of the PowerShell scripts are analyzing the account name as the literal user followed by a variable named $name, instead of interpreting the whole account name as a literal.

As I didn't want to go through the various PS scripts in the BPA installation directory, I decided to take the lazy approach.
I created a symbolic link C:\Users\user pointing to C:\Users\user$name\ using the following command:

mklink /d \Users\user \Users\user$name

After that the BPA was able to perform the checks as expected.
Of course it is not a long term solution and it works only for my account, but still easier than scanning all the ps1 files to find the culprit.

26 September 2013

Error TF400324 when starting the Visual Studio Test Controller

I recently had a problem starting the Test Controller Configuration Tool. There was no error, but it simply hung on the loading state. A quick look at the event log showed three errors. The most important one was:
The Controller service could not be started. TF400324: Team Foundation services are not available from server: [redacted URL]

The URL was referring to an old team project collection. I actually wanted to use the Configuration Tool to change this URL.

Since I could not attach the controller to another collection by using the Configuration Tool, I started to look around to find where the configuration itself was stored. The answer is an XML file named QTControllerConfig.xml located in C:\Program Files (x86)\Microsoft Visual Studio 11.0\Common7\IDE.
I opened the file, replaced the content with this:
<?xml version="1.0" encoding="UTF-8"?>
<ControllerConfiguration xmlns="http://microsoft.com/schemas/VisualStudio/TeamTest/2010/QTControllerConfig.xsd">
  <TestEnvironments>
    <TestEnvironment name="Default" id="8869bc36-5a69-4901-b46a-a38dfbd2ed06">
      <Description>Default Test Environment</Description>
      <MachineRoles>
        <MachineRole name="Default" id="dc134fe8-3c53-42e4-bcc1-6f2392e2fb8c" />
      </MachineRoles>
    </TestEnvironment>
  </TestEnvironments>
  <Properties>
    <Property name="MaxAgentVersionOnController" value="11.0.60610" />
  </Properties>
</ControllerConfiguration>
After that, I tried to open the Configuration Tool again and it worked.

For the record, updating the URL to the intended one did not work because the test controller itself was not yet registered.

28 June 2013

Visual Studio TFS 2012 and Web Deployment Packages

If you have been using Visual Studio 2010 and TFS to build Web Deployment packages (usable with MS Deploy), there is in the project properties a parameter for the name of the Web application in IIS.
The parameter is available in the Package/Publish Web section under IIS Web site/application name to use on the destination server.
Unfortunately this parameter is not available in Visual Studio 2012.
You can specify it when using the Publish feature (by right-clicking on the project) but if you want to set up builds in TFS, you will end up with an application in IIS with a _deploy suffix.

One possible solution is to add an additional parameter to the MSBuild command to update the IIS Web Application name.
In the process properties of the build definition, update the DeployIisAppPath in the MSBuild arguments:
MSBuild additional arguments

Entity Framework and TFS Build

I recently had an issue when trying to configure automatic deployments in TFS.
I was building a MS Deploy package with one build definition and deploying it with another.
The application was based on ASP.NET MVC with Entity Framework as a ORM
When I tried to open the application on the target server, I got an error "Unable to load the specified metadata resource".

The entity data model was configured to store the model files as resources into the assembly. The error was caused by the fact that the build process was no longer executing the packaging step. Usually Visual Studio does it automatically for you but MSBuild is not so kind. You have to manually tell it to execute the EntityDeploy step.

I added an instruction in the project file (containing the data model) to execute the packaging step.

<Target Name="AfterBuild">
  <EntityDeploy Sources="Models\DataModel.edmx" outputPath=".">
  </EntityDeploy>
</Target>

After that I made sure the build definition specified the MSBuild switch to rebuild the binaries (and not just build).

25 April 2012

.NET 4.0 version of InformationBox

At long last, a .NET 4.0 version of InformationBox was published on CodePlex!
As you might expect, it now supports the optional and named parameters making it a little easier to read the code.

You can grab the latest source code release from here: http://infobox.codeplex.com/SourceControl/list/changesets

08 August 2011

DateTimePicker and DateTime.MaxValue

For some unknown reason, the Winforms DateTimePicker control does not allow for dates higher than 9998-12-31. Trying to set the DateTimePicker MaxDate property of DateTime.MaxValue will result in an exception. This is a limitation imposed by the component itself.

Good news is there is a small trick to overcome this limitation. It requires to update the static MaxDateTime property to an arbitrary value (DateTime.MaxValue in our case). Lets put up some reflection code for that purpose:

var dtpType = typeof(DateTimePicker);
var field = dtpType.GetField("MaxDateTime"BindingFlags.Public | BindingFlags.Static);
if (field != null)
{
    field.SetValue(new DateTimePicker(), DateTime.MaxValue);
}

Just copy and paste this code into the startup method. Basically it needs to run before any DateTimePicker control is created.

Please note that running this code can have side effects because it is not known why this limitation is present in the first place. Use it at your own risk.

13 September 2010

Create UserControl with inline content

Let's say you want to create a user control that contains some literal text:
<uc1:InlineContent>
    This is some standard text message
</uc1:InlineContent>
Here is the simplest UserControl that matches this description:
using System.Web.UI;

[ParseChildren(ChildrenAsProperties = true,
               DefaultProperty = "Content")]
public partial class InlineContent : System.Web.UI.UserControl
{
    [PersistenceMode(
        PersistenceMode.EncodedInnerDefaultProperty)]
    public string Content { get; set; }
}