Building Visual Studio Setup Projects with TFS 2010 Team Build

UPDATE: 2010-09-15 – Added details about the use of the ExitCode variable


One of the most common complaints from people starting to use Team Build is that is doesn’t support building Microsoft’s own Setup and Deployment project (*.vdproj). When creating a default build definition that compiles a solution containing a setup project, you’ll get the following warning:

The project file “MyProject.vdproj” is not supported by MSBuild and cannot be built.


This is what the problem is all about. MSBuild, that is used for compiling your projects, does not understand the proprietary vdproj format defined by Microsoft quite some time ago. Unfortunately there is no sign that this will change in the near future, in fact the setup projects has barely changed at all since they were introduced. VS 2010 brings no new features or improvements hen it comes to the setup projects.

VS 2010 does include a limited version of InstallShield which promises to be more MSBuild friendly and with more or less the same features as VS setup projects. I hope to get a closer look at this installer project type soon.

But, how do we go about to build a Visual Studio setup project and produce an MSI as part of a Team Build process? Well, since only one application known to man understands the vdproj projects, we will have to installa copy of Visual Studio on the build server. Sad but true. After doing this, we use the Visual Studio command line interface (devenv) to perform the build.

In this post I will show how to do this by using the InvokeProcess activity directly in a build workflow template. You’ll want to run build your setup projects after you have successfully compiled the projects.

  1. Install Visual Studio 2010 on the build server(s)


  2. Open your build process template /remember to branch or copy the xaml file before modifying it!)


  3. Locate the Compile the Project activity


  4. Select the activity and open the Variables tab at the lower right
  5. Add a new variable called ExitCode of type Int32. This variable will contain the exit code from the devenv process and can be validated for errors.


  6. Drop an instance of the InvokeProcess activity from the toolbox onto the designer, after the Run MSBuild for Project activity


  7. Drop an instance of the WriteBuildMessage activity inside the Handle Standard Output section.
    • Set the Importance property to Microsoft.TeamFoundation.Build.Client.BuildMessageImportance.High
      (NB: This is necessary if you want the output from devenv to show up in the build log when running the build with the default verbosity)
    • Set the Message property to stdOutput


  8. Drop an instance of the WriteBuildError activity to the Handle Error Output section
    • Set the Message property to errOutput


  9. Select the InvokeProcess activity and set the values of the parameters to:


    Note that the Result is piped to the ExitCode variable.

  10. The finished workflow should look like this:



  11. This will generate the MSI files, but they won’t be copied to the drop location. This is because we are using devenv and not MSBuild, so we have to do this explicitly


  12. Drop a Sequence activity somewhere after the Copy to Drop location activity.


  13. Create a variable in the Sequence activity of type IEnumerable<String> and call it GeneratedInstallers


  14. Drop a FindMatchingFiles activity in the sequence activity and set the properties to:



  15. Drop a ForEach<String> activity after the FindMatchingFiles activity. Set the Value property to GeneratedInstallers


  16. Drop an InvokeProcess activity inside the ForEach activity.
    •  FileName: “xcopy.exe”
    • Arguments: String.Format(“””{0}”” “”{1}”””, item, BuildDetail.DropLocation)

  17. The Sequence activity should look like this:



  18. Save the build process template and check it in.


  19. Run the build and verify that the MSI’s is built and copied to the drop location.


Note 1: One of the drawback of using devenv like this in a team build is that since all the output from the default compilations is placed in the Binaries folder, the outputs is not avaialable when devenv is invoked, which causes the whole solution to rebuild again. In TFS 2008, this was pretty simple to fix by using the CustomizableOutDir property. In TFS 2010, the same feature is not avaialble. Jim Lamb blogged about this recently, have a look at it if you have a problem with this:

Note 2: Although the above solution works, a better approach is to wrap this in a custom activity that you can use in your builds. I will come back to this in a future post.

