Darren put the challenge so I thought I would take it up.  I’m an ENTJ.   The interesting thing that I have noticed is that I have done these personality tests at various stages throughout my life and I have found that they do change with your life experiences. 

Anyway, ENTJ is Extraverted, Intuitive, Thinking, Judging

However, I don’t necessarily subscribe to the trademark of the type “I’m really sorry you have to die.” 

I was reading through my feeds today and I noticed one from Tiago Pascoal that sparked my interest.   One of the most common questions that I get when consulting around TFS is how to restrict the list of people that you can assign a work item to.    After reading his post, I liked what I saw.   By making a slight modification to the process template (see below) you can restrict the list of people that are in the list.  

As part of my default installation I normally setup AD groups and assign them to Project\Contributers and Project\Project Administrators.   Doing this allows the infrastructure people to use their normal group management tools to manage the access to TFS.   I need to do some investigation to see if making this change to the process template will still work if named accounts are not in the Contributors group.

From Tiago’s post.

But i prefer a more restrictive view. Only list users that have access to the project. So when customizing process templates, I typically use this definition for the assigned to field:

<FIELD name="Assigned To" refname="System.AssignedTo" type="String">   
       <ALLOWEDVALUES expanditems="true" filteritems="excludegroups">            
          <LISTITEM value="[Project]\Contributors" />       
          <LISTITEM value="[Project]\Project Administrators" /> 
      </ALLOWEDVALUES>       
      <PROHIBITEDVALUES expanditems="true">   
         <LISTITEM value="tfsservice" /> 
      </PROHIBITEDVALUES> 
      <ALLOWEXISTINGVALUE /> 
</FIELD> 

This definitions, states that only users who are contributors or project administrator of the project will be listed. (will exclude the tfsservice account from the listing. tfsservice being the account name that runs the service. By default Microsoft recommends tfsservice name, but your installation may vary). I also use the allowexisting value to allow us to edit work items assigned to users who no longer have access to the project.

This is just a quick note to myself as a keep forgetting it.  After you have added in the WiXUtilExtension.dll to your project if you want to enable intellisense ensure that the first line of you wix contains the following namespaces:

xmlns=”http://schemas.microsoft.com/wix/2006/wi” xmlns:util=”http://schemas.microsoft.com/wix/UtilExtension”>

