Taming TFS - Automatic deployment of Click Once projects

By eidias on (tags: tfs, categories: infrastructure)

We’ve covered deploying web application, now it’s time for click once. So let’s get to it.

This is the end result:


After some checks I’m retrieving the project files with “FindMatchingFiles” activity, then for each project and each configuration publishing the project and transferring it to the test server.

Here’s the breakdown in detail.

The “FindMatchingFiles” activity arguments:

Argument Value
MatchPattern String.Join(";", ClickOnceProjects.Select(Function(p) String.Format("{0}\**\{1}.csproj", SourcesDirectory, p)))
Result ClickOnceProjectsToTransfer


Argument Value
To projectName
Value Path.GetFileNameWithoutExtension(project)

Publish Click Once Projects (type “MSBuild”)

Argument Value

String.Format("/p:SkipInvalidConfigurations=true /property:PublishDir=""{0}/"";SignManifests=True;ManifestCertificateThumbprint={1};ApplicationVersion={2};PublisherName={3};InstallURL={4};UpdateUrl={5};SupportUrl={6};UpdateEnabled={7};UpdateMode={8};BootstrapperEnabled=True;IsWebBootstrapper=True;MapFileExtensions=True",
              Path.Combine(BinariesDirectory, PublishedDir, Directory.GetParent(project).Name),
              InstallUrl.Replace("$(ProjectName)", projectName),
              UpdateUrl.Replace("$(ProjectName)", projectName),
              SupportUrl.Replace("$(ProjectName)", projectName),

configuration platformConfiguration.Configuration
Project project
Targets New String() {"Publish"}
TargetsNotLogged New String() {"Publish"}
ToolPlatform MSBuildPlatform
Verbosity Verbosity

The following things are worth mentioning

  • CommandLineArguments – most of them are standard publishing parameters for click once, but not all, pay special attention to MapFileExtensions parameter as it’s apparently a part of secret knowledge
  • TargetsNotLogged – this is populated with the same list as Targets property. If you don’t specify this, your build will have an additional ‘summary’ like this one:
    If you’re ok with that, leave the argument empty


Argument Value
Address FtpAddress + "/" + projectName
Password FtpPassword
User FtpUser

and finally FtpTransfer:

Argument Value
Address FtpAddress + "/" + projectName
Password FtpPassword
User FtpUser
SourceDirectory Path.Combine(BinariesDirectory, PublishedDir, projectName)

I’ve blogged about the Ftp actions here. You can also find the source code there.

That’s it. Hope this will give you some additional hints on how to handle tfs builds.