Build your own Hosted VSTS Agent Cloud: Part 4 – Customize

If you have followed the previous 3 parts (part 1, part 2, part 3) you have a full CI/CD pipeline that allows you to deploy your own private agents based on the official Microsoft configuration for the VSTS Hosted Agent Pool. One of the steps was importing the GitHub repository containing the Packer configuration in your own VSTS account. This allows you to easily customize the script and make sure that your private agents fit your needs. In this post I’ll show you some customization I made to the Packer configuration.

Customizing the current configuration

If you look at the Readme file stored in the repository, you can easily see which software is installed on the agent. And it’s a lot. The file vs2017-Server2016-Azure.json shows that Microsoft calls a PowerShell script to install each component and another script to validate that the installation succeeded.

For example, if you don’t need Wix just remove the following two snippets from the json file:


   "type": "powershell",


      "{{ template_dir }}/scripts/Installers/Vs2017/Install-Wix.ps1"




   "type": "powershell",


      "{{ template_dir }}/scripts/Installers/Vs2017/Validate-Wix.ps1"



The same is true for things like Java or Go. Just remove the JSON snippet and Packer won’t install those components.

Caching Docker images

If you’re doing Docker development, you’ve probably noticed that downloading Docker images takes time. Images such as SQL Server on Linux or ASP.NET are quite big and no matter how fast your internet connection, downloading these takes time. Fortunately, Microsoft already added a script that helps you cache Docker images on your VM. Update-DockerImages.ps1 defines a DockerPull function and caches a couple of default images:

function DockerPull {

   Param ([string]$image)

   Write-Host Installing $image ...

   $j = Start-Job -ScriptBlock { docker pull $args[0] } -ArgumentList $image

   while ( $j.JobStateInfo.state -ne "Completed" -And $j.JobStateInfo.state -ne "Failed" ) {

      Write-Host $j.JobStateInfo.state

      Start-Sleep 10


   $results = Receive-Job -Job $j



DockerPull microsoft/windowsservercore

DockerPull microsoft/nanoserver

DockerPull microsoft/aspnetcore-build:1.0-2.0

DockerPull microsoft/aspnet

DockerPull microsoft/dotnet-framework

If you need another image that you want to use for building or testing your app, this is the place to add them. That way, they will be downloaded once and will be available on all your Agents.

Caching NPM packages

Another part where I want to add some extra caching is npm. Since you’re using private agents you will already benefit for not having to download all npm packages on each build but if you have a couple of popular packages, you can add them to the end of the Node install script:


npm install -g gulp-cli

npm install -g grunt-cli

npm install -g bower

npm install -g cordova

Adding and customizing your own scripts

And of course, you can also install completely new tooling by adding a script. Microsoft has to balance how often a tool is used with the amount of disk space they have available on the VM. For example, at the time of writing there is an issue on the GitHub repo asking for the SonarQube scanner. Microsoft answer is that you can install this as a part of your build which is true. But now that you’re running your own agent, it’s easy to add a simple script that installs the SonarQube scanner on your image and as a result on all your Agents.

Another thing you can take advantage of is having a faster update cadence. Microsoft has a huge responsibility making sure that the Hosted Pool works for millions of users. This also means they do some thorough testing which takes time. Currently, after a Visual Studio update is released, it still takes a couple of weeks before the Agent is updated. No one stops you modifying your script to install the newest VS update, run some quick test and start using it before Microsoft releases an official update.


In this series I showed you how to use Packer, VSTS, Azure and all the work Microsoft did to create a CI/CD pipeline for building and deploying your own VSTS Agents. I hope that this series also showed you some of the powerful capabilities of VSTS and Azure when it comes to automating deployments. You can find all the scripts I created on GitHub. If something doesn’t work for you, please post an issue or send a PR. For now, I hope this series was useful for you and helps you in running your own agents!

Wouter de Kort works as a lead architect and consultant. He helps organizations stay on the cutting edge of software development. Wouter focuses on DevOps. He loves solving complex problems and helping other developers to grow. Wouter authored the book DevOps on the Microsoft stack and a couple of other books. Wouter is a Microsoft MVP and an ALM Ranger. You can find him on Twitter (@wouterdekort), on his blog at and at the various conferences where Wouter speaks.


9 Responses

  1. There’s an easier, more convenient and straight forward way to manage your Private Build Agents. Simply use and Azure DevTest Lab in your Azure subscription to create your VSTS build agent VMs, using a Formula with a list of Artifacts in the Azure DevTest Lab instance. You can include a “VSTS Build Agent” artifact in the formula, such that your VM gets automatically provisioned with VSTS build agent executable and automatically registers to your specified VSTS agent queue.

    More info in the video here:

    • Hi Ross,

      that’s absolutely a possibility. This post was based on reusing the work that Microsoft already does for their Hosted Pool. The VSTS team uses Packer and creates a standard image that they can use to quickly spin up new build machines.

      Kind regards,

  2. Thanks for the great article, there is one thing you mentioned at the beginning but not explaining later is about the
    ” worry about installing updates or applying patches to the platform”.

    I’m assuming as long as it’s a custom image, we don’t get the benefit of the VM is always up to date, meaning the updates and patches we still have to do ourselves and recreate image frequently, am I understanding right?

    • Hi Dawei,

      the not worrying about updates and patches was about VSTS in comparison with TFS. VSTS as a SaaS solution is always up to date and maintained by Microsoft.

      But when it comes to the IaaS Build VMs you’re absolutely right. Those need to be updated and patched. I wouldn’t patch the individual machines once they are deployed. Instead, make sure you use the latest Windows image for your base image and apply any required patches while building the images. Then destroy any existing build agents and deploy new ones that have the latest fixes build in.

      Does that make sense?


  3. Hi
    I am constantly getting errors when installing SSDT after VS2017. This happens only when I run build on VSTS agent in previously created image locally. When I run it locally – SSDT in image installs successfully
    Can you point, where to look for a problem further?

Leave a Reply

Your email address will not be published. Required fields are marked *

Post comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.