With a continuous integration and release pipeline configured and working, I was going back through projects and creating the necessary build and release tasks. One build job however was failing with the following error:

2016-03-04T13:04:26.3021168Z Set workingFolder to default: D:\TFS\tasks\NuGetInstaller\0.1.16
2016-03-04T13:04:26.3391205Z Executing the powershell script: D:\TFS\tasks\NuGetInstaller\0.1.16\NuGetInstaller.ps1
2016-03-04T13:04:26.6061472Z D:\TFS\agent\worker\tools\NuGet.exe restore "d:\TFS\_work\1\s\src\MySolution.sln"  -NonInteractive
2016-03-04T13:04:26.9761842Z MSBuild auto-detection: using msbuild version '14.0' from 'C:\Program Files (x86)\MSBuild\14.0\bin'.
2016-03-04T13:04:27.0951961Z ##[error]There are duplicate packages: log4net.1.2.10
2016-03-04T13:04:27.1041970Z ##[error]Unexpected exit code 1 returned from tool NuGet.exe

The error causing the job to fail is:

There are duplicate packages

Checking The Build

So I checked out the project and compiled with Visual Studio, no problems. Then I tried using the nuget command from the command line.

D:\Projects\MySolution\src>nuget restore
ll packages listed in packages.config are already installed.

The packages folder already exists so we have to clear it first. Since I have Cygwin installed (and I prefer the Unix tools), I just deleted the folder from the command line:

rm -rf Packages

You can obviously do this from the Windows explorer shell or use the native DOS commands.

So running the command again, all of the packages restore without issue. Hmmm…

Replicating The Error

So next, I run the identical command that was logged in the log output for the build job:

D:\TFS\_work\1\s\src>D:\TFS\agent\worker\tools\NuGet.exe restore "d:\TFS\_work\1\s\src\MySolution.sln"  -NonInteractive
MSBuild auto-detection: using msbuild version '12.0' from 'C:\Program Files (x86)\MSBuild\12.0\bin'.
There are duplicate packages: log4net.1.2.10

And now we finally get the error to duplicate.

But why?

Let’s check the versions of our NuGet utility.

On the build server, we have:

D:\TFS\_work\1\s\src>D:\TFS\agent\worker\tools\NuGet.exe
nuget Version: 3.2.1.10581

On the workstation with Visual Studio (with NuGet specified in the path), we have:

D:\Projects\MySolution\src>nuget
NuGet Version: 2.8.50926.602

Different NuGet Versions

So the build server is using the 3.x branch of NuGet which doesn’t handle XML errors as gracefully (or is more strict) as the prior version. So now we know the cause of the problem, let see if we can find the duplicate.

And sure enough, inside of a subproject we have the following inside of the packages.config file:

  <package id="log4net" version="1.2.10" targetFramework="net45" />
  <package id="log4net" version="1.2.10" targetFramework="net45" />

Remove the dupliate line, recommit and push the code.

Problem SOLVED!

For my employer, I’ve been working on setting up a continuous integration and release pipeline using Team Foundation Server (TFS) on-premise. Earlier this year, I had started experimenting with the standalone Release Management 2015 tool. Although I made some progress, the XAML based workflows and client tooling left a lot to be desired and I ended up reverting to using msbuild deployment options directly from the build itself. Not ideal, but better than nothing.

I was ecstatic to learn that a web-based version of Release Management had been integrated into Visual Studio Team Services (VSTS), formerly Visual Studio Online, as part of a preview release. But much to my dismay, the new Release Management (in preview), wasn’t scheduled to be available for on-premise TFS until later in 2016. VSTS typically get’s new updates every three weeks, with those updates rolled to TFS on-premise on a quarterly cycle. It was clear that the Release Management 2015 client and server tool were going away so it didn’t pay time to continue exploring the solution.

An Early Birthday Present!

After resigning myself to the fact that I’d have to wait to get my hands on the new Release Management tools, the release candidate for TFS 2015 Update 2 was announced. Much to my surprise and excitement TFS 2015 Update 2 RC1 included the new web-based version of Release Management.

Although I typically avoid release candidates, this couldn’t wait…

Dude, Where’s My IIS Deployment?

Missing IIS Web Application Deployment TaskWith the new bits installed on the server, I finally had access to the new web-based Release Management UI and could start following along with some of the online tutorials I was seeing for VSTS. In one of those tutorials, I saw reference to an “IIS Web Application Deployment” task. Just the task I needed to deploy my application to IIS! Unfortunately, this task wasn’t available on my on-premise installation?

After a little bit of searching, I found the open source vso-agent-task Github repo for all of the tasks included in VSTS:

Included in that repo is the IISWebAppDeployment task which is missing for my installation. I assumed that the IISWebAppDeployment task wasn’t available simply because it hadn’t been included in the TFS 2015 Update 2 RC1 release. Should be simple enough to fix…

Use The Source

With the source in hand, the next step was figuring out how to get it deployed. I found an article that discussed how to deploy custom tasks… not a task for the faint of heart. As I prepared myself for the task, I learned that since that post was originally made, Microsoft had released the TFS Cross Platform Command Line Interface which not only simplifies the process but is the supported and recommended method for installing extensions.

TFS Cross Platform Command Line Interface

Insallation

Installation of the tool is easy with node.js and npm.

npm -g install tfx-cli

Getting Authenticated

