Implementing Custom Tasks in VSTS

with 4 Comments

I think that one of the strengths of the build and release system in Visual Studio Team Services (VSTS) is the large variety of tasks that is available. If you ever want a task that does something that the default tasks can’t do, chances are high that someone else has made a task for just that purpose already, and that it’s ready to be installed from the Visual Studio Marketplace.

But sometimes you might be out of luck, and you have to make the work yourself. What now?

Create Task Groups

The easiest way to create a reusable task is to create a Task Group from an already configured tasks in a build or release definition. You create a task group by selecting one or many tasks, right clicking, and selecting Create task group.

Here is an example of a task that I’ve made that is made up of a single Azure PowerShell task.

Implementing Custom Tasks in VSTS - Task Group 1

All configuration variables, the ones named like $(abc), that are present in the tasks of a task group are put as input parameters of the task group, each with a configurable default value and description.

Implementing Custom Tasks in VSTS - Task Group 2

Task groups are great because they are so easy to make, but have the drawback of only being available in the team project where they are created.

Implementing Custom Tasks in VSTS

If you intend to share your tasks between several team projects or even accounts, your best option is to implement a custom task. Tasks in VSTS are made up of a command executable and a task manifest. The executable can be either a full blown command line application, or a simple PowerShell script. The task manifest is a json-file that contains some metadata such as the task ID, a declaration of what the configuration GUI should contain, and how the executable is invoked.

Strangely, I have not been able to find any official documentation of how to fill in the task manifest json-file. But there is an active pull request with a schema that may be useful if you ever wonder what to write.

An easy way to get started is to copy one of the default tasks of VSTS, and modify it to your needs. Just remember to generate a new ID for your custom task!

The documentation of the VSTS DevOps Task SDK encourages you to write scripts for either the agent’s Node or PowerShell3 handlers.

Look at Microsoft’s reference tasks for guidance:

Or, if you want an old school PowerShell task without that much “SDK-noise” you can copy one of mine:

I think you will find that making your own custom tasks is quite straight forward.

Install Custom Tasks With tfx-cli

One way to install a task is to use the TFS Cross Platform Command Line utility (tfx-cli) in a Node.js command prompt:

  • npm install -g tfx-cliThis installs the tfx-cli tool.
  • tfx loginThe login is reused throughout the entire session.
    • Enter collection url >
    • Enter personal access token > 2lqewmdba7theldpuoqn7zgs46bmz5c2ppkazlwvk2z2segsgqrqThis is obviously a bogus token… You can add tokens to access your account at
  • tfx build tasks upload --task-path c:\path-to-repo\MyCustomTask
    • If you change your mind and do not want a task anymore, you can remove it with tfx build tasks delete --task-id b8df3d76-4ee4-45a9-a659-6ead63b536b4, where the Guid is easiest found in the task.json of your task.

If you make a change to a task that you have previously uploaded, you have to bump its version before you upload it again.

Create Team Services Extensions

Another way to install a custom task is to package it inside an Team Services extension. You can read in the official documentation how to get started, or just follow these steps.

If you do not have a publisher id already, head over to the Visual Studio Marketplace Publishing Portal and create it in one of the Azure directories which are associated with your account.

Create an extension manifest-file with the name vss-extension.json, and with content like the following:

Then, run the command tfx extension create in a Node.js command prompt, and upload the generated .vsix-file in the publishing portal.

Implementing Custom Tasks in VSTS - Publishing Portal

Or if you prefer, you can use the command tfx extension publish instead, and supply your personal access token.

If the "galleryFlags": ["Public"] setting is kept commented out, the extension will default to be a private extension, meaning that the extension will only be available in the collections you choose. Access to private extensions are managed through the publishing portal.

Once your extension is battle proven, be a good community member and make it public so that all can benefit from your work.

Follow Johan Classon:

Azure enthusiast, .Net Developer, PowerShell empowered DevOps hacker, and Solutions Architect.

4 Responses

  1. Venky Venkataraman
    | Reply

    Thanks for this nice writeup. Can you clarify this for me? We have written release step to copy files over WinRM that we have created as Task but now we want to share it across all the TFS projects. We have a TFS in house installation and I want to know if the steps you have described is applicable for in house TFS installation as well?

    • Johan Classon
      | Reply

      They are. But you do not have to go through the Market if you do not want to. Just run tfx extension create and upload the generated .vsix-file to your on premise TFS directly.

  2. Johnny Larsen
    | Reply

    Hi Johan.
    Thank you for taking the time to post good articles

    I struggling passing inputs parameters to the referenced powershell file.
    I have surfed the internet for help regarding passing inputs parameters from json to the referenced powershell file.
    I’m using a build agents on premises.
    I have doubled checked multiple times for typos, the referenced powershell file exists, because i’m getting an error from the powershell.

    Do you have any ideas about what i can have misunderstood?
    I’m have tried to use both Powershell and PowerShell3 as executor, and it seems that PowerShell3 isn’t supported for on-premises agents.


    • Johan Classon
      | Reply

      Hm… One quirk of VSTS tasks is that all arguments needs to be passed in as [string]s. If you have set any other parameter type, say [int] or [switch] for example, it would not work. What I have seen, parameters are passed the same way both on-premise and on VSTS.

Leave a Reply