0 thoughts on “Building Visual Studio Setup Projects with TFS 2010 Team Build”

  1. Originally posted on:

    I’m trying to follow these steps but I’m stuck on step 7. Alongside where I’ve entered [ExitCode] in the Result property there’s a Compiler error stating: “Compiler error(s) encountered processing expression “[ExitCode]”. ‘ExitCode’ is not declared. It may be inaccessible due to its protection level.”

    Please help.

  2. Originally posted on:

    I have created a build agent on another server so I can take the load off compiling on the TFS Server itself. I guess I need to install VS 2010 on the Build Server to get my applications to compile correctly. You mentioned installing VS 2010 on the build server, but what edition did you end up installing. I am cheap, I want to install the least expensive edition that I can. Can I install the Shell and get by with that?

  3. Originally posted on:

    Thanks for the article, very well laid out and very helpful!

    I get the same problem as Rob at step #7. If i just leave that field blank, though, instead of putting “[ExitCode]” in there then everything seems to work fine. I’m curious if I even need to do anything about it.

    Also, on a side note, it seems to expect VB code in all the configuration properties. Is there an option somewhere to make it use C# ?


  4. Originally posted on:

    Thanks for the help, I managed to get this working, *except* that when the devenv command runs on the build server, the following error is logged. Package ‘Microsoft.VisualStudio.TestTools.TestCaseManagement.QualityToolsPackage, Microsoft.VisualStudio.QualityTools.TestCaseManagement, Version=, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a’ failed to load.

    Any ideas, can provide more info if necessary.

  5. Originally posted on:

    Excellent post, very helpful. The trouble is I also have the QualityTools.TestCaseManagement issue mentioned above by Chris.

    I think Rudi’s solution above is a red herring, it actually results in devenv failing but it doesn’t fail the build so it looks like the build has passed (check the log).

    I think the issue is that I’m using VS2010 Premium instead of Ultimate and that the QualityTools.TestCaseManagement.DLL is failing to load because the LoadTest.DLL file isn’t installed (I’m not trying to do Load Testing btw).

    Does anyone have a solution to this problem?

    I’m currently participating in a thread on it, but we don’t seem to be getting anywhere, over here:

  6. Originally posted on:

    This is very good and helpful but I still have a problem. I’m using devenv to build some non-Microsoft compiler projects (e.g., C, Fortran) that MSBuild can’t handle. I see the logged output and in some cases I see errors (e.g., no such source file), but the devenv errors don’t seem to come in as error output so the TFS build says no errors (even though the devenv log clearly shows compile and link errors). What are people doing for this?

  7. Originally posted on:

    Thanks Jakob for the reply.

    The solution file contains the setup project. The issue was that I had space in the folder name in TFS. enclosed the variable localproject in queotes like …+ “””” + localProject + “””” and it worked.

    However I am getting below errors:
    C:Program Files (x86)Microsoft Visual Studio /Build Debug “D:Builds5AO SDMC.NETWebApplicationStarterKit4_CISourcesWebApplication.sln”

    Microsoft (R) Visual Studio Version 10.0.30319.1.
    Copyright (C) Microsoft Corp. All rights reserved.

    Package ‘Microsoft.VisualStudio.TestTools.TestCaseManagement.QualityToolsPackage, Microsoft.VisualStudio.QualityTools.TestCaseManagement, Version=, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a’ failed to load.

    Package ‘Microsoft.VisualStudio.TestTools.TestCaseManagement.QualityToolsPackage, Microsoft.VisualStudio.QualityTools.TestCaseManagement, Version=, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a’ failed to load.

    Also there are 4 other errors with no message associated.

    Can you please guide for these unknown errors?

  8. Originally posted on:


    at the begining, thanks for the post, it helped me a lot.

    I got similar problem with “Package ‘Microsoft.VisualStudio.TestTools.TestCaseManagement.QualityToolsPackage, Microsoft.VisualStudio.QualityTools.TestCaseManagement, Version=, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a’ failed to load.”.

    I resolved it by changing to devenv.exe in path to visual studio.

    Hope this will help somebody.

    Best regards,

  9. Originally posted on:

    I came across a fairly simple way to have the output of each project end up in their respective bin/[configuration] so that when compiling the .vdproj, the entire solution is not rebuilt. In step 10 listed above, find “Run MSBuild for Project”. Select this activity, and in the properties window, clear the property OutDir. This will enable the normal OutputPath of project. However, none of the output files will be copied to the Binaries directory and will then not end up in the drop folder. There will be a warning about in the tfs build log. However, what you will see in the drop folder is the log file and the .msi/.exe, depending on which files were specified to be copied over the drop folder in step 14 when defining the “Find generated installers” activity.

  10. Originally posted on:

    Hi Jakob,

    Thanks for the post. It is really helpful. I have a couple of questions though:

    (1) Regarding the ExitCode variable, I’m still not quite sure with what condition should I use with a If or switch because I’m getting “Compiler error(s) encountered processing expression “[ExitCode]”. ‘ExitCode’ is not declared. It may be inaccessible due to its protection level.” error.
    (2) Also, I’m getting the same error for localProject.

    I would really appreciate if you could help me fix these errors. I’m new to MSBuild 4.0.

    Thanks a ton,

  11. Originally posted on:

    @Paresh: Sorry for the late answer.

    If you can’t reference a workflow variable (such as localProject), the reason is usually that you the variable is not in the current scope. localProject is declared inside the “Compile the Project” sequence activity,
    which means that you can only reference the variable within that activity.

    Reagarding the ExitCode variable, have you added the variable to the “Compile the Project” sequence activity (Step 5 above). If so, you should be able to reference the variable later in the same scope.

  12. Originally posted on:

    Hi. I have some problems. I think that I misunderstood some section.
    Until section 11 you describe how to create msi, but where can I find created files?
    In section 12 you wrote drop a sequence somewhere after “copy to drop”, but where should I find “copy to drop” sequence? Where do you mean by “somewhere”?

  13. Originally posted on:


    I have configured the TFS system in my client Win 7 machine and the MSIs are not getting built and the error is showing as “These files could not be found and will not be loaded.
    The operation could not be completed”. I modified the argument for devenv as String.Format(“{0} /build {1}|{2}”, localProject, platformConfiguration.Configuration, platformConfiguration.Platform) as the argument shown in this article was showing error to “use devenv [solutionfile | projectfile | anyfile.ext] [switches]””

    When I invoke the command from console it builds the MSI But not from the Teambuild system.

    Please let me know what could be the error.

    Earlier I was always

  14. Originally posted on:

    This is awesome!

    I do have a few questions though. I have implemented this for one of our projects and it was successfully building the MSI files and copying them, however it has stopped working. Any ideas on how to update this to handle any potential errors?

    The MSI files doesn’t seem to be generated by the invoking of DevEnv. However when we build manually on TFS machine running DevEnv the MSI file is found in the release folder for our setup project. Any ideas?

  15. Originally posted on:

    The IEnumerable<String> is found by; Browse for types. find IEnumerable<t>. Then there will be a combo slection allowing you to change the ‘t’ to String.
    Now when you select OK it will fill that cell and there will be an additional entry for that cell that will be “system.collections.generic.ienumerable<System.String>


  16. Originally posted on:

    Hey there, thanks for the great article! It worked like charm! Let me suggest two small improvements (hopefully I did not overlooked some in the other comments):
    1) It would be really great if you could show up the path to the activities mentioned in the article, I have searched some time to find
    (Compile the Project = Process -> Sequence -> Run on Agent -> Try Compile, Test… -> Sequence -> Compile, Test, an… ->
    Try Compile and Test -> Compile and Test -> For Each Configur… -> Compile and Test … ->
    If BuildSettings.HasProjectsTo -> For Each Proejct in BuildSettin… -> Try to Compile the Project -> Compile the Project)
    2) If you set an relative “Output file name” on the setup project properties you can skip steps 12-17 because the msi file will be automatically build to the right location and is included in the normal Copy to Drop Location.
    I am not pretty sure with the 2) improvement because I already modified the template slightly concerning source and binary directory but if someone could try it would be a pleasure!

    Anyway great job and thanks for the solution! Hopefully we can get this working also in VS & TFS 2012 where deployment project type is kicked out completely!
    Best Regards

  17. Originally posted on:

    Thanks for the very helpful article with clear explanations!
    Though, I got a problem 🙁

    The VS2010 is installed on the Build Server, but when running the build (all steps as described above OK, modified the devenv.exe path for real one on the build server), I get the error:

    “File not found: C:Porgram FilesMicrosoft Visual Studio”

    (The file is there, I’ve checked)
    Does any body know why and how to fix it?


  18. Originally posted on:

    Thank you for the post. It works great.
    But, is there a way to increase the setup project Version number (and change the Product code ? Without it, if I try to install the installer, I get the error “Another version of this product is already installed. Installation of this version cannot continue. To configure or remove the existing version of this product, use Add/Remove programs on the control panel.”

  19. Originally posted on:


    I have the setup project containing the solution build in VS 2010.
    I have setup the Workflow template as per the steps mentioned above and only issue im facing while building the project is File not found for devenv.exe. VS 2010 is not installed in the Build server but VS 2012 is installed. Can i give the devenv path of 2012? I tried giving that path also but giving the same exception as File Not Foud. Please help

  20. Originally posted on:

    Hi Jakob,

    Thanks for the input. Build is working fine.
    But it seems like MSI is not found in the dropped location. do we need to build the.vdproj [msi project] in Process tab in the build definition. or Only building the solution will work. since solution contains two projects one which creates exe and another msi. i have modified the solution configuration for this solution by checking that Build option for vdproj project.
    but ended in a warning saying that .vdproj is not supported by MSBuild and cannot be built.

  21. Originally posted on:

    Thank you for the detailed steps above. However, I am getting a compile error saying: Compile error(s) encountered processing expression “GeneratedInstallers”. ‘String’ cannot be converted to ‘System.Collections.Generic.IEnumerable(Of String)’ because ‘Char’ is not derived from ‘String’, as required for the ‘Out’ generic parameter ‘T’ in ‘Interface IEnumerable(Of Out T)’.
    Please let me know how this can be fixed.

Leave a Reply

Your email address will not be published.