Now that TFS Integrator has been released here are the upgrade instructions.    The quickest way to upgrade to TFS Integrator is to do the following:

 

  1. Grab this zip file.  In it are 2 files.   TFSIntegrator.exe and Readify.TeamFoundation.Common.dll
  2. Stop your TFSIntegrator Service.
  3. Backup you existing TFSInstallation, especially the ContinuousIntegration.xml and DependencyReplication.xml
  4. Extract the files and copy them over the top of your existing installation. (Gota love XCopy deployment)
  5. Once the files have been copied across you can restart the service.
  6. Grab your ContinousIntegration.xml file and check it into the root of the TeamBuildTypes folder of every team project hat you have setup for ContinuousIntegration.

    For example if you have the following config file

    <ContinuousIntegration xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance” xmlns:xsd=”http://www.w3.org/2001/XMLSchema” xmlns=”http://schemas.readify.net/tfsintegrator/continuousintegration/20060712″>
    <TeamProject TeamProject=”SystemA”>
    <Build ChangedPath=”$/SystemA” BuildType=”SystemAContinuous” Sleep=”60″ BuildMachine=”BUILDSERVER”/>
    </TeamProject>
    <TeamProject TeamProject=”SystemB”>
    <Build ChangedPath=”$/SystemB” BuildType=”SampleTeamProjectBContinuous” Sleep=”60″ BuildMachine=”BUILDSERVER”/>
    </TeamProject>
    </ContinuousIntegration>

    You will need to check in ContinuousIntegration.xml into  $/SystemA/TeamBuildTypes and $/SystemB/TeamBuildTypes.

  7. Grab your dependencyreplication.xml file and check it into every $/<TeamProject>/TeamBuildType/<TeamBuild> from which you wish to replicate files.

    For example if you have the following configuration file:

    <?xml version=”1.0″ encoding=”utf-16″?>
    <DependencyReplication xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance” xmlns:xsd=”http://www.w3.org/2001/XMLSchema” xmlns=”http://schemas.readify.net/tfsintegrator/dependencyreplication/20060725″>
    <TeamProject TeamProject=”SystemB” RootFolder=”$/SystemB”>
    <Dependency TeamProject=”SystemA” BuildType=”SystemAContinuous” >
    <File Source=”Release/Output1.dll” Destination=”$/SystemB/SystemB/Dependencies/Output1.dll” />
    <File Source=”Release/Output2.dll” Destination=”$/SystemB/SystemB/Dependencies/Output2.dll” />
    </Dependency>
    </TeamProject>
    <TeamProject TeamProject=”SystemC” RootFolder=”$/SystemC”>
    <Dependency TeamProject=”SystemB” BuildType=”SystemBContinuous” >
    <File Source=”Release/OutputB1.dll” Destination=”$/SystemC/SystemC/Dependencies/Output1.dll” />
    <File Source=”Release/OutputB2.dll” Destination=”$/SystemC/SystemC/Dependencies/Output2.dll” />
    </Dependency>
    </TeamProject>
    </DependencyReplication>

    You will need to check in the DependencyReplication.xml into $/SystemA/TeamBuildTypes/SystemAContinuous and to $/SystemB/TeamBuildTypes/SystemBContinuous

  8. Once you have verified that TFSIntegrator is still working as expected you can go back and tidy up the configuration files. 

    Using the example above $/SystemA/TeamBuildTypes/continuousintegration.xml could be refactored to look like:

    <ContinuousIntegration xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance” xmlns:xsd=”http://www.w3.org/2001/XMLSchema” xmlns=”http://schemas.readify.net/tfsintegrator/continuousintegration/20060712″>
    <TeamProject TeamProject=”SystemA”>
    <Build ChangedPath=”$/SystemA” BuildType=”SystemAContinuous” Sleep=”60″ BuildMachine=”BUILDSERVER”/>
    </TeamProject>
    </ContinuousIntegration>

    And $/SystemA/TeamBuildTypes/SystemAContinuous/dependencyreplication.xml could be refactored to look like:

    <?xml version=”1.0″ encoding=”utf-16″?>
    <DependencyReplication xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance” xmlns:xsd=”http://www.w3.org/2001/XMLSchema” xmlns=”http://schemas.readify.net/tfsintegrator/dependencyreplication/20060725″>
    <TeamProject TeamProject=”SystemB” RootFolder=”$/SystemB”>
    <Dependency TeamProject=”SystemA” BuildType=”SystemAContinuous” >
    <File Source=”Release/Output1.dll” Destination=”$/SystemB/SystemB/Dependencies/Output1.dll” />
    <File Source=”Release/Output2.dll” Destination=”$/SystemB/SystemB/Dependencies/Output2.dll” />
    </Dependency>
    </TeamProject>
    </DependencyReplication>

  9. And that is it your are all done!

This is the final series in the posts on the new version of TFS Integrator.  This takes you through the steps of installing TFS Integrator for the first time.

Account Setup

  1. First thing that you need to do is create an account for TFS Integrator, this could be the account that you run your team builds under if you already have one or a new one.
  2. You need to confirm that the account is a member of the Team Foundation Administrators group (Right Click in on your TFS Sever in Team Explorer and select Team Foundation Server Settings -> Group Membership) 
  3. You then need to add the account to the administrators group.  This is so it has the necessary privilages to create a WCF end point.  (I know this is not the best and will post the actual required permisions and how to give an account access to a WCF end point at a later stage)
  4. You then need to give the account Logon As a Service Right.  To do this go to Administration Tools-> Local Security Policy.   This will bring up the Local Security Policy MMC snap in.   Once it is loaded select Local Polices from the left hand tree view and User Rights Assignment.    
  5. Double click the “Logon As A Service” Policy and add the account that you are using.
     
  6. Now you have completed the account setup phase

Installation of TFS Integrator 1.1

  1. Download TFS Integrator from here.
  2. Double click on the msi and following the bouncing ball.
  3. At the following screen you will need to enter some information:
    Service Account:  Is the account that you wish the TFSIntegrator Service to run as
    Service Password:  Is the password for the service account
    TFS Server: Is your TFS Server that you wish TFS Integrator to register itself with
    Base Address: This is the starting address for TFS Integrator end ponts.  The computer name here will need to be name of the computer that you are installing TFSIntegrator on. 
  4. Continue to the end of the installation.  
  5. To check that the installation is successfully open up the Services mmc snap in and check and make sure that TFS Integrator is running.

