Self-host build agents for Visual Studio 2019
Microsoft are deprecating Windows Server 2019 images in Azure DevOps.
If you’re a basic boy like me, who:
- Has solutions that only build in Visual Studio 2019 (v16), and
- Uses Microsoft hosted build agents in DevOps
…then you got problems.
You probably have an azure-pipelines.yml
somewhere that looks like this:
pool:
vmImage: 'windows-2019'
#... snip ...
- task: VSBuild@1
inputs:
solution: '$(servicesSolution)'
vsVersion: '16.0'
msbuildArgs: '/p:UseWPP_CopyWebApplication=true /p:PipelineDependsOnBuild=false /p:CreatePackageOnPublish=true /p:DeployOnBuild=true /p:PackageLocation="$(build.artifactstagingdirectory)\PublishedWebsites"'
platform: '$(buildPlatform)'
configuration: '$(buildConfiguration)'
displayName: Build Services
Visual Studio 2019 could absolutely run on Windows Server 2022, but MS align their OS images so that 19 has 19 and 22 has 22, etc.
What’s to be done
You could:
- Upgrade your solutions so they open and build in Visual Studio 2022 (hard), or
- Set up some local build agents on Windows 2019 (not hard)!!
In IT we like to call these two options “strategic” (♟️) and “tactical” (🔫) respectively which feels a little machismo like we’re living in Splinter Cell.
I was also recently introduced to the word “tactegic” (🤪) which has put me “on tilt” as the kids say.
Anyhow, there’s a deadline involved, which is “you’re not allowed to build on Tuesdays in June and then when June is finished you’re not allowed to build your main line of business codebase ever again, lol” and as a rule, insurance executives don’t like it when you tell them they can’t deploy insurance any more. So we did the “tactical” option.
How
We selected some boxen which are used for a low traffic internal test environment and could do a little extra work on the side. These already have the DevOps deployment agent installed, but I’ll come onto that.
I recommend you install VS2019 on the target box before installing the DevOps build agent, as this way round you can do fewer restarts.
- Get the VS2019 installer from my.visualstudio.com
- Log onto the box you want to use as a build agent
- Paste the installer there and run it
- For us, we needed to tick the ASP.Net workload and add a few build tools, like .Net Framework 4.8
We have a cute little dependence on C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\Common7\IDE\TextTransform.exe
because someone hardcoded it into a build tool, so after installing VS 2019 Pro, I had to copy the content of ...\2019\Professional\Common7\IDE
into ...\2019\Enterprise\Common7\IDE
After installing VS, you need to restart the box.
Install the agent
I’m pretty sure this is the same agent download as used for Deployment Groups. But to install it for an Agent Group, DevOps doesn’t offer you the neat little all-in-one PowerShell script.
Instead they say to download (at time of writing): https://download.agent.dev.azure.com/agent/4.255.0/vsts-agent-win-x64-4.255.0.zip
If it’s the distant future, then use the latest version offered to you by DevOps, obviously.
Then, on the agent, use an Admin PowerShell:
mkdir agent
cd agent
Add-Type -AssemblyName System.IO.Compression.FileSystem ; [System.IO.Compression.ZipFile]::ExtractToDirectory("$HOME\Downloads\vsts-agent-win-x64-4.255.0.zip", "$PWD")
…which is a fancy way of unzipping the content of that download into C:\agent
.
- Generate a PAT on DevOps and save it in a Notepad somewhere.
- Have your instance URL to hand, like
https://dev.azure.com/AcmeCorp
- Run
.\config.cmd
as admin in the agent dir to start the setup wizard.- I like to accept defaults on this, like using
NETWORK SERVICE
as the user and stuff, and I’ve never had need of the specialSERVICE_SID_TYPE_UNRESTRICTED
option which MS staff themselves don’t understand - I just used the “Default” agent pool
- I like to accept defaults on this, like using
To Restart the Agent
If you want to restart the agent so it can rescan its capabilities… restart the box 😉
If you can’t restart the box, use PowerShell to grab the service name and restart it:
Get-Service | Where-Object { $_.Name -like "vstsagent*" } | Format-Table -Property Name, DisplayName, Status -AutoSize -Wrap
Restart-Service "vstsagent.<my-agent>"
Use your agent pool instead of hosted
In your pipeline yaml, change:
pool:
vmImage: 'windows-2019'
to
pool:
name: Default
Unless you used a different pool name earlier.
PR, build, release to test (or prod) and hope the world keeps turning.
That’s it
That’s what I’ve learned.
I like having these notes because I can look back and say “Wow, look at me in Summer of ‘25 messing with DevOps agent pools!”. Good times.
Happy summer summer times (it’s summertime) 🌞 Time to sit back and unwind 😎