The first step is to get logged into the TFS server. By default, the logon process is going to look for a VSTS personal authentication code which doesn’t apply (yet) to TFS on-premise. Thankfully basic authentication is supported, but you’ll need to enable it on your TFS server. While you’re enabling basic authentication, I strongly encourage you to configure your TFS / IIS server to force SSL. Sending a basic username and password without an encrypted connection is ALWAYS a bad idea.

Run the following command to interactively login:

C:\Users\gheeres\vso-agent-tasks>tfx login --auth-type basic
TFS Cross Platform Command Line Interface v0.3.15
Copyright Microsoft Corporation
> Service URL: https://tfs.heeresonline.com/MyCollection
> Username: tfs-admin@heeresonline.com
> Password:
Logged in successfully

One logged in, you can run additional commands to view the list of installed tasks.

C:\Users\gheeres\vso-agent-tasks>tfx build tasks list
TFS Cross Platform Command Line Interface v0.3.15
Copyright Microsoft Corporation

id            : 7c6a6b71-4355-4afc-a274-480eab5678e9
name          : DecryptFile
friendly name : Decrypt File (OpenSSL)
visibility    : Build,Release
description   : A thin utility task for file decryption using OpenSSL.
version       : 1.0.5

...

If I recall, when I grep‘ed the output for the IISWebAppDeployment task nothing was found. This should be easy. Let get that deployed.

C:\Users\gheeres\vso-agent-tasks>tfx build tasks upload --task-path Tasks\IISWebAppDeployment
TFS Cross Platform Command Line Interface v0.3.15
Copyright Microsoft Corporation
Error: Failed Request: Conflict(409) - A task definition with id 89a3a82d-4b3e-4a09-8d40-a793849dc94f and version 1.0.9 has already
been uploaded. To replace the existing definition, re-register the task definition before uploading the package.

$&!#? Already Been Uploaded? Seriously?

The error tells us that the task, has already been uploaded. But when we search our Task list in the build and release UIs, the “IIS Web Application Deployment” task is still not seen. Hmmm…

If we look at the task.json file, we notice a “visibility” attribute with the value of “Preview”.

  "visibility": [
    "Preview",
    "Build",
    "Release"
  ]

Although I couldn’t find documentation, this “Preview” tag must prevent the UI for seeing the task. So lets get that changed. Edit the Tasks/IISWebAppDeployment/task.json file to remove the “Preview” option, or apply the following patch.

diff --git a/Tasks/IISWebAppDeployment/task.json b/Tasks/IISWebAppDeployment/task.json
index fc1d9b4..2bd1535 100644
--- a/Tasks/IISWebAppDeployment/task.json
+++ b/Tasks/IISWebAppDeployment/task.json
@@ -6,7 +6,6 @@
   "helpMarkDown": "[More Information](http://aka.ms/iiswebappdeployreadme)",
   "category": "Deploy",
   "visibility": [
-    "Preview",
     "Build",
     "Release"
   ],

Overwrite

Now if we try to deploy it again, we’ll get the same error that the task still exists. One solution is to increment the version information. However if you do that, it could break future updates. So instead, we’ll use the –overwrite command. You can view the list of available options by using the –help command. The output is included below:

C:\Users\gheeres\vso-agent-tasks>tfx build tasks upload --help
TFS Cross Platform Command Line Interface v0.3.15
Copyright Microsoft Corporation

                        fTfs
                      fSSSSSSSs
                    fSSSSSSSSSS
     TSSf         fSSSSSSSSSSSS
     SSSSSF     fSSSSSSST SSSSS
     SSfSSSSSsfSSSSSSSt   SSSSS
     SS  tSSSSSSSSSs      SSSSS
     SS   fSSSSSSST       SSSSS
     SS fSSSSSFSSSSSSf    SSSSS
     SSSSSST    FSSSSSSFt SSSSS
     SSSSt        FSSSSSSSSSSSS
                    FSSSSSSSSSS
                       FSSSSSSs
                        FSFs    (TM)

Syntax:
tfx build tasks upload --arg1 arg1val1 arg1val2[...] --arg2 arg2val1 arg2val2[...]

Command: upload
Upload a Build Task.

Arguments:
  --task-path  Local path to a Build Task.
  --overwrite  Overwrite existing Build Task.

Global server command arguments:
  --auth-type    Method of authentication ('pat' or 'basic').
  --username     Username to use for basic authentication.
  --password     Password to use for basic authentication.
  --token        Personal access token.
  --service-url  URL to the service you will connect to, e.g. https://youraccount.visualstudio.com/DefaultCollection.
  --fiddler      Set up the fiddler proxy for HTTP requests (for debugging purposes).
  --proxy        Use the specified proxy server for HTTP traffic.

Global arguments:
  --help       Get help for any command.
  --save       Save arguments for the next time a command in this command group is run.
  --no-prompt  Do not prompt the user for input (instead, raise an error).
  --output     Method to use for output. Options: friendly, json, clipboard.
  --json       Alias for --output json.

To see more commands, type tfx build tasks --help

So let’s try deploying that again with the –overwrite option.

C:\Users\gheeres\vso-agent-tasks>tfx build tasks upload --task-path Tasks\IISWebAppDeployment --overwrite
TFS Cross Platform Command Line Interface v0.3.15
Copyright Microsoft Corporation

Task at C:\Users\gheeres\vso-agent-tasks\Tasks\IISWebAppDeployment uploaded successfully!

SUCCESS!!!

IISWebAppDeployment uploaded successfully!

Checking the list of available tasks, we see that it is now available. In a future post, I walk through our release configuration.