Setting Up Continuous Integration and DependencyReplication

The last step that you need to do is setup your configuration files for ContinousIntegration.   For this we are going to use the following source control tree.

$/SystemA
        TeamBuildTypes
                SystemAContinuous
        SystemA       

$/SystemB
        TeamBuildTypes
                SystemBContinuous
        SystemB
                Dependencies

If we want to setup ContinousIntegration for SystemA.  We would put the following configuration file in $/SystemA/TeamBuildTypes/ContinuousIntegration.xml

<ContinuousIntegration xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance” xmlns:xsd=”http://www.w3.org/2001/XMLSchema” xmlns=”http://schemas.readify.net/tfsintegrator/continuousintegration/20060712″>
  <TeamProject TeamProject=”SystemA”>
         <Build ChangedPath=”$/SystemA” BuildType=”SystemAContinuous” Sleep=”60″ BuildMachine=”BUILDSERVER”/>
  </TeamProject>
</ContinuousIntegration>

If we want to setup ContinousIntegration for SystemB.  We would put the following configuration file in $/SystemB/TeamBuildTypes/ContinuousIntegration.xml

<ContinuousIntegration xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance” xmlns:xsd=”http://www.w3.org/2001/XMLSchema” xmlns=”http://schemas.readify.net/tfsintegrator/continuousintegration/20060712″>
  <TeamProject TeamProject=”SystemB”>
         <Build ChangedPath=”$/SystemB” BuildType=”SystemBContinuous” Sleep=”60″ BuildMachine=”BUILDSERVER”/>
  </TeamProject>
</ContinuousIntegration>

To setup dependency replication so that the outputs of the SystemAContinuous are replicated to $/SystemB/SystemB/Dependencies you would put the following configuration file in $/SystemA/TeamBuildTypes/SystemAContinuous/DependencyReplication.xml

<?xml version=”1.0″ encoding=”utf-16″?>
<DependencyReplication xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance” xmlns:xsd=”http://www.w3.org/2001/XMLSchema” xmlns=”http://schemas.readify.net/tfsintegrator/dependencyreplication/20060725″>
  <TeamProject TeamProject=”SystemB” RootFolder=”$/SystemB”>
     <Dependency TeamProject=”SystemA” BuildType=”SystemAContinuous” >
       <File Source=”Release/Output1.dll” Destination=”$/SystemB/SystemB/Dependencies/Output1.dll” />
       <File Source=”Release/Output2.dll” Destination=”$/SystemB/SystemB/Dependencies/Output2.dll” />
     </Dependency>
   </TeamProject>
</DependencyReplication>

And that is it.  You have now installed and configured TFS Integrator.          

I presented today at the VSTSUG in Canberra today the new version of TFS Integrator.   At the time I said that I would blog about it so here it is.    So what is in the version of TFS Integrator.   Well firstly there has been two major changes:

  1. ContinuousIntegraton.xml and DependencyReplication.xml are now stored inside TFS. 
  2. New Setup has been developed that installs the service and updates the TFSIntegrator.exe.config file with the configuration settings.

Besides this two major enhancements, there have been fixes to perform case insensitive checks on all paths.  There have been some instances where the case of a directory has cause TFSIntegrator not to start a build or perform a dependency replication, this errors should have been fixed with this release.

So lets tackle the first new feature.    After some discussion and real life administration of TFS on large projects it quickly became apparent that storing the configuration files in c:\program files\TFSIntegrator doesn’t work, especially for the dependency replication file.   As a result, I decided to store them inside TFS.  This has a number of benefits:

  1. The files are now versioned, so changes to them over time can be tracked. 
  2. Instead of having one set of config files for your whole TFS installation the config file are now maintained on a Team Project level.

In terms of the second new feature we wanted to make the installation process a little smoother.  So now the installation processs is only a couple of steps rather than runing a setup project, then running the TFSIntegrator.exe to install the application and configuring a service.  

So the new version of TFS Integrator can be found here.

