How to Use Azure DevOps Pipeline Agent on Windows Server 2025

Self-hosted Azure Pipelines agents give you complete control over the build environment — you choose the operating system, installed toolchains, network access, and hardware resources. On Windows Server 2025, a self-hosted agent is ideal when your pipelines need access to internal resources like private NuGet feeds, on-premises databases, signing certificates stored in hardware security modules, or simply require more CPU and RAM than the Microsoft-hosted agents provide. This guide covers downloading and configuring the Azure Pipelines agent, running it as a Windows service for unattended operation, organizing agents into pools, expressing hardware and software requirements through pipeline demands, building .NET applications, and maintaining agent health through diagnostics.

Prerequisites

  • Windows Server 2025 (Standard or Datacenter) with network access to dev.azure.com and *.vsblob.vsassets.io
  • An Azure DevOps organization and a project with at least Contributor rights
  • A Personal Access Token (PAT) with Agent Pools (Read & Manage) scope
  • .NET 8 SDK or later installed (required for .NET build pipelines)
  • Git for Windows installed and on the system PATH
  • PowerShell 5.1 or PowerShell 7+ (recommended for cross-platform pipeline tasks)
  • A dedicated low-privilege service account for running the agent (do not run as Domain Admin)

Step 1: Create a Dedicated Service Account

Running the agent under a dedicated domain or local account with least-privilege follows security best practices. Grant the account only what it needs — typically read access to source repositories and write access to build output directories.

# Create a local service account for the build agent
$securePassword = ConvertTo-SecureString "Ag3ntP@ssword2025!" -AsPlainText -Force
New-LocalUser -Name "svc_buildagent" -Password $securePassword `
    -FullName "Azure DevOps Build Agent Service Account" `
    -Description "Runs Azure Pipelines self-hosted agent" `
    -PasswordNeverExpires $true `
    -UserMayNotChangePassword $true

# Add to local Users group (avoid Administrators group unless absolutely required)
Add-LocalGroupMember -Group "Users" -Member "svc_buildagent"

# Grant "Log on as a service" right (required for service installation)
# Use ntrights.exe or secedit — here using the ntrights approach:
$seceditCfg = @"
[Unicode]
Unicode=yes
[Version]
signature="`$CHICAGO`$"
Revision=1
[Privilege Rights]
SeServiceLogonRight = *S-1-5-20,svc_buildagent
"@
$seceditCfg | Out-File -FilePath "C:Tempsecedit_logon.inf" -Encoding Unicode
secedit /configure /db secedit.sdb /cfg "C:Tempsecedit_logon.inf" /areas USER_RIGHTS

Write-Host "Service account configured."

Step 2: Download the Azure Pipelines Agent

Download the latest agent package from your Azure DevOps organization’s agent pools settings page. The download URL follows a predictable pattern from the GitHub releases of the azure-pipelines-agent repository.

# Create agent directory
New-Item -Path "C:AgentsAgent01" -ItemType Directory -Force
Set-Location "C:AgentsAgent01"

# Download latest Azure Pipelines agent for Windows x64
# Replace the version number with the latest from:
# https://github.com/microsoft/azure-pipelines-agent/releases
$agentVersion = "3.248.0"
$agentUrl = "https://vstsagentpackage.azureedge.net/agent/${agentVersion}/vsts-agent-win-x64-${agentVersion}.zip"

Write-Host "Downloading Azure Pipelines Agent v${agentVersion}..."
Invoke-WebRequest -Uri $agentUrl -OutFile "agent.zip" -UseBasicParsing

# Extract the agent
Expand-Archive -Path "agent.zip" -DestinationPath "C:AgentsAgent01" -Force
Remove-Item "agent.zip"

Write-Host "Agent extracted to C:AgentsAgent01"
Get-ChildItem "C:AgentsAgent01" | Select-Object Name, Length

Step 3: Configure the Agent

Run the configuration script to register the agent with your Azure DevOps organization. You will need the organization URL and a PAT with Agent Pools scope. For unattended configuration (CI/CD pipelines bootstrapping agents), all parameters can be passed on the command line.

Set-Location "C:AgentsAgent01"

# Interactive configuration (prompts for PAT, pool name, etc.)
.config.cmd

# Fully unattended configuration (for scripted provisioning):
.config.cmd `
    --url "https://dev.azure.com/myorganization" `
    --auth pat `
    --token "YOUR_PAT_TOKEN_HERE" `
    --pool "Self-Hosted-WS2025" `
    --agent "WS2025-BuildAgent-01" `
    --work "_work" `
    --acceptTeeEula `
    --runAsService `
    --windowsLogonAccount ".svc_buildagent" `
    --windowsLogonPassword "Ag3ntP@ssword2025!" `
    --replace

The --replace flag allows the configuration to overwrite an existing agent registration with the same name, which is useful for re-imaging machines or re-provisioning agents.

Step 4: Install and Start the Agent as a Windows Service

Running the agent as a Windows service ensures it starts automatically after reboots and operates without requiring an interactive logon session.

Set-Location "C:AgentsAgent01"

# Install the agent as a Windows service
.svc.cmd install

# Start the service
.svc.cmd start

# Verify service status
Get-Service -Name "vstsagent.myorganization.Self-Hosted-WS2025.WS2025-BuildAgent-01" |
    Select-Object Name, Status, StartType

# Alternatively, query via SCM:
sc.exe query "vstsagent*"

# Check agent diagnostics log for registration confirmation
Get-Content "C:AgentsAgent01_diagAgent_$(Get-Date -Format 'yyyyMMdd')*.log" -Tail 30

If the service fails to start, check the Windows Event Log under Windows Logs → Application for entries from the VSTSAgent source, and review the _diag folder logs.

Step 5: Configure Agent Pools and Capabilities

Agent capabilities are key-value pairs that describe what software and tools are installed on the agent. Pipelines use demands to target agents that have specific capabilities.

# Agent capabilities are automatically detected from environment variables and installed tools.
# You can add custom capabilities by setting environment variables or user-defined capabilities
# in the Azure DevOps portal: Organization Settings > Agent Pools > [Pool] > Agents > [Agent] > Capabilities

# Common auto-detected capabilities on a Windows Server 2025 agent with .NET SDK:
# - DotNetFramework (version detected)
# - msbuild (if Visual Studio Build Tools installed)
# - vstest (if VS Test Agent installed)
# - PowerShell (version)
# - git (version)

# Install .NET 8 SDK on the agent (if not already present)
winget install Microsoft.DotNet.SDK.8 --silent --accept-source-agreements

# Install Visual Studio 2022 Build Tools for MSBuild/C++ builds
# Download vs_buildtools.exe and install silently:
$buildToolsUrl = "https://aka.ms/vs/17/release/vs_BuildTools.exe"
Invoke-WebRequest -Uri $buildToolsUrl -OutFile "C:Tempvs_BuildTools.exe" -UseBasicParsing
& "C:Tempvs_BuildTools.exe" --quiet --wait --norestart `
    --add Microsoft.VisualStudio.Workload.ManagedDesktopBuildTools `
    --add Microsoft.VisualStudio.Workload.WebBuildTools `
    --add Microsoft.VisualStudio.Workload.MSBuildTools

