This recipe outlines how to configure Team Build, Sandcastle and the Sandcastle Help File Builder (SHFB) to generate MSDN-style documentation for assemblies.

The usual way to configure SHFB is to open the GUI and create a SHFB project file from your solution file with your desired configuration. Then you’re supposed to check this file into source control and maintain it each time you add a new assembly.

This recipe outlines a possibly simpler approach - it uses a common SHFB project template file and passes the assemblies that Team Build generates as arguments to the SandcastleBuilderConsole.exe program. This means it automatically includes all assemblies that have been built.

Once the documentation has been built, it is copied to the Team Build drop location along with the binaries.


Add to TFSBuild.proj as an override of the GenerateDocumentation target


The following pre-requisite software is required for the build server:
  • Sandcastle Jan 2008 Release from Sandcastle project on Codeplex
  • Sandcastle Help File Builder Installer from SHFB project on Codeplex
  • Html Help Workshop from Microsoft HTML Help Downloads
  • MSBuild Community Tasks MSI from



<Import  Project="$(MSBuildExtensionsPath)\MSBuildCommunityTasks\MSBuild.Community.Tasks.Targets"/>
 <Target Name="GenerateDocumentation">
   <!-- Find all assemblies in the output directory -->
   <CreateItem Include="$(OutDir)*.dll">
     <Output ItemName="Assemblies" TaskParameter="Include" />
   <!-- Document assemblies that have corresponding XML documentation files -->
   <CreateItem Include="@(Assemblies)"
     <Output ItemName="AssembliesToDocument" TaskParameter="Include" />
   <!-- Include assemblies that are missing XML documentation files as dependencies -->
   <CreateItem Include="@(Assemblies)"
     <Output ItemName="DependenciesToDocument" TaskParameter="Include" />
     <SandcastleBuidlerPath>C:\Program Files\EWSoftware\Sandcastle Help File Builder\SandcastleBuilderConsole.exe</SandcastleBuidlerPath>
     <!-- Sandcastle Builder project file and template -->
     <!-- @(AssembliesToDocument -> '-assembly=&quot;%(RelativeDir)%(Filename).dll&quot;',' ') -->
     <!-- This transform does the following: -->
     <!-- Take all the XML files found and replace the extension with .DLL.
          Add a -assembly=" to the start of each one and add a "[space] to the end of each one -->
     <!-- MSBuild Transforms: -->
     <!-- HACK: For some reason the -outputpath argument requires a '.' on the end,
          otherwise you get BUILD FAILED: Illegal characters in path. -->
     <SandcastleBuilderArguments>@(AssembliesToDocument -> '-assembly=&quot;%(RelativeDir)%(Filename).dll&quot;',' ') @(DependenciesToDocument -> '-dependency=&quot;%(RelativeDir)%(Filename).dll&quot;',' ') -outputpath=&quot;$(OutDir).&quot;</SandcastleBuilderArguments>
   <!-- Check if builder and files exist -->
   <Error Text="Sandcastle Help File Builder is not found at $(SandcastleBuidlerPath)."
          Condition="!Exists('$(SandcastleBuidlerPath)')"  />
   <Error Text="Sandcastle Help File Builder project template is not found at $(SandcastleBuilderProjectTemplateFile)."
          Condition="!Exists('$(SandcastleBuilderProjectTemplateFile)')" />
   <!-- Copy template project file to build folder -->
   <Copy SourceFiles="$(SandcastleBuilderProjectTemplateFile)"
         DestinationFiles="$(SandcastleBuilderProjectFile)" />
   <!-- Update documentation properties with build variables -->
   <XmlUpdate XPath="/project/HelpTitle" XmlFileName="$(SandcastleBuilderProjectFile)" Value="Documentation for $(BuildDefinition)" />
   <XmlUpdate XPath="/project/HtmlHelpName" XmlFileName="$(SandcastleBuilderProjectFile)" Value="$(BuildDefinition)" />
   <XmlUpdate XPath="/project/FooterText" XmlFileName="$(SandcastleBuilderProjectFile)" Value="Build Number: $(BuildNumber)" />
   <Exec Command="&quot;$(SandcastleBuidlerPath)&quot; &quot;$(SandcastleBuilderProjectFile)&quot; $(SandcastleBuilderArguments)" />


Because the drop location is a network share, the viewing of CHM files is often blocked. This is because network shares fall into the “Intranet” security zone, which isn’t trusted.

There are two options for getting around this:
  1. Copy the documentation file to your local machine, right-click, select properties, select Unblock.
  2. Or disable blocking for the Intranet zone by creating the following registry key. (

Windows Registry Editor Version 5.00


Last edited Nov 2, 2010 at 6:14 PM by wbarthol, version 2


No comments yet.