<?xml version="1.0" encoding="utf-8"?>
<rss xmlns:atom="https://www.w3.org/2005/Atom" xmlns:sy="https://purl.org/rss/1.0/modules/syndication/" xmlns:dc="https://purl.org/dc/elements/1.1/" xmlns:content="https://purl.org/rss/1.0/modules/content/" xmlns:wfw="https://wellformedweb.org/CommentAPI/" xmlns:slash="https://purl.org/rss/1.0/modules/slash/"
  version="2.0">
  <channel>
    <title>Jim Lamb</title>
    <atom:link
      href="https://docs.microsoft.com/archive/blogs/jimlamb/feed.xml"
      rel="self"
      type="application/rss+xml" />
    <link>https://docs.microsoft.com/archive/blogs/jimlamb/feed.xml</link>
    <description>Program Manager for Team Foundation Server.
This content is provided &amp;ldquo;AS IS&amp;rdquo; with no warranties and confers no rights.</description>
    <lastBuildDate>Tue, 16 Apr 2019 05:12:35 GMT</lastBuildDate>
    <language>en-US</language>
    <sy:updatePeriod>hourly</sy:updatePeriod>
    <sy:updateFrequency>1</sy:updateFrequency>
    <item>
      <title>Building in Parallel Across Multiple Build Agents with TFS 2010</title>
      <link>https://docs.microsoft.com/archive/blogs/jimlamb/building-in-parallel-across-multiple-build-agents-with-tfs-2010</link>
      <pubDate>Tue, 14 Sep 2010 07:53:00 GMT</pubDate>
      <dc:creator><![CDATA[Jim Lamb]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/jimlamb/2010/09/14/building-in-parallel-across-multiple-build-agents-with-tfs-2010/</guid>
      <description><![CDATA[One of our developers, Patrick Carnahan, has put together a customized build process template that...]]></description>
      <content:encoded><![CDATA[<p>One of our developers, <a title="Patrick Carnahan&#39;s MSDN Blog" href="https://blogs.msdn.com/b/patcarna/" target="_blank">Patrick Carnahan</a>, has put together a customized build process template that parallelizes a build by platform/configuration. That is, if you use it to build multiple platforms (e.g. “x86” and “x64”) and/or configurations (e.g. “Debug” and “Release”), it will distribute the build of each platform/configuration to a separate <a href="https://msdn.microsoft.com/en-us/library/bb399135.aspx" target="_blank">Build Agent</a>.</p>  <p>You can download the template from the MSDN Code Gallery: <a title="Download the Parallel Process Template from MSDN Code Gallery" href="https://code.msdn.microsoft.com/Project/Download/FileDownload.aspx?ProjectName=TfsSdk&amp;DownloadId=13825" rel="enclosure">ParallelTemplate.xaml</a></p>  <p>Once you’ve downloaded the template, you’ll need to add it to your version control repository before you can use it with your build definitions. Just follow these steps to get started:</p>  <ol>   <li>Open Visual Studio 2010 and connect to your Team Project Collection</li>    <li>Open Source Control Explorer and navigate to the location of your build process templates (e.g. $/<em>Project</em>/BuildProcessTemplates).</li>    <li>Copy the ParallelTemplate.xaml file to the folder on your local disk that this version control folder is mapped to. In Source Control Explorer, you’ll see a link to this folder labeled Local Path. Clicking the link will open Windows Explorer on that folder.</li>    <li>Right click on an empty area of the contents pane and select <strong>Add Items to Folder…</strong>       <br />      <br /><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/57/97/metablogapi/2313.image_258DF31B.png" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/CommunityServer-Blogs-Components-WeblogFiles/00-00-00-57-97-metablogapi/2313.image_5F00_258DF31B.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/57/97/metablogapi/7271.image_thumb_3615C83C.png" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/CommunityServer-Blogs-Components-WeblogFiles/00-00-00-57-97-metablogapi/7271.image_5F00_thumb_5F00_3615C83C.png" width="441" height="450" /></a></li>    <li>The <strong>Add To Source Control</strong> dialog will open. It will automatically hide any files that are already checked in, so you should only see the ParallelTemplate.xaml file that you just copied to this folder.      <br />      <br /><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/57/97/metablogapi/8741.image_06E3DCA5.png" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/CommunityServer-Blogs-Components-WeblogFiles/00-00-00-57-97-metablogapi/8741.image_5F00_06E3DCA5.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/57/97/metablogapi/3542.image_thumb_69AE0ECD.png" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/CommunityServer-Blogs-Components-WeblogFiles/00-00-00-57-97-metablogapi/3542.image_5F00_thumb_5F00_69AE0ECD.png" width="582" height="450" /></a></li>    <li>Click <strong>Next</strong> and you’ll be asked to confirm the operation – click <strong>Finish</strong> to pend the add.      <br />      <br /><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/57/97/metablogapi/0246.image_6507DE46.png" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/CommunityServer-Blogs-Components-WeblogFiles/00-00-00-57-97-metablogapi/0246.image_5F00_6507DE46.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/57/97/metablogapi/8357.image_thumb_1C01BC80.png" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/CommunityServer-Blogs-Components-WeblogFiles/00-00-00-57-97-metablogapi/8357.image_5F00_thumb_5F00_1C01BC80.png" width="582" height="450" /></a></li>    <li>Right click on the file and select <strong>Check In Pending Changes…</strong> Enter an appropriate check-in comment and commit the add.      <br />      <br /><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/57/97/metablogapi/6114.image_1FBF6150.png" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/CommunityServer-Blogs-Components-WeblogFiles/00-00-00-57-97-metablogapi/6114.image_5F00_1FBF6150.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/57/97/metablogapi/2477.image_thumb_3293E4FA.png" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/CommunityServer-Blogs-Components-WeblogFiles/00-00-00-57-97-metablogapi/2477.image_5F00_thumb_5F00_3293E4FA.png" width="441" height="450" /></a></li>    <li>Next, create a new Build Definition, or edit an existing one. Select the <strong>Process</strong> page of the Build Definition Editor and click the <strong>Show Details</strong> button to see the details of the currently selected build process template. You’ll need to click <strong>New…</strong> to select the XAML file you just checked into version control.      <br />      <br /><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/57/97/metablogapi/8345.image_0F83738A.png" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/CommunityServer-Blogs-Components-WeblogFiles/00-00-00-57-97-metablogapi/8345.image_5F00_0F83738A.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/57/97/metablogapi/8838.image_thumb_174B662C.png" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/CommunityServer-Blogs-Components-WeblogFiles/00-00-00-57-97-metablogapi/8838.image_5F00_thumb_5F00_174B662C.png" width="543" height="450" /></a>      <br />      <br />Click the <strong>Select an existing XAML file</strong> radio button and click <strong>Browse…</strong> to browse for the ParallelTemplate.xaml file you just checked in.</li>    <li>The build process parameters for the Parallel Template are the same as the ones for the Default Template, so no other changes are required to your existing build definition.</li> </ol>  <p>Things to keep in mind when using this build process template:</p>  <ul>   <li>Builds are parallelized by platform/configuration so, if you’re only building one platform/configuration, your build won’t be distributed across multiple Build Agents.</li>    <li>You’ll need more than one Build Agent available for this build process to parallelize your build. Keep in mind that you can configure multiple Build Agents on a single physical machine – appropriate if the machine has multiple processor cores. Note that you may want to configure each Build Agent to use a working directory on a separate physical disk, if multiple local disks are available.</li> </ul>]]></content:encoded>
    </item>
    <item>
      <title>Windows Workflow vs. MSBuild in TFS 2010</title>
      <link>https://docs.microsoft.com/archive/blogs/jimlamb/windows-workflow-vs-msbuild-in-tfs-2010</link>
      <pubDate>Wed, 09 Jun 2010 07:40:54 GMT</pubDate>
      <dc:creator><![CDATA[Jim Lamb]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/jimlamb/2010/06/09/windows-workflow-vs-msbuild-in-tfs-2010/</guid>
      <description><![CDATA[I often hear people asking if Windows Workflow replaces MSBuild in TFS 2010, so I wanted to take a...]]></description>
      <content:encoded><![CDATA[<p>I often hear people asking if Windows Workflow replaces MSBuild in TFS 2010, so I wanted to take a moment to comment on this question.</p> <!--more-->  <p></p>  <p>We haven't replaced MSBuild with Windows Workflow (WF). We still very much rely on MSBuild as the core build engine, which is it's core competency. You'll find that there are lots of tasks that are still most easily and effectively automated with MSBuild. In fact, for the next release of Visual Studio, we're working with the MSBuild team to replace solution (.sln) files with MSBuild project files.</p>  <p>We introduced WF as a way of providing a higher level orchestration layer on top of the core build engine (which is MSBuild in the build process templates we include in the box). It makes it possible to do things like distribute a process across multiple machines and to tie the process into other workflow-based processes.</p>  <p>So, when should you automate with MSBuild and when should you automated with WF? Here's my general guidance on that subject:</p>  <ul>   <li>If the task requires knowledge of specific build inputs or outputs, use MSBuild </li>    <li>If the task is something you need to happen when you build in Visual Studio, use MSBuild </li>    <li>If the task is something you only need to happen when you build on the build server, use WF unless it requires knowledge of specifi build inputs/outputs </li> </ul>  <p>When using MSBuild, remember that you can customize your project files directly (by unloading them and then editing them in Visual Studio), or you can create custom .targets files and import them into your individual projects. The latter approach is useful for functionality that's common to multiple projects to avoid maintaining multiple copies.</p>  <p>When using WF, remember that you can write code activities for low-level tasks but that you can also compose higher-level tasks using straight XAML. We're actually working on a version of the default build process template that shipped with TFS 2010 that gives you a simpler, less granular view of the overall process by using a set of composed XAML activities.</p></!--more-->]]></content:encoded>
    </item>
    <item>
      <title>Turn on Compile-time View Checking for ASP.NET MVC Projects in TFS Build 2010</title>
      <link>https://docs.microsoft.com/archive/blogs/jimlamb/turn-on-compile-time-view-checking-for-asp-net-mvc-projects-in-tfs-build-2010</link>
      <pubDate>Tue, 20 Apr 2010 08:35:41 GMT</pubDate>
      <dc:creator><![CDATA[Jim Lamb]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/jimlamb/2010/04/20/turn-on-compile-time-view-checking-for-asp-net-mvc-projects-in-tfs-build-2010/</guid>
      <description><![CDATA[When you create a View for an ASP.NET MVC web application, you add an .ASPX or .ASCX file that uses...]]></description>
      <content:encoded><![CDATA[<p>When you create a View for an ASP.NET MVC web application, you add an .ASPX or .ASCX file that uses the ASP.NET engine to render a combination of mark-up and code. Unfortunately, those Views don’t get compiled until IIS renders them for your web site which means that something as simple as a typo in a namespace could break your site. You could manually visit each and every view to verify that it compiles successfully or you could create automated UI tests that do it for you. Fortunately, there’s an easier way to verify your views at compile-time.</p>  <p>To let you detect these errors at compile time, ASP.NET MVC projects now include an <em>MvcBuildViews</em> property, which is disabled by default. To enable this property, open the project file and set the <em>MvcBuildViews</em> property to <em>true</em>, as shown in this example from the ASP.NET MVC Release Notes:</p>  <pre class="brush: xml">&lt;PropertyGroup&gt;
  &lt;MvcBuildViews&gt;true&lt;/MvcBuildViews&gt;
&lt;/PropertyGroup&gt;</pre>

<p><strong>Note</strong> that enabling this feature will add some overhead to your build process.</p>

<p>Unfortunately, this feature won’t work out of the box with TFS Build 2010 because of the way the post-build processing is done. If you look at the .csproj file for your ASP.NET MVC project, you’ll see an overridden <em>AfterBuild</em> target that invokes the <em>AspNetCompiler</em> task on your web application project’s sources. The problem here is two-fold:</p>

<ol>
  <li>The <em>AfterBuild</em> target shouldn’t be overridden directly since that’s reserved for end-user post-build processing. </li>

  <li>The <em>PhysicalPath</em> attribute passed to the <em>AspNetCompiler</em> task needs to be updated to a value that will work both locally and on the build server. </li>
</ol>

<p>Fortunately, both of these issues are easily resolved. In the example below, I’ve introduced a new <em>BuildViews</em> target that will only execute if the <em>MvcBuildViews</em> property is set to <em>true</em>. It also takes advantage of a new feature in MSBuild 4.0 that simplifies the task of injecting a custom target into the dependency chain. The <em>AfterTargets</em> attribute tells MSBuild to execute this target after the Build target has finished. For the <em>PhysicalPath</em> attribute on the <em>AspNetCompiler</em> task, I’ve used <em>WebProjectOutputDir</em> which is defined in Microsoft.WebApplication.targets as a location that resolves correctly for builds in both Visual Studio and TFS.</p>

<pre class="brush: xml">&lt;Target Name=&quot;BuildViews&quot; Condition=&quot;'$(MvcBuildViews)'=='true'&quot; AfterTargets=&quot;Build&quot;&gt;
  &lt;Message Importance=&quot;normal&quot; Text=&quot;Precompiling views&quot; /&gt;
  &lt;AspNetCompiler VirtualPath=&quot;temp&quot; PhysicalPath=&quot;$(WebProjectOutputDir)&quot; /&gt;
&lt;/Target&gt;</pre>

<p><strong>Note</strong> that after adding this custom target at an appropriate location in your web application’s project (.csproj) file (I’d recommend placing it just above the <em>AfterBuild</em> target, you’ll want to comment out the <em>AfterBuild</em> target.</p>

<p>Now, if you have an error in one of your views, it will show up as a compile-time error in Visual Studio and in your TFS builds. If you don’t want to take the performance hit of the additional compilation step, you can conditionally set the <em>MvcBuildViews</em> property to true for a specific configuration only (e.g. Release).</p>]]></content:encoded>
    </item>
    <item>
      <title>CustomizableOutDir in TFS 2010</title>
      <link>https://docs.microsoft.com/archive/blogs/jimlamb/customizableoutdir-in-tfs-2010</link>
      <pubDate>Tue, 13 Apr 2010 13:26:48 GMT</pubDate>
      <dc:creator><![CDATA[Jim Lamb]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/jimlamb/2010/04/13/customizableoutdir-in-tfs-2010/</guid>
      <description><![CDATA[Aaron Hallberg had previously blogged about Preserving Output Directory Structures in Orcas Team...]]></description>
      <content:encoded><![CDATA[<p><a href="https://blogs.msdn.com/aaronhallberg/default.aspx">Aaron Hallberg</a> had previously blogged about <a href="https://blogs.msdn.com/aaronhallberg/archive/2007/06/07/preserving-output-directory-structures-in-orcas-team-build.aspx">Preserving Output Directory Structures in Orcas Team Build</a>. The approach he described allows you to work around the problem of having all of your build outputs dumped into a single directory. Unfortunately, things have changed in TFS 2010 and the approach he describes is no longer applicable. There is, however, a way to achieve similar results with a small customization of the default build process template.</p>  <p>The key is the second invocation (the first invokes the “clean” target) of the MSBuild activity which builds a particular solution/project. You’ll need to modify this invocation as follows:</p>   <pre class="brush: xml">&lt;mtbwa:MSBuild 
  CommandLineArguments=&quot;[String.Format(&amp;quot;/p:SkipInvalidConfigurations=true;
    TeamBuildOutDir=&amp;quot;&amp;quot;{0}&amp;quot;&amp;quot; {1}&amp;quot;, 
      BinariesDirectory, MSBuildArguments)]&quot;
  Configuration=&quot;[platformConfiguration.Configuration]&quot; 
  DisplayName=&quot;Run MSBuild for Project&quot; 
  GenerateVSPropsFile=&quot;[True]&quot; 
  LogFileDropLocation=&quot;[logFileDropLocation]&quot; 
  OutDir=&quot;[outputDirectory]&quot; 
  Platform=&quot;[platformConfiguration.Platform]&quot; 
  Project=&quot;[localProject]&quot; 
  RunCodeAnalysis=&quot;[RunCodeAnalysis]&quot; 
  TargetsNotLogged=&quot;[New String() {
    &amp;quot;GetNativeManifest&amp;quot;, 
    &amp;quot;GetCopyToOutputDirectoryItems&amp;quot;, 
    &amp;quot;GetTargetPath&amp;quot;}]&quot; 
  ToolPlatform=&quot;[MSBuildPlatform]&quot; 
  Verbosity=&quot;[Verbosity]&quot; /&gt;</pre>

<p>Note that I’ve changed the <strong>CommandLineArguments</strong> attribute by setting a <strong>TeamBuildOutDir</strong> property and <em>removing</em> the <strong>OutDir</strong> property. This will set a global property named <strong>TeamBuildOutDir</strong> to the output directory that TFS Build <em>would have</em> redirected all of your build outputs to originally. You can then use that property to selectively copy your build outputs in a manner of your own choosing. For example, if you wanted to simply organize your outputs by solution and project, you could configure each project’s OutputPath as follows:</p>

<pre class="brush: xml">&lt;OutputPath Condition=&quot;'$(TeamBuildOutDir)'=='' &quot;&gt;
  bin\$(Configuration)\
&lt;/OutputPath&gt;
&lt;OutputPath Condition=&quot;'$(TeamBuildOutDir)'!='' &quot;&gt;
  $(TeamBuildOutDir)$(SolutionName)\$(ProjectName)\$(Configuration)
&lt;/OutputPath&gt;</pre>

<p>There are, of course, any number of ways you could implement this depending on your own requirements. For instance, I have a build definition that builds all of the samples for the TFS SDK and copies ZIP files (with the sources) for each solution and VSIX files (for solutions that generate them) to the drop location. If you generate an installer, you may only want to copy that to the drop location.</p>

<p>Note that, if you’re running automated unit tests during your build without a Test Metadata (.vsmdi) file, you’ll also need to customize the <strong>SearchPathRoot </strong>attribute on the invocation of the MSTest activity to get it to find your unit test assemblies.</p>]]></content:encoded>
    </item>
    <item>
      <title>Configuring Multiple TFS Build Services on one Machine</title>
      <link>https://docs.microsoft.com/archive/blogs/jimlamb/configuring-multiple-tfs-build-services-on-one-machine</link>
      <pubDate>Tue, 13 Apr 2010 11:53:11 GMT</pubDate>
      <dc:creator><![CDATA[Jim Lamb]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/jimlamb/2010/04/13/configuring-multiple-tfs-build-services-on-one-machine/</guid>
      <description><![CDATA[In TFS 2010, the Build Service is a Windows Service that is associated with a particular TFS Team...]]></description>
      <content:encoded><![CDATA[<p>In TFS 2010, the Build Service is a Windows Service that is associated with a particular TFS <a href="https://msdn.microsoft.com/en-us/library/dd236915.aspx">Team Project Collection</a>. Each Build Service support zero to one (0..1) Build Controllers and zero to <em>n</em> (0..n) Build Agents. Each Build Agent is associated to a specific Build Controller but an Agent and its corresponding Controller don’t need to be on the same machine. This topology lets you configure a continuous integration build that queues its builds on the Build Controller you’ve specified which then farms out the heavy lifting to any of the <em>n</em> agents it manages. This gives you an easy way to load balance your builds across a set of machines.</p>  <p>There is a potential down-side, however, in that each build service can only service one particular project collection. In TFS 2005 and 2008, a build agent was configured for a particular Team Project and you could only run one Build Agent per machine (though you could manually configure the same build agent for multiple Team Projects on the same server. Since you can have multiple Team Projects in a single Team Project Collection, the configuration experience has definitely improved in TFS 2010. That said, you may still find yourself needing to provide build services for multiple Project Collections from a single build machine. While I don’t recommend using this as a production configuration, it may be useful if you’re juggling multiple Project Collections on a machine that you’re using for demonstration purposes.</p>  <p><strong>Note: this is not a supported configuration of the TFS Build Service – use it at your own risk.</strong></p>  <ol>   <li>Open a Command Prompt window as Administrator on the build machine. </li>    <li>Use the command line interface to the Service Control Manager to setup a second named instance of the Build Service.      <br />      <br />E.g. sc.exe create buildMachine-collection2 binpath=&quot;C:\Program Files\Microsoft Team Foundation Server 2010\Tools\TfsBuildServiceHost.exe /NamedInstance:buildMachine-collection2&quot; DisplayName=&quot;Visual Studio Team Foundation Build Service Host (Collection2)&quot; <em>Note: For TFS 2012, you'll need to use the corresponding path to the executable.</em>      <br />      <br />We recommend including the Project Collection name in the display and instance names for this second instance of the Build Service to make it easier to determine which instance you’re managing. </li>    <li>Set the <strong>TFSBUILDSERVICEHOST</strong> environment variable to refer to the new instance of the Build Service you just created by setting its value to the string you passed in the <strong>NamedInstance</strong> parameter in step 2. <em>Note: For TFS 2012, the environment variable name is <strong>TFSBUILDSERVICEHOST.2012</strong>.</em>      <br />      <br />E.g. set TFSBUILDSERVICEHOST=buildMachine-collection2 </li>    <li>Start the Team Foundation Administration Console from the same command prompt so that it gets the environment variable you just set.      <br />      <br />E.g. &quot;C:\Program Files\Microsoft Team Foundation Server 2010\Tools\tfsmgmt.exe&quot; </li>    <li>Ensure that the new Build Service instance has a TFS resource Uri that is distinct from the originally configured Build Service. You can view the Uri in the <strong>Uri</strong> value under the following registry key:       <br />      <br />HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\10.0\TeamFoundation\Build\tfsbuildservicehost1       <br />      <br />If the Uri is the same as the one under the Build\ServiceHost registry key, you’ll need to unregister the new Build Service instance and re-register it. To do so, first you’ll need to create a new Controller or Agent for the new Build Service instance in the Team Foundation Administration console. Next, you’ll need to click <strong>Unregister</strong> to unregister the Build Service and delete its associated Controller and/or Agents. When you re-register it, it should get a new Id that won’t conflict with the originally configured Build Service instance. </li>    <li>Ensure that the new Build Service instance is configured to listen on a different port than the originally configured Build Service. You can do this by opening the Properties dialog for the Build Service and changing the port appropriately. </li>    <li>If you’re working in a demo environment and the project collections you’re configuring Build Services for are starting out in the same state, there’s a good chance that, if you configure a Build Controller for each of the two Build Service instances, the Build Controllers will both end up with the same Id due to the way the TFS database auto-increments identity columns. This is only an issue if you use the custom assembly path for both Build Controllers and they use a potentially conflicting set of content in that path. If that’s the case, you can remove one of the Build Controllers from one of the Build Service instances, then recreate it and it should get a different Id. </li>    <li>Update default working directory for the agents you create on each Build Service instance. If you don't, there’s a chance that two Build Agents (one under each Build Service instance) will have the same Id and, consequently, the same working directory. Update the working directory in the Agent Properties dialog to include the collection name or some other distinguishing element. E.g. $(SystemDrive)\Builds\$(BuildAgentId)_Coll2\$(BuildDefinitionPath). </li>    <li>If you’re using (or plan to use) the new Symbol Server integration features in TFS 2010, you’ll need to setup a separate Symbol Store for each Team Project Collection. Symbol Server does not support concurrent storage access. TFS Build handles this by synchronizing access to the Symbol Stores used within a given Team Project Collection. This synchronization doesn’t work across Collections, however, so you’ll need to maintain separate Symbol Server stores for each Collection – fortunately, this is just a shared directory. </li>    <li>Ensure that the drop folders used in the Build Definitions across Project Collections are different. In most cases, this won’t be a problem unless two projects have same name across Project Collections. </li>    <li>Before installing TFS hot-fix or service pack, please stop all Build Service instances manually from Service Control Manager and restart them after patch installation is successful. </li> </ol>  <p>When you’re done, you’ll have a single machine that is providing Build Services for two separate TFS Team Project Collections. If you want to run builds on both Build Service instances concurrently, you’ll want to take steps to prevent resource contention like moving the working directories for the Agent on one of the instances to a separate hard disk. Even then you may encounter serious performance degradation if two instances of MSTest are invoked at the same time.</p>  <p>Let me reiterate that this is a <strong>hack</strong> and is <strong>not a supported configuration</strong> of TFS Build 2010. If you believe you have legitimate need to apply this configuration to a production build environment, <a href="https://blogs.msdn.com/jimlamb/contact.aspx">contact me</a> and describe your scenario in detail.</p>]]></content:encoded>
    </item>
    <item>
      <title>Test Page</title>
      <link>https://docs.microsoft.com/archive/blogs/jimlamb/test-page</link>
      <pubDate>Tue, 13 Apr 2010 08:08:00 GMT</pubDate>
      <dc:creator><![CDATA[Jim Lamb]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/jimlamb/2010/04/13/test-page/</guid>
      <description><![CDATA[This is a test of some source code embedded from Gist


How does it look?]]></description>
      <content:encoded><![CDATA[<P>This is a test of some source code embedded from Gist</P>
<SCRIPT src="https://gist.github.com/364711.js?file=CreateParentChildWorkItemLink.cs" mce_src="https://gist.github.com/364711.js?file=CreateParentChildWorkItemLink.cs"></SCRIPT>

<P>How does it look?</P>]]></content:encoded>
    </item>
    <item>
      <title>Installing just the Server Components of TFS 2010</title>
      <link>https://docs.microsoft.com/archive/blogs/jimlamb/installing-just-the-server-components-of-tfs-2010</link>
      <pubDate>Tue, 06 Apr 2010 10:06:41 GMT</pubDate>
      <dc:creator><![CDATA[Jim Lamb]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/jimlamb/2010/04/06/installing-just-the-server-components-of-tfs-2010/</guid>
      <description><![CDATA[If you’re developing (or planning to develop) on the Team Foundation API and you want to get the...]]></description>
      <content:encoded><![CDATA[<p>If you’re developing (or planning to develop) on the Team Foundation API and you want to get the server assemblies installed on your machine in addition to the client assemblies that are included with Visual Studio, just follow these simple steps:</p>  <ul>   <li>Launch Setup from the TFS 2010 media </li>    <li>Navigate to the feature selection page of the Wizard </li>    <li>Select <strong>Team Foundation Components</strong> and de-select (uncheck) Team Foundation Server and Team Foundation Build Service as shown below:       <br /><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/BlogFileStorage/blogs_msdn/jimlamb/WindowsLiveWriter/InstallingjusttheServerComponentsofTFS20_B3F6/image_3.png" original-url="https://blogs.msdn.com/blogfiles/jimlamb/WindowsLiveWriter/InstallingjusttheServerComponentsofTFS20_B3F6/image_3.png" width="578" height="450" /> </li>    <li>Click <strong>Install</strong> </li> </ul>  <p>When you’re done, you’ll have the server components installed on your machine without the overhead of an application tier and build service. Now you can build things like custom warehouse adapters.</p>]]></content:encoded>
    </item>
    <item>
      <title>How to: Implement, package and deploy custom check-in policy for TFS 2010</title>
      <link>https://docs.microsoft.com/archive/blogs/jimlamb/how-to-implement-package-and-deploy-custom-check-in-policy-for-tfs-2010</link>
      <pubDate>Wed, 31 Mar 2010 10:48:59 GMT</pubDate>
      <dc:creator><![CDATA[Jim Lamb]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/jimlamb/2010/03/31/how-to-implement-package-and-deploy-custom-check-in-policy-for-tfs-2010/</guid>
      <description><![CDATA[This How to article walks you through the process of creating, packaging, deploying and applying a...]]></description>
      <content:encoded><![CDATA[<p>This How to article walks you through the process of creating, packaging, deploying and applying a custom check-in policy for TFS. Check-in policies let you run rules, whenever someone attempts to check-in a set of changes, to ensure that the changes meet a specific set of criteria. As an example, this article illustrates how to ensure that C# and VB.NET source files comply with formatting guidelines using the excellent .NET code organizer, formatter and beautifier, <a href="https://narrange.net/">NArrange</a>. To implement your own custom check-in policy, you create a class that derives from <a href="https://msdn.microsoft.com/en-us/library/microsoft.teamfoundation.versioncontrol.client.policybase.aspx">PolicyBase</a> and implements the <a href="https://msdn.microsoft.com/en-us/library/microsoft.teamfoundation.versioncontrol.client.ipolicydefinition.aspx">IPolicyDefinition</a> and <a href="https://msdn.microsoft.com/en-us/library/microsoft.teamfoundation.versioncontrol.client.ipolicyevaluation.aspx">IPolicyEvaluation</a> interfaces. Once the assembly containing this class must be registered appropriately in the Microsoft Windows® registry, you can apply the policy to your team project.</p>  <h3>Before You Begin</h3>  <p>To complete this walkthrough, you’ll need the Edit project-level information permission for the Team Project you want to apply the check-in policy to. For more information, see <a href="https://msdn.microsoft.com/en-us/library/ms252587.aspx">Team Foundation Permissions</a>.</p>  <h3>Step 1 – Create and Build a Custom Policy Class</h3>  <p>In this initial step, you create a new class library and add a custom policy class by deriving from the PolicyBase base class in the Microsoft.TeamFoundation.VersionControl.Client namespace. By deriving from this base class, your class implements the IPolicyDefinition and IPolicyEvaluation interfaces. The example policy code below applies code formatting standards to each C# and VB.NET source file that's checked in using NArrange.</p>   <pre class="brush: csharp plain">namespace TeamFoundation.Samples.CheckinPolicies
{
    using System;
    using System.Collections.Generic;
    using System.IO;

    using Microsoft.TeamFoundation.VersionControl.Client;

    using NArrange.Core;

    [Serializable]
    public class ArrangePolicy : PolicyBase, ILogger
    {
        #region Fields

        [NonSerialized]
        IPendingCheckin _pendingCheckin;

        #endregion Fields

        #region Properties

        /// &lt;summary&gt;
        /// Gets a value indicating whether this check-in policy has an editable configuration
        /// &lt;/summary&gt;
        /// &lt;value&gt;&lt;c&gt;true&lt;/c&gt; if this instance can edit; otherwise, &lt;c&gt;false&lt;/c&gt;.&lt;/value&gt;
        public override bool CanEdit
        {
            get
            {
                return false;
            }
        }

        /// &lt;summary&gt;
        /// Gets the description.
        /// &lt;/summary&gt;
        /// &lt;value&gt;The description.&lt;/value&gt;
        public override string Description
        {
            get { return "Runs NArrange against any .cs and .vb files in your pending changes"; }
        }

        /// &lt;summary&gt;
        /// Gets the type.
        /// &lt;/summary&gt;
        /// &lt;value&gt;The type.&lt;/value&gt;
        public override string Type
        {
            get { return "NArrange Policy"; }
        }

        /// &lt;summary&gt;
        /// Gets the type description.
        /// &lt;/summary&gt;
        /// &lt;value&gt;The type description.&lt;/value&gt;
        public override string TypeDescription
        {
            get { return "This policy prevents users from checking in files that don't comply with your coding style guidelines."; }
        }

        #endregion Properties

        #region Methods

        /// &lt;summary&gt;
        /// Dispose method unsubscribes to the event so we don't get into 
        /// scenarios that can create null ref exceptions
        /// &lt;/summary&gt;
        public override void Dispose()
        {
            base.Dispose();
            _pendingCheckin.PendingChanges.CheckedPendingChangesChanged -= PendingChanges_CheckedPendingChangesChanged;
        }

        public override bool Edit(IPolicyEditArgs policyEditArgs)
        {
            // no policy settings to save
            return true;
        }

        /// &lt;summary&gt;
        /// Evaluates the pending changes for policy violations
        /// &lt;/summary&gt;
        /// &lt;returns&gt;&lt;/returns&gt;
        public override PolicyFailure[] Evaluate()
        {
            var failures = new List&lt;policyfailure&gt;();
            const String supportedSourceFileExtensions = ".cs;.vb";

            // get a temporary location to write out the configuration file for NArrange
            var configFilePath = Path.GetTempFileName();

            // get the configuration file from our resources and write it to disk
            using (var writer = new StreamWriter(configFilePath))
            {
                writer.Write(Resources.DefaultConfig);
            }

            // instantiate a new FileArranger - this is the engine for NArrange
            var fileArranger = new FileArranger(configFilePath, this);

            // process each file in the set of pending changes
            foreach (var pendingChange in PendingCheckin.PendingChanges.CheckedPendingChanges)
            {
                // invoke NArrange on C# and VB.NET source files only
                if (supportedSourceFileExtensions.Contains(Path.GetExtension(
                    pendingChange.LocalItem).ToLowerInvariant()))
                {
                    fileArranger.Arrange(pendingChange.LocalItem, pendingChange.LocalItem, true);
                }
            }

            // clean up the temporary copy of the configuration file
            File.Delete(configFilePath);

            return failures.ToArray();
        }

        /// &lt;summary&gt;
        /// Initializes this policy for the specified pending checkin.
        /// &lt;/summary&gt;
        /// &lt;param name=&quot;pendingCheckin&quot; /&gt;The pending checkin.&lt;/param&gt;
        public override void Initialize(IPendingCheckin pendingCheckin)
        {
            base.Initialize(pendingCheckin);

            _pendingCheckin = pendingCheckin;
            pendingCheckin.PendingChanges.CheckedPendingChangesChanged += PendingChanges_CheckedPendingChangesChanged;
        }

        /// &lt;summary&gt;
        /// Logs a message.
        /// &lt;/summary&gt;
        /// &lt;param name=&quot;level&quot; /&gt;Log level.&lt;/param&gt;
        /// &lt;param name=&quot;message&quot; /&gt;Log message.&lt;/param&gt;
        /// &lt;param name=&quot;args&quot; /&gt;Message arguments.&lt;/param&gt;
        public void LogMessage(LogLevel level, string message, params object[] args)
        {
        }

        /// &lt;summary&gt;
        /// Subscribes to the PendingChanges_CheckedPendingChangesChanged event 
        /// and reevaluates the policy. You should not do this if your policy takes 
        /// a long time to evaluate since this will get fired every time there is a
        /// change to one of the items in the pending changes window.
        /// &lt;/summary&gt;
        /// &lt;param name=&quot;sender&quot; /&gt;The source of the event.&lt;/param&gt;
        /// &lt;param name=&quot;e&quot; /&gt;The &lt;see cref=&quot;System.EventArgs&quot; /&gt; instance containing the event data.&lt;/param&gt;
        void PendingChanges_CheckedPendingChangesChanged(object sender, EventArgs e)
        {
            if (!Disposed)
            {
                OnPolicyStateChanged(Evaluate());
            }
        }

        #endregion Methods
    }
}</pre>

<p>Note that, for this check-in policy, I’ve added a copy of NArrange’s default configuration file (DefaultConfig.xml) as a file resource which I write out to disk when needed to pass to the FileArranger object.</p>

<h3>Step 2 – Package the Custom Check-in Policy</h3>

<p>The easiest way to package your check-in policy for deployment is to use <a href="https://msdn.microsoft.com/en-us/library/ff363239(v=VS.100).aspx">VSIX Deployment</a>. A VSIX package is a ZIP file that follows the Open Packaging Conventions (OPC) standard. The package contains binaries and supporting files, together with a <a href="https://msdn.microsoft.com/en-us/library/dd997170(v=VS.100).aspx">[Content_Types].xml</a> file and a .vsix manifest file. One VSIX package may contain the output of multiple projects, or even multiple packages that have their own manifests. For more information about the contents of a VSIX package, see <a href="https://msdn.microsoft.com/en-us/library/dd997148(v=VS.100).aspx">Anatomy of a VSIX Package</a>.</p>

<p>For this check-in policy, we’ll add a new <a href="https://msdn.microsoft.com/en-us/library/dd393742(v=VS.100).aspx">VSIX Project</a> to our solution as shown below:</p>

<p><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Add New VSIX Project" border="0" alt="Add New VSIX Project" src="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/BlogFileStorage/blogs_msdn/jimlamb/WindowsLiveWriter/HowtoImplementacustomcheckinpolicyforTFS_AF28/image_3.png" original-url="https://blogs.msdn.com/blogfiles/jimlamb/WindowsLiveWriter/HowtoImplementacustomcheckinpolicyforTFS_AF28/image_3.png" width="600" height="349" /></p>

<p>To get the required registry key created, we’ll need to add a pkgdef file to our VSIX package the tells it where to create the key and what value to set as shown below:</p>

<pre class="brush: plain">[$RootKey$\TeamFoundation\SourceControl\Checkin Policies]
&quot;TeamFoundation.Samples.CheckinPolicies&quot;=&quot;$PackageFolder$\TeamFoundation.Samples.CheckinPolicies.dll&quot;</pre>

<p>This creates a key for our assembly named after our namespace which will allow Team Explorer to locate our check-in policy. Note that everyone who will be checking in files affected by your check-in policy will need to install it on their machine(s). Luckily, installing VSIX packages is really easy. You just double click on the VSIX file (generated at build time by the VSIX Project) and you’ll see a dialog box like this:</p>

<p><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/BlogFileStorage/blogs_msdn/jimlamb/WindowsLiveWriter/HowtoImplementacustomcheckinpolicyforTFS_AF28/image_602dcb87-aa1c-45fd-8748-96d2a5e6379c.png" original-url="https://blogs.msdn.com/blogfiles/jimlamb/WindowsLiveWriter/HowtoImplementacustomcheckinpolicyforTFS_AF28/image_602dcb87-aa1c-45fd-8748-96d2a5e6379c.png" width="488" height="372" /> </p>

<p>You can edit the .vsixmanifest file in your VSIX Project to customize attributes of your package like the name, description, license, icon, preview image, etc.</p>

<h3>Step 3 – Apply the Custom Policy</h3>

<p>In this step you add the custom policy to your team project. This ensures that the policy is evaluated each time a developer checks in a file to this team project.</p>

<ol>
  <li>In <strong>Team Explorer</strong>, right-click your team project, point to <strong>Team Project Settings</strong> and then click <strong>Source Control</strong>. </li>

  <li>Click the <strong>Check-in Policy</strong> tab and then click <strong>Add</strong>. </li>

  <li>Select the <strong>NArrange Policy</strong> and click <strong>OK</strong> and then <strong>OK</strong> again. </li>
</ol>

<p>The policy is now applied each time a developer checks a file into this team project.</p>

<h4>Step 4 – Validate the Custom Policy</h4>

<p>In this step, you check-in a source file to ensure that the custom policy works correctly.</p>

<ol>
  <li>Make a change to a C# or VB.NET source file and then check-in the file. </li>

  <li>Verify that the source file is organized, formatted and beautified by NArrange. </li>
</ol>

<h3>Additional Resources</h3>

<p>You can download the sources for this check-in policy from <a href="https://code.msdn.microsoft.com/TfsSdk">Code Gallery</a> – <a title="direct link" href="https://code.msdn.microsoft.com/Project/Download/FileDownload.aspx?ProjectName=TfsSdk&amp;DownloadId=10207">CheckinPolicies.zip</a></p>]]></content:encoded>
    </item>
    <item>
      <title>Extending Team Projects and Team Explorer in TFS 2010</title>
      <link>https://docs.microsoft.com/archive/blogs/jimlamb/extending-team-projects-and-team-explorer-in-tfs-2010</link>
      <pubDate>Fri, 26 Feb 2010 09:49:57 GMT</pubDate>
      <dc:creator><![CDATA[Jim Lamb]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/jimlamb/2010/02/26/extending-team-projects-and-team-explorer-in-tfs-2010/</guid>
      <description><![CDATA[In this post, I’m going to walk you through a TFS SDK sample that extends Team Projects and Team...]]></description>
      <content:encoded><![CDATA[<p>In this post, I’m going to walk you through a <a href="https://code.msdn.microsoft.com/TfsSdk" target="_blank">TFS SDK</a> sample that extends Team Projects and Team Explorer in TFS 2010. This solution is implemented as a Visual Studio Industry Partner (VSIP) package and includes a Project Creation Wizard plug-in and a Team Explorer plug-in. To get started, just follow these steps:</p>  <ol>   <li>If you haven’t already, install Visual Studio 2010 SP1. </li>    <li>Download and install the <a href="https://www.microsoft.com/download/en/details.aspx?id=21835" target="_blank">Visual Studio 2010 SP1 SDK</a> since you won’t be able to build the sources without it. </li>    <li>Download an unzip the ExtendingTeamProjects sample from the <a href="https://code.msdn.microsoft.com/Release/ProjectReleases.aspx?ProjectName=TfsSdk" target="_blank">TFS SDK on Code Gallery</a>. </li>    <li>Open the solution, right click on the TeamProjectExtensionPackage project and select <strong>Properties</strong>. Select the <strong>Debug</strong> tab and, under “Start Action,” select <strong>Start External Program</strong> and specify the full path to Visual Studio 2010 (%ProgramFiles(x86)%\Microsoft Visual Studio 10.0\Common7\IDE\DevEnv.exe). Then, under “Start Options” specify the following command line arguments: <strong>/rootsuffix Exp</strong>. </li>    <li>Build the solution. </li>    <li>Start Debugging (F5) the solution – this will start a new instance of Visual Studio. </li> </ol>  <h3>Project Creation Wizard</h3>  <p>You see the Project Creation Wizard when you select <u>F</u>ile, <u>N</u>ew, <u>T</u>eam Project… from Visual Studio’s main menu. The wizard lets you specify a name and description for your new team project and then asks you to select a process template. Before you can try the sample out, you’ll need to upload the provided sample process template to your project collection by selecting Tea<u>m</u>, <u>T</u>eam Project Collection Settings, P<u>r</u>ocess Template Manager… and clicking <strong>Upload</strong> to browse for and upload the process template that’s included with the source code. When you start the sample in the Debugger (F5), it will spawn an experimental instance of Visual Studio with our package already installed and ready to go.</p>  <p><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="3-ProjectCreationWizard-ProcessTemplate" border="0" alt="3-ProjectCreationWizard-ProcessTemplate" src="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/BlogFileStorage/blogs_msdn/jimlamb/WindowsLiveWriter/ExtendTeamProjectsandTeamExplorerinTFS20_133FA/3-ProjectCreationWizard-ProcessTemplate_3.png" original-url="https://blogs.msdn.com/blogfiles/jimlamb/WindowsLiveWriter/ExtendTeamProjectsandTeamExplorerinTFS20_133FA/3-ProjectCreationWizard-ProcessTemplate_3.png" width="592" height="480" /> </p>  <p>For this sample, we have a custom process template that declares a special group ID that includes a task list from a separate XML file. That XML file includes a set of web links arranged in a folder structure. Those links are passed to our Project Creation Wizard plug-in as the new Team Project is getting created. The plug-in also adds a new page to the wizard that lets the user enter additional web links and, optionally, to add a link to the newly created Team Project in Web Access.</p>  <p><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="4-ProjectCreationWizard-LinksPlugin" border="0" alt="4-ProjectCreationWizard-LinksPlugin" src="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/BlogFileStorage/blogs_msdn/jimlamb/WindowsLiveWriter/ExtendTeamProjectsandTeamExplorerinTFS20_133FA/4-ProjectCreationWizard-LinksPlugin_c454a4eb-4ef8-4d86-a130-82336fd7abf2.png" original-url="https://blogs.msdn.com/blogfiles/jimlamb/WindowsLiveWriter/ExtendTeamProjectsandTeamExplorerinTFS20_133FA/4-ProjectCreationWizard-LinksPlugin_c454a4eb-4ef8-4d86-a130-82336fd7abf2.png" width="592" height="480" /> </p>  <p>This page derives from the TeamProjectWizardPage class which provides some handy methods to manage the state of the navigation buttons at the bottom of the wizard. The LinksProjectComponentCreator takes the links entered by the user, merges them with the links specified in the process template and stores an XML representation of the data in a property on the Team Project.</p>  <h3>Team Explorer</h3>  <p>Once your new Team Project has been created, you’ll see a new folder in Team Explorer called <strong>Links</strong> that shows the links that were specified in the sample process template as well as the links you entered when you went through the Project Creation Wizard. </p>  <p><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="TeamExplorer-Links" border="0" alt="TeamExplorer-Links" src="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/BlogFileStorage/blogs_msdn/jimlamb/WindowsLiveWriter/ExtendTeamProjectsandTeamExplorerinTFS20_133FA/TeamExplorer-Links_a8603ad3-31a3-4e45-afa6-723db8fffc81.png" original-url="https://blogs.msdn.com/blogfiles/jimlamb/WindowsLiveWriter/ExtendTeamProjectsandTeamExplorerinTFS20_133FA/TeamExplorer-Links_a8603ad3-31a3-4e45-afa6-723db8fffc81.png" width="243" height="384" /> </p>  <p>If you connect to another Team Project that doesn’t use the sample process template, you’ll notice that the Links folder does not appear. That’s because our Team Explorer plug-in implements the <strong>ITeamExplorerPluginFilter</strong> interface which lets us specify whether or not our plug-in should appear for a particular team project. The Team Explorer plug-in implements a context menu for the root Links node with a single command. It shows how to handle invocations of that command as well as how to handle activation of the links in the hierarchy it presents.</p>  <h3>Deployment</h3>  <p>When you build the solution, you’ll see that it creates a <a href="https://msdn.microsoft.com/en-us/library/ff363239(VS.100).aspx" target="_blank">VSIX</a> package which is a ZIP file that follows a particular set of conventions to make it easy to install into Visual Studio. To hand this extension off to a teammate, just give them access to the TeamProjectExtensionPackage.vsix file which you can find in the output directory. When they open that file, they can click <strong>Install</strong> to install the extension into Visual Studio.</p>  <p>If you have any questions or comments on this sample, please post below or <a href="https://blogs.msdn.com/jimlamb/contact.aspx" target="_blank">contact me</a>.</p>]]></content:encoded>
    </item>
    <item>
      <title>Create a Custom WF Activity to Sync Version and Build Numbers</title>
      <link>https://docs.microsoft.com/archive/blogs/jimlamb/create-a-custom-wf-activity-to-sync-version-and-build-numbers</link>
      <pubDate>Fri, 12 Feb 2010 13:08:00 GMT</pubDate>
      <dc:creator><![CDATA[Jim Lamb]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/jimlamb/2010/02/12/create-a-custom-wf-activity-to-sync-version-and-build-numbers/</guid>
      <description><![CDATA[Updated for TFS 2010 RTM!
One of the common requests we hear is to provide a way of automatically...]]></description>
      <content:encoded><![CDATA[<h3>Updated for TFS 2010 RTM!</h3>
<p>One of the common requests we hear is to provide a way of automatically updating the version information in the assemblies produced by a TFS build. Unfortunately, it&rsquo;s one of those features that never gets quite high enough on our priority list to get implemented. You may have noticed that we haven&rsquo;t provided a solution to this problem in TFS 2010 Beta 2, but this article is going to show you how to solve this problem yourself and will even give you the sources (see the attached ZIP file) for a working solution that you can start using today.</p>
<p><a href="https://www.wintellect.com/CS/blogs/jrobbins/archive/2009/11/09/tfs-2010-build-number-and-assembly-file-versions-completely-in-sync-with-only-msbuild-4-0.aspx" mce_href="https://www.wintellect.com/CS/blogs/jrobbins/archive/2009/11/09/tfs-2010-build-number-and-assembly-file-versions-completely-in-sync-with-only-msbuild-4-0.aspx"> John Robbins</a> at Wintellect recently blogged on how to how to sync build numbers and assembly file version numbers in sync with MSBuild 4.0 and I think he&rsquo;s taken a fine approach to the problem. I&rsquo;m going to show you how to solve the problem with a custom workflow activity and a customized build process template. With this solution, you&rsquo;ll be able to easily configure parameters in your build definition to control how your files get versioned. Like John&rsquo;s approach, it does require that you customize the build number format for your build definition so that it includes an element that can be used as a version number. Other than that, it&rsquo;s a nice, clean approach with no other dependencies.</p>
<h3>Tracing Binaries to Builds</h3>
<p>TFS already provides a way of automatically incrementing build numbers and, while the default build numbering scheme is date-based, it&rsquo;s not in a format that&rsquo;s suitable for using as a version number. The default build numbering scheme uses the following format:</p>
<pre class="brush: plain">$(BuildDefinitionName)_$(Date:yyyyMMdd)$(Rev:.r)</pre>
<p>This format yields build numbers like &ldquo;DefinitionName_20091112.1&rdquo; where the last number is an auto-incrementing number for each build of this definition that occurs in a given day. Unfortunately, this doesn&rsquo;t translate well to a version number. For this exercise, I&rsquo;m going to use a date-based build and version number that looks like this:</p>
<pre class="brush: plain">$(BuildDefinitionName)_$(Year:yyyy).$(Month).$(DayOfMonth)$(Rev:.r)</pre>
<p>This will yield a build number like &ldquo;DefinitionName_2009.11.18.1&rdquo; which has a component that is suitable for use as an assembly version number.</p>
<h3>Planning the Activity</h3>
<p>Workflow activities can be implemented in code (using the managed language of your choice) or in XAML (using the Windows Workflow designer in Visual Studio or your favorite XML editor). There are advantages and disadvantages for each. <a href="https://msdn.microsoft.com/en-us/library/ms734415.aspx" mce_href="https://msdn.microsoft.com/en-us/library/ms734415.aspx"> Code Activities</a> derive from System.Workflow.Activities.CodeActivity and implement their logic in an overridden Execute method. This method executes synchronously meaning that, while it&rsquo;s running, your activity (and therefore your build) can&rsquo;t be cancelled. So, you&rsquo;ll want to keep the implementation of this method short and sweet avoiding things like web service calls.</p>
<p>XAML activities can be implemented using the Workflow Designer where you can drag and drop activities from the toolbox, set properties, define arguments, etc. visually. For this exercise, we&rsquo;ll be using a both types:</p>
<ul>
<li><strong>ReplaceInFile</strong>. This is a code activity whose sole purpose is to replace all occurrences of a regular expression in a text file with a specified string.</li>
<li><strong>UpdateVersionInfo</strong>. This is a XML activity that extracts the version component from the current build number, finds the files matching a specification (e.g. &ldquo;AssemblyInfo.*&rdquo;) within a specified directory, then uses the ReplaceInFile activity to update the version information in those files to match the build number. This activity will also use the GetBuildDetail and FindMatchingFiles activities provided with TFS Build.</li>
</ul>
<h3>Developing the Activity</h3>
<p>I created a new C# Activity Library project to contain my code and XAML activities. I named it &ldquo;ActivityPack&rdquo; so that I could logically add additional activities to it over time.</p>
<p><img style="display: inline; border-width: 0px;" title="image" border="0" alt="image" src="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/BlogFileStorage/blogs_msdn/jimlamb/WindowsLiveWriter/HowtocreateacustomworkflowactivityforTFS_90CA/image_5.png" original-url="https://blogs.msdn.com/blogfiles/jimlamb/WindowsLiveWriter/HowtocreateacustomworkflowactivityforTFS_90CA/image_5.png" width="640" height="362" mce_src="https://blogs.msdn.com/blogfiles/jimlamb/WindowsLiveWriter/HowtocreateacustomworkflowactivityforTFS_90CA/image_5.png" /></p>
<p>Once your new project is created, the Workflow Designer will automatically open on the XAML file that&rsquo;s been added. If you look at the toolbox, you&rsquo;ll notice that there aren&rsquo;t any TFS Build activities there. To add them, follow these steps:</p>
<ol>
<li>Right click on the toolbox and select <strong>Choose Items&hellip;</strong></li>
<li>The Choose Toolbox Items dialog box will open. Select the <strong>System.Activities Components</strong> tab.</li>
<li>Click <strong>Browse</strong> and select Microsoft.TeamFoundation.Build.Workflow.dll from the following location: <br /> &lt;Program Files (x86)&gt;\Microsoft Visual Studio 10.0\Common7\IDE\PrivateAssemblies</li>
<li>Verify that the activities appear in the list and that they are checked, then click <strong>OK</strong>. The TFS Build activities should now appear in the toolbox.</li>
</ol>
<p>Before we construct the XAML activity, we&rsquo;ll need to create the CodeActivity to perform the actual regular expression search and replace. Right click on your project and select Add, New Item&hellip; Then, select <strong>Workflow</strong> from the list of Installed Templates, select <strong>Code Activity</strong> from the list of item types and specify <strong>ReplaceInFile.cs</strong> as the Name.</p>
<p><img style="display: inline; border-width: 0px;" title="image" border="0" alt="image" src="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/BlogFileStorage/blogs_msdn/jimlamb/WindowsLiveWriter/HowtocreateacustomworkflowactivityforTFS_90CA/image_8.png" original-url="https://blogs.msdn.com/blogfiles/jimlamb/WindowsLiveWriter/HowtocreateacustomworkflowactivityforTFS_90CA/image_8.png" width="640" height="372" mce_src="https://blogs.msdn.com/blogfiles/jimlamb/WindowsLiveWriter/HowtocreateacustomworkflowactivityforTFS_90CA/image_8.png" /></p>
<p>Next, you&rsquo;ll need to add a reference to the Microsoft.TeamFoundation.Build.Client assembly by browsing to it under &lt;Program Files (x86)&gt;\Microsoft Visual Studio 10.0\Common7\IDE\ReferenceAssemblies\v2.0 and adding it to your using clauses. Then, add the following attribute to your CodeActivity class' declaration:</p>
<pre class="brush: csharp">[BuildActivity(HostEnvironmentOption.Agent)]
public sealed class ReplaceInFile : CodeActivity</pre>
<p>This attribute tells TFS that this activity is safe to load into the build controller. I&rsquo;ll shed some more light on custom build activity deployment a little later. Before moving onto the XAML activity, you&rsquo;ll need to build your project to get the code activity to show up in the toolbox.</p>
<p>The XAML activity is composed of a number of activities organized into a sequential workflow. Here&rsquo;s the pseudo-code for the activity:</p>
<ul>
<li>Update Version Info &lt;Sequence&gt;
<ul>
<li>Validate Arguments &lt;Sequence&gt;
<ul>
<li>Validate SourcesDirectory &lt;If&gt;
<ul>
<li>String.IsNullOrEmpty(SourcesDirectory) Or (Not Directory.Exists(SourcesDirectory)) &lt;Condition&gt;</li>
<li>Throw ArgumentException &lt;Then&gt;</li>
</ul>
</li>
<li>Validate FileSpec &lt;If&gt;
<ul>
<li>String.IsNullOrEmpty(FileSpec) &lt;Condition&gt;</li>
<li>Throw ArgumentException &lt;Then&gt;</li>
</ul>
</li>
<li>Validate RegularExpression &lt;If&gt;
<ul>
<li>String.IsNullOrEmpty(RegularExpression) &lt;Condition&gt;</li>
<li>Throw ArgumentException &lt;Then&gt;</li>
</ul>
</li>
</ul>
</li>
<li>Get the Build &lt;GetBuildDetail&gt;
<ul>
<li>BuildDetail &lt;Result&gt;</li>
</ul>
</li>
<li>Extract Version Info &lt;Assign&gt;
<ul>
<li>VersionInfo &lt;To&gt;</li>
<li>New System.Text.RegularExpressions.Regex(RegularExpression).Match(BuildDetail.BuildNumber).Value &lt;Value&gt;</li>
</ul>
</li>
<li>Form Qualified Spec &lt;Assign&gt;
<ul>
<li>FileSpecToMatch &lt;To&gt;</li>
<li>Path.Combine(SourcesDirectory, "**", FileSpec) &lt;Value&gt;</li>
</ul>
</li>
<li>Find Matching Files &lt;FindMatchingFiles&gt;
<ul>
<li>FileSpecToMatch &lt;MatchPattern&gt;</li>
<li>MatchingFiles &lt;Result&gt;</li>
</ul>
</li>
<li>Handle Matching Files &lt;If&gt;
<ul>
<li>MatchingFiles.Any() &lt;Condition&gt;</li>
<li>&lt;Then&gt;
<ul>
<li>Process Matching Files &lt;Sequence&gt;
<ul>
<li>Log Version to Set &lt;WriteBuildMessage&gt;</li>
<li>Enumerate Matching Files &lt;ForEach&lt;System.String&gt;&gt;
<ul>
<li>Update Version Info in File &lt;Sequence&gt;
<ul>
<li>Log Update &lt;WriteBuildMessage&gt;</li>
<li>Update Version in File &lt;ReplaceInFile&gt;</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
<ul>
<li>Warn No Matches Found &lt;WriteBuildWarning&gt;</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
<p>A total of 10 different workflow activities are used including the ReplaceInFile code activity we created earlier and two TFS Build activities (GetBuildDetail and FindMatchingFiles). You could implement this logic entirely in a code activity, but you would be re-implementing functionality that already exists in the activities include with VS/TFS 2010. And, the XAML activity still gets compiled into MSIL when you build your the activity library project, so there&rsquo;s no separate file that needs to be managed. Lastly, it makes it easier for the Workflow run-time environment to cancel the execution of your activity.</p>
<p>This custom activity includes a set of Arguments. In Workflow, arguments can be in, out, in/out, or properties. If you look along the bottom edge of the Workflow Designer tool window in Visual Studio you&rsquo;ll see buttons for Variables, Arguments and Imports. Variables are used to define local storage for a particular scope of your workflow. Arguments are used to define the inputs and outputs of your workflow. Imports are used like &ldquo;using&rdquo; statements in your code so that you don&rsquo;t have to type out the full namespace everywhere. The value for these is represented as a VB.NET expression so it can (and often does) include code. Here are the arguments for the UpdateVersionInfo activity:</p>
<p><img style="display: inline; border-width: 0px;" title="image" border="0" alt="image" src="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/BlogFileStorage/blogs_msdn/jimlamb/WindowsLiveWriter/HowtocreateacustomworkflowactivityforTFS_90CA/image_8e41e8dc-4f20-401c-97e3-add31348099f.png" original-url="https://blogs.msdn.com/blogfiles/jimlamb/WindowsLiveWriter/HowtocreateacustomworkflowactivityforTFS_90CA/image_8e41e8dc-4f20-401c-97e3-add31348099f.png" width="500" height="197" mce_src="https://blogs.msdn.com/blogfiles/jimlamb/WindowsLiveWriter/HowtocreateacustomworkflowactivityforTFS_90CA/image_8e41e8dc-4f20-401c-97e3-add31348099f.png" /></p>
<p>The SourcesDirectory is the directory to search for source files to update. When we integrate this activity into the build process template, we&rsquo;ll be able to get this path from the build environment. The FileSpec is the file specification to find beneath the sources directory and it defaults to AssemblyInfo.* so the user won&rsquo;t have to modify this in most cases. The RegularExpression is the regular expression used to extract a version number from the build number and to find within the files and replace with that version number. The VersionInfo argument is an output that stores the version number used by the activity which could be handy if you want to use it somewhere else in your build process. In the Workflow Designer, you can pass these arguments to activities you&rsquo;re using by simply referring to them by name.</p>
<h3>Testing the Activity</h3>
<p>It&rsquo;s a good idea to setup some unit tests to validate your custom activities outside the context of the build process. To get started, create a new unit test project and add a Workflow Activity to serve as your test workflow.</p>
<ul>
<li>Add a new C# Test Project to your solution</li>
<li>Add a project reference to your Activity Library</li>
<li>Add references to Microsoft.TeamFoundation.Build.Client and Microsoft.TeamFoundation.Build.Workflow</li>
<li>Add a new C# Workflow Activity item to that project</li>
</ul>
<p>Adding a Workflow Activity will create a XAML file in your test project that you can use as your test workflow. In this particular case, I&rsquo;m using the GetBuildDetail activity which depends on an implementation of the IBuildDetail interface being available in the environment. For testing, I recommend create a mock BuildDetail object. In this case, I&rsquo;ve created a separate C# Class Library project to contain this mock object and potentially additional ones as the need arises. It only overrides the BuildNumber property so that our custom activity can get a build number to extract version information from. Here&rsquo;s what the overridden property looks like:</p>
<pre class="brush: csharp">public string BuildNumber
{
    get
    {
        return String.Format("{0}_{1}.{2}.{3}.{4}",
            Environment.MachineName,
            DateTime.Now.Year,
            DateTime.Now.Month,
            DateTime.Now.Day,
            Convert.ToInt16(DateTime.Now.TimeOfDay.TotalMinutes));
    }
    set
    {
        throw new NotImplementedException();
    }
}</pre>
<p mce_keep="true">&nbsp;</p>
<p><img style="display: inline; margin-left: 0px; margin-right: 0px; border-width: 0px;" title="Test Workflow" border="0" alt="Test Workflow" align="right" src="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/BlogFileStorage/blogs_msdn/jimlamb/WindowsLiveWriter/HowtocreateacustomworkflowactivityforTFS_90CA/image_0acf8605-0215-4c6c-a672-81e297b952d9.png" original-url="https://blogs.msdn.com/blogfiles/jimlamb/WindowsLiveWriter/HowtocreateacustomworkflowactivityforTFS_90CA/image_0acf8605-0215-4c6c-a672-81e297b952d9.png" width="261" height="338" mce_src="https://blogs.msdn.com/blogfiles/jimlamb/WindowsLiveWriter/HowtocreateacustomworkflowactivityforTFS_90CA/image_0acf8605-0215-4c6c-a672-81e297b952d9.png" /> The getter provides a reasonable build number for our purposes and lets us exercise our custom activity outside the scope of the actual build process where it&rsquo;s easier to debug and iterate on your design and implementation.</p>
<p>The actual unit tests need to instantiate our test workflow, set the arguments as appropriate for the test, add an instance of our mock BuildDetail object to the workflow&rsquo;s extensions and invoke the workflow. The workflow itself is very simple with just the bare minimum necessary to exercise our custom activity. It&rsquo;s a Sequence activity with a GetBuildDetail activity that will retrieve an IBuildDetail instance from the workflow run-time environment and pass it into our custom UpdateVersionInfo activity. I&rsquo;ve also defined an Out Argument to receive the version string used by our custom activity so that I can write it out to the console.</p>
<p>The actual unit tests vary depending on what aspect of the activity&rsquo;s behavior is being validated, but the general form of the tests follows this pattern:</p>
<pre class="brush: csharp">// another way of specifying in arguments to our workflow
var workflow = new TestWorkflow() {
    SourceDir = SourcesDirectory,
    FileSpec = String.Empty
};

// create the workflow run-time environment and add our mock
// BuildDetail object.
var workflowInvoker = new WorkflowInvoker(workflow);
workflowInvoker.Extensions.Add(new BuildDetail());

try
{
    workflowInvoker.Invoke();
}
catch (expectedException)
{
}</pre>
<p>The main test in this example uses a typical AssemblyInfo source file for C#, VB.NET and C++ (CLR) and runs the UpdateVersionInfo activity on them to verify that the files are updated as expected.</p>
<h3>Integrating the Activity</h3>
<p>Build process templates reside in version control and there&rsquo;s no way to queue a build in TFS using a customized build process template that only exists in your local file system. So, we&rsquo;ll need a working copy of the default build process template to avoid interfering with any existing build definitions. One way of managing this is to branch the default build process template and do your customizations in the branched version. That way you can create a test build definition that uses the branched build process template without interfering with your other builds. You can also add the branched version to your solution so that you can edit it in the same context as your custom activity. In the provided example, I&rsquo;ve added it to a Templates folder beneath the unit test project (and set its &ldquo;Build Action&rdquo; to &ldquo;None&rdquo;).</p>
<p><img style="display: inline; border-width: 0px;" title="image" border="0" alt="image" src="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/BlogFileStorage/blogs_msdn/jimlamb/WindowsLiveWriter/HowtocreateacustomworkflowactivityforTFS_90CA/image_7236bd1f-1cf5-4f3a-9286-7a0ccf2b431c.png" original-url="https://blogs.msdn.com/blogfiles/jimlamb/WindowsLiveWriter/HowtocreateacustomworkflowactivityforTFS_90CA/image_7236bd1f-1cf5-4f3a-9286-7a0ccf2b431c.png" width="640" height="386" mce_src="https://blogs.msdn.com/blogfiles/jimlamb/WindowsLiveWriter/HowtocreateacustomworkflowactivityforTFS_90CA/image_7236bd1f-1cf5-4f3a-9286-7a0ccf2b431c.png" /></p>
<p>Once you&rsquo;ve verified your activity, customized the build process template, and validated its behavior, you can merge it back to the BuildProcessTemplates folder (or whichever folder you&rsquo;re using to store your build process templates) and your builds can immediately get the benefit of it. Note that, in this case, you&rsquo;ll need to update the build number format for your build definitions before using the provided activity.</p>
<p>You&rsquo;ll want to review the build process template you&rsquo;re integrating with when deciding where to insert your custom activity. In this case, I&rsquo;ve placed it at the end of the Initialize Workspace sequence so that it happens immediately after the &ldquo;Get.&rdquo;</p>
<p><img style="display: inline; border-width: 0px;" title="image" border="0" alt="image" src="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/BlogFileStorage/blogs_msdn/jimlamb/WindowsLiveWriter/HowtocreateacustomworkflowactivityforTFS_90CA/image_c9197795-f0d1-49a6-bf12-e6e05bc4fe2d.png" original-url="https://blogs.msdn.com/blogfiles/jimlamb/WindowsLiveWriter/HowtocreateacustomworkflowactivityforTFS_90CA/image_c9197795-f0d1-49a6-bf12-e6e05bc4fe2d.png" width="193" height="480" mce_src="https://blogs.msdn.com/blogfiles/jimlamb/WindowsLiveWriter/HowtocreateacustomworkflowactivityforTFS_90CA/image_c9197795-f0d1-49a6-bf12-e6e05bc4fe2d.png" /></p>
<p>I&rsquo;ve also added two In Arguments that will be visible in the build definition editor to make it easy for users to customize the behavior of the custom activity. These arguments are file spec (e.g. AssemblyInfo.*) and regular expression (e.g. "\d+\.\d+\.\d+\.\d+"). Both of these arguments have default values so they don&rsquo;t <em>have</em> to be set but you can override them if appropriate. To expose arguments to the build definition editor, you add an argument just like you would for any XAML workflow. In the screen shot below, you can see the two arguments I&rsquo;ve added.</p>
<p><img style="display: inline; border-width: 0px;" title="image" border="0" alt="image" src="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/BlogFileStorage/blogs_msdn/jimlamb/WindowsLiveWriter/HowtocreateacustomworkflowactivityforTFS_90CA/image_156bb7ff-9dee-48e7-acd0-e3b43a73872b.png" original-url="https://blogs.msdn.com/blogfiles/jimlamb/WindowsLiveWriter/HowtocreateacustomworkflowactivityforTFS_90CA/image_156bb7ff-9dee-48e7-acd0-e3b43a73872b.png" width="640" height="276" mce_src="https://blogs.msdn.com/blogfiles/jimlamb/WindowsLiveWriter/HowtocreateacustomworkflowactivityforTFS_90CA/image_156bb7ff-9dee-48e7-acd0-e3b43a73872b.png" /></p>
<p>The other interesting argument is &ldquo;Metadata&rdquo; which is where you can specify a display name, help text and other properties for your arguments that will be used in the build definition editor. If you click on the ellipsis (&hellip;) button for the Metadata property, you&rsquo;ll see the Process Parameter Metadata Editor.</p>
<p><img style="display: inline; border-width: 0px;" title="image" border="0" alt="image" src="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/BlogFileStorage/blogs_msdn/jimlamb/WindowsLiveWriter/HowtocreateacustomworkflowactivityforTFS_90CA/image_ece699df-d367-4a1f-8d39-3dbaafc62bee.png" original-url="https://blogs.msdn.com/blogfiles/jimlamb/WindowsLiveWriter/HowtocreateacustomworkflowactivityforTFS_90CA/image_ece699df-d367-4a1f-8d39-3dbaafc62bee.png" width="410" height="479" mce_src="https://blogs.msdn.com/blogfiles/jimlamb/WindowsLiveWriter/HowtocreateacustomworkflowactivityforTFS_90CA/image_ece699df-d367-4a1f-8d39-3dbaafc62bee.png" /></p>
<p>You&rsquo;ll only need to specify the editor if you&rsquo;re using a custom type for your argument of if you want to provide a custom user interface for setting a standard type. If you do specify an editor, you&rsquo;ll need to specify its type using an <a href="https://msdn.microsoft.com/en-us/library/system.type.assemblyqualifiedname(VS.100).aspx" mce_href="https://msdn.microsoft.com/en-us/library/system.type.assemblyqualifiedname(VS.100).aspx"> assembly qualified name</a> and the assembly hosting the editor will need to be in the GAC or in the Visual Studio probing path of each user&rsquo;s machine.</p>
<p>Once you have customized the build process template and checked it into version control, you can create a test build definition that uses that build process template. Here&rsquo;s how to create a build definition to use your custom build process template:</p>
<ul>
<li>Open Team Explorer</li>
<li>Right click on the <strong>Builds</strong> folder and select <strong>New Build Definition</strong></li>
<li>Setup your build definition as desired</li>
<li>Select the <strong>Process</strong> tab and click <img style="display: inline; border-width: 0px;" title="image" border="0" alt="image" src="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/BlogFileStorage/blogs_msdn/jimlamb/WindowsLiveWriter/HowtocreateacustomworkflowactivityforTFS_90CA/image_b6e46358-96b4-4c9a-a94f-8b9cc0e3550f.png" original-url="https://blogs.msdn.com/blogfiles/jimlamb/WindowsLiveWriter/HowtocreateacustomworkflowactivityforTFS_90CA/image_b6e46358-96b4-4c9a-a94f-8b9cc0e3550f.png" width="86" height="16" mce_src="https://blogs.msdn.com/blogfiles/jimlamb/WindowsLiveWriter/HowtocreateacustomworkflowactivityforTFS_90CA/image_b6e46358-96b4-4c9a-a94f-8b9cc0e3550f.png" /></li>
<li>Click <strong>New </strong>to open the New Build Process Template dialog</li>
<li>Click <strong>Select an Existing XAML file</strong>, then click <strong> Browse</strong></li>
<li>Browse for the build process template XAML file you checked into version control and click <strong>OK</strong></li>
</ul>
<p>The XAML in your custom build process template will be parsed and you should see your new arguments appear in the build process parameter list as shown below:</p>
<p><img style="display: inline; border-width: 0px;" title="image" border="0" alt="image" src="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/BlogFileStorage/blogs_msdn/jimlamb/WindowsLiveWriter/HowtocreateacustomworkflowactivityforTFS_90CA/image_0c3023ac-ecf7-49de-9580-f77caa1692a6.png" original-url="https://blogs.msdn.com/blogfiles/jimlamb/WindowsLiveWriter/HowtocreateacustomworkflowactivityforTFS_90CA/image_0c3023ac-ecf7-49de-9580-f77caa1692a6.png" width="640" height="277" mce_src="https://blogs.msdn.com/blogfiles/jimlamb/WindowsLiveWriter/HowtocreateacustomworkflowactivityforTFS_90CA/image_0c3023ac-ecf7-49de-9580-f77caa1692a6.png" /></p>
<h3>Deploying the Activity</h3>
<p>Before checking in the branched version of the default build process template that we&rsquo;ve customized, we&rsquo;ll need to deploy a build of the custom activity assembly. The first step is to choose a location in version control for your custom activity assemblies. If you have custom MSBuild tasks, you can check those into the same location (or, more likely, a sub-folder beneath that location). After you check-in a build of the assembly to this location, you can modify your build controller&rsquo;s properties to load custom activities from that location using the Build Controller properties dialog (accessed from Visual Studio&rsquo;s Build, Manage Build Controllers&hellip; command). Select your build controller and click <strong>Properties</strong>.</p>
<p><img style="display: inline; border-width: 0px;" title="image" border="0" alt="image" src="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/BlogFileStorage/blogs_msdn/jimlamb/WindowsLiveWriter/HowtocreateacustomworkflowactivityforTFS_90CA/image_0b0fc1c6-7fed-4327-b5a1-e8d1b6252a7e.png" original-url="https://blogs.msdn.com/blogfiles/jimlamb/WindowsLiveWriter/HowtocreateacustomworkflowactivityforTFS_90CA/image_0b0fc1c6-7fed-4327-b5a1-e8d1b6252a7e.png" width="387" height="480" mce_src="https://blogs.msdn.com/blogfiles/jimlamb/WindowsLiveWriter/HowtocreateacustomworkflowactivityforTFS_90CA/image_0b0fc1c6-7fed-4327-b5a1-e8d1b6252a7e.png" /></p>
<p>You can click the ellipsis (&hellip;) button next to the &ldquo;Version control path to custom assemblies&rdquo; edit box to browse for the folder in version control that contains your custom assemblies. The Build Controller monitors this location for changes and, when you check-in a new version, it will pick it up automatically, and use it in all subsequent builds that get queued on that Controller. The contents of that folder will be automatically distributed to all build agents participating in builds for that controller.</p>
<h3>Conclusion</h3>
<p>I hope you&rsquo;ve found this article to be a useful introduction to build process customization in TFS 2010 and custom workflow activity development. I wanted to provide something that was just complex enough to really illustrate how you would do this in a production environment. You can download the complete sources for the solution here:</p>
<p><strong>Download</strong> the complete solution as <a href="https://code.msdn.microsoft.com/Project/Download/FileDownload.aspx?ProjectName=TfsSdk&amp;DownloadId=10204"> ActivityPack.zip</a> (updated for TFS 2010 RC) from MSDN Code Gallery.</p>
<p>Note that you&rsquo;ll need the <a href="https://msbuildtasks.tigris.org/files/documents/3383/28296/MSBuild.Community.Tasks.msi" mce_href="https://msbuildtasks.tigris.org/files/documents/3383/28296/MSBuild.Community.Tasks.msi"> MSBuild Community Tasks</a> to load and build this solution.</p>]]></content:encoded>
    </item>
  </channel>
</rss>