The obvious question after this is where to from here.  The top three items on the list are:

  1. Simplification of the DependencyReplication.xml configuration file, because of the new changes.
  2. Getting ready for TFS Orcas.  As a result, TFS Integrator will no longer support Continuous Integration as it will be supported out of the box.    Also, dependency replication will need to be updated to cater for the new changes to the build
  3. A UI to manage the configuration files a little better. It sucks at the moment having to manually edit those configuration files.
  4. The ability to do wild card selections as part of the dependency replication, rather than having to specify individual files.

Shortly I will be posting up installation instructions to install the product from scratch, and to perform an upgrade.

I have been working on a new version of TFSIntegrator that will be released very shortly.   As part of the new release I wanted to include a new improved version of the setup project.   One of the goals that I wanted to include was the ability to install the service during the installation process.  With Wix V3.0 this is pretty easy.  There is a ServiceInstall and ServiceControl elements that you can use.   There are a couple of things to remember:

  1. The ServiceInstall element needs to be in the same component that install the file for the service. 
  2. The file that is used, is the one with the KeyPath attribute set to yes.

An example component is as follows:

<Component Id="InstallService" Guid="{A217EE94-F719-47c4-BEE0-28FDF944CD5C}">
     <File Id="EXECUTABLE1" Name="TfsIntegrator.exe" Source="Files\TfsIntegrator.exe" 
KeyPath="yes"/> <ServiceInstall Id="ABC" Name="TfsIntegrator" DisplayName="TfsIntegrator" Type="ownProcess" Start="auto" ErrorControl="normal" Description="TfsIntegrator" Account="[SERVICEACCOUNT]" Password="[SERVICEPASSWORD]" /> <ServiceControl Id="StartTfsIntegrator" Name="TfsIntegrator" Start="install" Wait="no" /> <ServiceControl Id="StopTfsIntegrator" Name="TfsIntegrator" Stop="both" Wait="yes" Remove="uninstall" /> </Component>

We have been doing a lot of work lately with Wix, one of the things that we have been trying to do is to have the setup program encrypt the connection string section of our web.config.    Normally you can use ASPNETREG_IIS to encrypt the connection string section.   In Wix you can achieve the same thing using <CustomActions>.    Let me walk you through the steps.

First thing that you need to do is to find the location of the ASPNET_REGIIS executable.  This can be done using the DirectorySearch element.

<Property Id="FRAMEWORKBASEPATH">

<RegistrySearch Id="FindFrameworkDir" Root="HKLM"  Key="SOFTWARE\Microsoft\.NETFramework"  Name="InstallRoot" Type="raw" >

</RegistrySearch>

</Property><Property Id="ASPNETREGIIS" >

<DirectorySearch Path="[FRAMEWORKBASEPATH]" Depth="4" Id="FindAspNetRegIis">

<FileSearch Name="aspnet_regiis.exe" MinVersion="2.0.5" />

</DirectorySearch>

</Property>

Next you need to create your CustomActions.   When securing a config file the first thing you need to is to create a key container.  This can be done using the following CustomAction

<CustomAction Id='CREATE_RSA_CONTAINER'

                    ExeCommand="[ASPNETREGIIS] -pc "PUT-YOUR-KEY-CONTAINER-HERE" -exp"

                    Return='check'

                    Directory='INSTALLDIR'

                    />

Next CustomAction required is to give the user running you application pool access to the key container.   For this command you need to also specify the user that is running you website.

<CustomAction Id='CREATE_RSA_PERMISSION'

                    ExeCommand='[ASPNETREGIIS] -pa "PUT-YOUR-KEY-CONTAINTER-HERE"

 		     "[USER-DOMAIN]\[USER-NAME]"'

                    Return='check'

                    Directory='INSTALLDIR'/>  

Once the user has permission to the key container, the final step is to encrypt the config file. This is done by the following command.

 <CustomAction Id='ENCRYPT_CONFIG'

                    ExeCommand='[ASPNETREGIIS] -pef "connectionStrings" "[WEBINSTDIR]" -prov "RSAEncryptionProvider"'

                    Return='check'

                    Directory='INSTALLDIR'

                    />

For the eagle eyed, you will notice that their is a new property being used called WEBINSTDIR the ASPNET_REGIIS command requires you to specify the directory of where the location of the web config is. Unfortunately, you cannot use the INSTALLDIR because the command requires that the directory be specified without a trailing slash which the INSTALLDIR has.  To get around this I used another directory search<Property Id="WEBINSTDIR" >

        <DirectorySearch Path="[INSTALLDIR]" Depth="0" Id="FindInstallDirectory">

          <FileSearch Name="web.config"/>

        </DirectorySearch>

