How to Use Azure DevOps Pipeline Agent on Windows Server 2022
Azure DevOps Pipelines can run jobs on Microsoft-hosted agents (ephemeral VMs in Azure) or on self-hosted agents that you manage. A self-hosted agent running on Windows Server 2022 gives you control over the build environment — installed tools, network access to on-premises resources, hardware specifications, and cost. This guide covers the complete lifecycle of a self-hosted Windows pipeline agent: installation, registration, running as a Windows service, using it in pipelines, and maintenance.
When to Use a Self-Hosted Agent
Microsoft-hosted agents (the windows-latest or windows-2022 images) are convenient for standard builds but have limitations. They have a 60-minute (or 360-minute for paid) job time limit, no persistent disk between runs, and no access to private network resources like on-premises NuGet feeds, databases, or artifact stores. A self-hosted agent on Windows Server 2022 solves all of these:
Use self-hosted agents when your pipeline needs access to on-premises databases or file shares, when builds take longer than the hosted agent time limits, when you need specific software versions or hardware (GPU, specialized certificates, HSM), or when you want to reuse cached dependencies between builds to reduce build times.
Creating an Azure DevOps Project and Agent Pool
Before installing the agent, set up an agent pool in your Azure DevOps organization. Navigate to your Azure DevOps organization URL (e.g., https://dev.azure.com/yourorg), then go to Organization Settings > Agent Pools > Add Pool. Choose “Self-hosted” as the pool type and give it a name (e.g., OnPremServers). You can scope the pool to specific projects or make it available organization-wide.
Next, generate a Personal Access Token (PAT) that the agent will use to authenticate to Azure DevOps during registration. Go to User Settings (top right) > Personal Access Tokens > New Token. Set the scope to “Agent Pools (Read & Manage)” with the appropriate expiration. Copy the token — you cannot retrieve it after closing the creation dialog.
Downloading and Installing the Agent
The agent software is a .zip package downloaded from Azure DevOps. Download it to the Windows Server 2022 machine where the agent will run.
# Create a directory for the agent (do NOT use a path with spaces)
mkdir C:AzDevOpsAgent1
cd C:AzDevOpsAgent1
# Download the latest Windows x64 agent
$agentUrl = "https://vstsagentpackage.azureedge.net/agent/3.240.1/vsts-agent-win-x64-3.240.1.zip"
Invoke-WebRequest -Uri $agentUrl -OutFile "C:AzDevOpsagent.zip"
# Extract the agent
Expand-Archive -Path "C:AzDevOpsagent.zip" -DestinationPath "C:AzDevOpsAgent1" -Force
Check the latest agent version from your Azure DevOps organization: go to Project Settings > Agent Pools > your pool > New Agent, and it will show the current version download link for your platform.
Registering the Agent with config.cmd
Run config.cmd in the agent directory to register the agent with your Azure DevOps organization. For interactive configuration:
cd C:AzDevOpsAgent1
.config.cmd
The wizard will prompt for:
– Server URL: https://dev.azure.com/yourorgname
– Authentication type: Press Enter for PAT
– Personal Access Token: paste the PAT created earlier
– Agent pool: enter the pool name (e.g., OnPremServers)
– Agent name: a unique name for this agent (default is the machine hostname)
– Work folder: the directory for pipeline job workspaces (default: _work in the agent directory)
For unattended/scripted registration using all command-line arguments:
.config.cmd `
--unattended `
--url "https://dev.azure.com/yourorgname" `
--auth pat `
--token "YOUR_PAT_TOKEN_HERE" `
--pool "OnPremServers" `
--agent "WS2022-Build01" `
--work "C:AzDevOpsWork" `
--runAsService `
--windowsLogonAccount "NT AUTHORITYNETWORK SERVICE"
The --runAsService flag registers and starts the agent as a Windows service immediately. The --windowsLogonAccount specifies the service account. Using NT AUTHORITYNETWORK SERVICE is appropriate for most builds; use a dedicated domain service account if the agent needs access to network resources (file shares, databases) that require specific credentials.
Running the Agent as a Windows Service
If you configured the agent as a service during registration, it will be installed as a Windows service named vstsagent.yourorgname.AgentName. Manage it like any other service:
# Find the agent service name
Get-Service | Where-Object { $_.Name -like "vstsagent*" }
# Example output: vstsagent.yourorgname.WS2022-Build01
# Start, stop, restart
Start-Service "vstsagent.yourorgname.WS2022-Build01"
Stop-Service "vstsagent.yourorgname.WS2022-Build01"
Restart-Service "vstsagent.yourorgname.WS2022-Build01"
# Check service status
Get-Service "vstsagent.yourorgname.WS2022-Build01" | Select-Object Name, Status, StartType
If you did not register as a service during config, install the service afterward:
cd C:AzDevOpsAgent1
.svc.cmd install
.svc.cmd start
If you need the agent to run interactively (useful for UI testing where the agent needs an active desktop session), run .run.cmd instead of installing as a service. For UI-capable builds, configure auto-logon on the server and place run.cmd in the startup folder.
Agent Capabilities and Demands
Agents advertise their capabilities — a key/value collection of software, environment variables, and user-defined properties. Azure DevOps automatically detects capabilities like installed .NET SDKs, MSBuild versions, Visual Studio installations, and Node.js. You can add custom capabilities in the agent pool settings in Azure DevOps (Agent Pools > your pool > your agent > Capabilities tab) or via environment variables on the agent machine.
Pipelines can declare demands to route jobs to agents with specific capabilities:
# In a pipeline YAML file, demand that the agent has a specific capability
jobs:
- job: Build
pool:
name: OnPremServers
demands:
- msbuild
- visualstudio
- Agent.OS -equals Windows_NT
Custom demands (for example, requiring a SQL Server instance for integration tests):
pool:
name: OnPremServers
demands:
- SqlServer2022
Add the corresponding user capability “SqlServer2022 = true” in the Azure DevOps agent capabilities UI, or set an environment variable named SqlServer2022 on the server.
Using a Self-Hosted Agent in a Pipeline
Reference the agent pool by name in your pipeline YAML:
trigger:
- main
pool:
name: OnPremServers
steps:
- task: NuGetToolInstaller@1
displayName: Install NuGet
- task: NuGetCommand@2
displayName: Restore NuGet packages
inputs:
restoreSolution: '**/*.sln'
- task: VSBuild@1
displayName: Build solution
inputs:
solution: '**/*.sln'
msbuildArgs: '/p:Configuration=Release'
platform: 'x64'
- task: VSTest@2
displayName: Run unit tests
inputs:
testSelector: 'testAssemblies'
testAssembliesViaFilter: '***Tests.dll'
platform: 'x64'
configuration: 'Release'
Contrast with a Microsoft-hosted agent YAML — the only difference is the pool specification:
# Microsoft-hosted Windows Server 2022 agent
pool:
vmImage: 'windows-2022'
# Self-hosted pool
pool:
name: OnPremServers
Caching on Windows Agents
One major advantage of self-hosted agents is that the work directory persists between runs, allowing dependency caches to speed up builds. Use the Cache task to formalize this:
variables:
NUGET_PACKAGES: C:NuGetCache
npm_config_cache: C:NpmCache
steps:
- task: Cache@2
displayName: Cache NuGet packages
inputs:
key: 'nuget | "$(Agent.OS)" | **/packages.lock.json,!**/bin/**,!**/obj/**'
restoreKeys: |
nuget | "$(Agent.OS)"
path: $(NUGET_PACKAGES)
- task: Cache@2
displayName: Cache npm modules
inputs:
key: 'npm | "$(Agent.OS)" | package-lock.json'
restoreKeys: 'npm | "$(Agent.OS)"'
path: $(npm_config_cache)
On a self-hosted agent, even without the Cache task, the work directory persists. Be aware that this can cause stale artifacts if builds do not clean properly. Configure your pipelines with a clean step or set the workspace clean option:
pool:
name: OnPremServers
workspace:
clean: all # Options: outputs, resources, all
Agent Diagnostics
When an agent fails to connect or jobs fail unexpectedly, agent diagnostic logs provide detailed information. Logs are stored in the agent’s _diag folder:
# View recent agent logs
Get-ChildItem "C:AzDevOpsAgent1_diag" | Sort-Object LastWriteTime -Descending | Select-Object -First 5
# View the most recent log
Get-Content (Get-ChildItem "C:AzDevOpsAgent1_diagAgent_*.log" | Sort-Object LastWriteTime -Descending | Select-Object -First 1).FullName -Tail 100
For job-level diagnostics, enable pipeline system diagnostics by setting the variable System.Debug to true in the pipeline run.
Updating the Agent
Azure DevOps will notify you in the UI when a new agent version is available. Agents can be updated from Azure DevOps (Organization Settings > Agent Pools > your agent > Update) or you can update manually:
# Stop the agent service
Stop-Service "vstsagent.yourorgname.WS2022-Build01"
# Unregister the agent
cd C:AzDevOpsAgent1
.config.cmd remove --unattended --auth pat --token "YOUR_PAT"
# Download new agent version
Invoke-WebRequest -Uri "https://vstsagentpackage.azureedge.net/agent/3.245.0/vsts-agent-win-x64-3.245.0.zip" -OutFile "C:AzDevOpsagent-new.zip"
# Remove old agent files (keep work directory)
Remove-Item "C:AzDevOpsAgent1*" -Recurse -Force -Exclude "_work"
# Extract new version
Expand-Archive -Path "C:AzDevOpsagent-new.zip" -DestinationPath "C:AzDevOpsAgent1" -Force
# Re-register and reinstall service
.config.cmd --unattended --url "https://dev.azure.com/yourorgname" --auth pat --token "YOUR_PAT" --pool "OnPremServers" --agent "WS2022-Build01" --runAsService
.svc.cmd start
Running Multiple Agents on One Host
A single Windows Server 2022 machine can host multiple agent instances, each running concurrently. This is useful for parallelizing jobs or for dedicating agents to different pools. Install each agent in a separate directory:
# Agent 1
mkdir C:AzDevOpsAgent1
# Extract and configure Agent1 as shown above
# Agent 2
mkdir C:AzDevOpsAgent2
# Extract agent zip to Agent2 directory
cd C:AzDevOpsAgent2
.config.cmd --unattended --url "https://dev.azure.com/yourorgname" --auth pat --token "YOUR_PAT" --pool "OnPremServers" --agent "WS2022-Build01-B" --work "C:AzDevOpsWork2" --runAsService
Each agent registers as a separate service with a unique agent name. The number of concurrent jobs you can run is limited by the machine’s CPU and memory. As a rule of thumb, one agent per 2–4 CPU cores is a reasonable starting point, adjusted by actual build workload and memory usage.
Monitor agent machine performance during builds with Windows Performance Monitor or by setting up Azure Monitor if the server is in a hybrid environment. Watch for CPU saturation, high memory usage causing page file activity, and disk I/O bottlenecks during large builds.
Self-hosted agents on Windows Server 2022 provide a powerful, flexible foundation for CI/CD pipelines that need on-premises integration, custom tools, or persistent build environments that go beyond what Microsoft-hosted agents can offer.