Write-Host "Build Tools installation initiated."

Step 6: Configure Demands in a YAML Pipeline

Demands ensure your pipeline runs only on agents that have the required tools installed. Specify demands at the job level in your YAML pipeline definition.

# Example azure-pipelines.yml demonstrating demands targeting the Windows Server 2025 agent:



# Test that the agent meets demands by running a pipeline manually:
Write-Host "Check agent capabilities at: https://dev.azure.com/myorganization/_settings/agentpools"

Step 7: Configure Parallel Jobs and Multiple Agent Instances

To run pipeline jobs in parallel, register multiple agent instances on the same server or add multiple servers to the agent pool.

# Register a second agent instance on the same server
New-Item -Path "C:AgentsAgent02" -ItemType Directory -Force
Copy-Item -Path "C:AgentsAgent01*" -Destination "C:AgentsAgent02" -Recurse -Force

Set-Location "C:AgentsAgent02"
.config.cmd `
    --url "https://dev.azure.com/myorganization" `
    --auth pat `
    --token "YOUR_PAT_TOKEN_HERE" `
    --pool "Self-Hosted-WS2025" `
    --agent "WS2025-BuildAgent-02" `
    --work "_work" `
    --acceptTeeEula `
    --runAsService `
    --windowsLogonAccount ".svc_buildagent" `
    --windowsLogonPassword "Ag3ntP@ssword2025!"

.svc.cmd install
.svc.cmd start

Write-Host "Second agent registered and running."

# Check how many parallel jobs your organization is licensed for:
# Organization Settings > Billing > Parallel jobs

Step 8: Agent Diagnostics and Maintenance

Set-Location "C:AgentsAgent01"

# Run agent diagnostic tests (network connectivity, Azure DevOps reachability)
.binAgentService.exe --diagnostics

# View recent diagnostic logs
$diagLog = Get-ChildItem "C:AgentsAgent01_diag" -Filter "Agent_*.log" |
    Sort-Object LastWriteTime -Descending | Select-Object -First 1
Get-Content $diagLog.FullName -Tail 50

# Stop, update, and restart the agent (for agent self-update scenarios)
.svc.cmd stop
.config.cmd remove --auth pat --token "YOUR_PAT_TOKEN_HERE"
# Re-download and re-extract latest agent version, then:
.config.cmd --url "https://dev.azure.com/myorganization" --auth pat --token "YOUR_PAT_TOKEN_HERE" `
    --pool "Self-Hosted-WS2025" --agent "WS2025-BuildAgent-01" --work "_work" --acceptTeeEula `
    --runAsService --windowsLogonAccount ".svc_buildagent" --windowsLogonPassword "Ag3ntP@ssword2025!"
.svc.cmd install
.svc.cmd start

# Check agent status from PowerShell via Azure DevOps REST API:
$org = "myorganization"
$pat = "YOUR_PAT"
$base64Pat = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(":$pat"))
$headers = @{ Authorization = "Basic $base64Pat"; "Content-Type" = "application/json" }
$pools = Invoke-RestMethod -Uri "https://dev.azure.com/$org/_apis/distributedtask/pools?api-version=7.1" -Headers $headers
$poolId = ($pools.value | Where-Object { $_.name -eq "Self-Hosted-WS2025" }).id
$agents = Invoke-RestMethod -Uri "https://dev.azure.com/$org/_apis/distributedtask/pools/$poolId/agents?api-version=7.1&includeCapabilities=false" -Headers $headers
$agents.value | Select-Object name, status, enabled, @{N="OS";E={$_.systemCapabilities."Agent.OS"}} | Format-Table

A self-hosted Azure Pipelines agent on Windows Server 2025 gives your CI/CD pipeline direct access to internal infrastructure, specialized build toolchains, and hardware resources that Microsoft-hosted agents cannot provide. By running the agent as a Windows service under a dedicated low-privilege account, organizing agents into named pools, expressing software requirements through demands, and maintaining agent health through regular diagnostics and updates, you can build a reliable, scalable build infrastructure that integrates seamlessly with Azure DevOps while keeping sensitive resources safely behind your network perimeter. As your build workload grows, adding additional agent instances or servers to the pool enables horizontal scaling without any changes to your pipeline definitions.