</Property>  

This allowed me to get the directory of where the web.config file was located.    The final step that is required is to add the CustomActions to the InstallExecuteSequence

       <InstallExecuteSequence>

        <Custom Action="CREATE_RSA_CONTAINER" After="InstallFiles" >NOT Installed </Custom>

        <Custom Action="REMOVE_RSA_CONTAINER" After="RemoveFiles">Installed</Custom>

        <Custom Action="CREATE_RSA_PERMISSION" After="CREATE_RSA_CONTAINER" >NOT Installed </Custom>

        <Custom Action="ENCRYPT_CONFIG" After="CREATE_RSA_PERMISSION" >NOT Installed AND ENCRYPTCONFIGVALUE = 1</Custom>

      </InstallExecuteSequence>

This install sequence will install the containers.   To allow for the config file to be not encrypted I have also added a property called ENCRYPTCONFIGVALUE.  In addition to this when an uninstall is run we need to the ability to remove the container which we created that can be done using this CustomAction

      <CustomAction Id='REMOVE_RSA_CONTAINER'

                    ExeCommand="[ASPNETREGIIS] -pz "PUT-YOUR-KEY-CONTAINER-HERE""

                    Return='check'

                    Directory='INSTALLDIR'

                    />

And that is it! It needs a bit more testing to ensure that it works in all scenarios

When using Wix you not sure of where a file will be located on the disk.   If this is the case then you need to use DirectorySearch and FileSearch to search for the file.   DirectorySearch  is quite simple you specify the directory that you wish to search and the file that you are trying to find.    A couple of things to point out

  1. Depth on the DirectorySearch element specifies how many sub directories deep you wish to search for the file.  If you only want to search in a specific directory specify a depth of 0. 
  2. MinVersion or MaxVersion can be used to limit the search to a specific file version.

The following is an example that I used to find the location aspnet_regiis for .NET Version 2.   Note:  I also did a RegistrySearch to find out where the .NETFramework was installed. 

 

<Property Id="FRAMEWORKBASEPATH">
<RegistrySearch Id="FindFrameworkDir" 
Root="HKLM"
Key="SOFTWARE\Microsoft\.NETFramework"
Name="InstallRoot" Type="raw" > </RegistrySearch> </Property> <Property Id="ASPNETREGIIS" > <DirectorySearch Path="[FRAMEWORKBASEPATH]"
Depth="4" Id="FindAspNetRegIis"> <FileSearch Name="aspnet_regiis.exe" MinVersion="2.0.5" /> </DirectorySearch> </Property>

You might have guessed I’ve had my head in Wix for a while, well here is another titbit that I have found.    I had a screen which if the user selected IntegratedSecurity, then it would disable the username and password entry boxes on the screen.     Again I used to a condition,this time however it was on a control and it was to used to enable/disable the control based on a check box.   Then based on the property that was set by a checkbox, I was able to enable /disable the control

The Wix snippet is as follows

 

<Control Type="Edit" Width="87" 
Height="15" X="255" Y="60" Id="UserEditBox" Property="USEREDITBOXVALUE" > <Condition Action="enable" >USEINTEGRATEDSECURITY = 1</Condition> <Condition Action="disable"><![CDATA[USEINTEGRATEDSECURITY <>1]]></Condition> </Control>
 
<Control Type="Edit" Width="87" Height="15" X="255" Y="60" Id="PasswordEditBox"
                       Property="PASSWORDTEXTBOXVALUE" >
         <Condition Action="enable" >USEINTEGRATEDSECURITY = 1</Condition>
         <Condition Action="disable"><![CDATA[USEINTEGRATEDSECURITY <>1]]></Condition>

</Control>
<Control 
Id="IntegratedSecurityCheckBox"
Type="CheckBox"
Text="Use Integrated Security"
Property="USEINTEGRATEDSECURITY"
Width="200"
Height="15"
X="26" Y="241"
CheckBoxValue="1"/>
 

About

I am a MCTS in Team Foundation Server based in Canberra, Australia. My passion is to improve developer productivity using tools like TFS.

I'm currently employed as a Senior Consultant at Readify

Tools I have Developed

  • TFS Integrator
  • TFS Deployer
  • TFS Listener

del.icio.us