The wait is now over! I have pulled my thumb out and finally put together the post no one has been waiting for!

ok,ok if you are here reading this article maybe someone is waiting for it?!?

If you have not already scaled out Ansible agents into containers make sure you go check this post out…. but hey maybe you are just here for the PowerShell so wait no longer and checkout the details below.

1). Connect to a Windows 2022 Server

Start by RDPing into the windows server built in the previous post and install docker (just the CLI is required, not the desktop version)

2). Create the folder structure

Create a new folder for the docker file and dependencies, for example G:\VMAN\AzureAgentContainer-W2K22\1.0

3). Download the Azure Agent for Windows

Download the Azure agent for Windows and copy it to G:\VMAN\AzureAgentContainer-W2K22\1.0

4). Creating the RunAgent.ps1 file

Create the file G:\VMAN\AzureAgentContainer-W2K22\1.0\RunAgent.ps1 and copy in the following contents

if (-not (Test-Path Env:AZP_URL)) {
  Write-Error "error: missing AZP_URL environment variable"
  exit 1
}
if (-not (Test-Path Env:AZP_TOKEN_FILE)) {
  if (-not (Test-Path Env:AZP_TOKEN)) {
    Write-Error "error: missing AZP_TOKEN environment variable"
    exit 1
  }
  $Env:AZP_TOKEN_FILE = "\azp\.token"
  $Env:AZP_TOKEN | Out-File -FilePath $Env:AZP_TOKEN_FILE
}
Remove-Item Env:AZP_TOKEN
if ((Test-Path Env:AZP_WORK) -and -not (Test-Path $Env:AZP_WORK)) {
  New-Item $Env:AZP_WORK -ItemType directory | Out-Null
}

# Let the agent ignore the token env variables
$Env:VSO_AGENT_IGNORE = "AZP_TOKEN,AZP_TOKEN_FILE"
Set-Location agent
try
{
  Write-Host "Configuring Azure Pipelines agent..." -ForegroundColor Cyan
  .\config.cmd --unattended `
    --agent "$(if (Test-Path Env:AZP_AGENT_NAME) { ${Env:AZP_AGENT_NAME} } else { hostname })" `
    --url "$(${Env:AZP_URL})" `
    --auth PAT `
    --token "$(Get-Content ${Env:AZP_TOKEN_FILE})" `
    --pool "$(if (Test-Path Env:AZP_POOL) { ${Env:AZP_POOL} } else { 'Default' })" `
    --work "$(if (Test-Path Env:AZP_WORK) { ${Env:AZP_WORK} } else { '_work' })" `
    --replace
  Write-Host "Running Azure Pipelines agent..." -ForegroundColor Cyan
  .\run.cmd
}
finally
{
  Write-Host "Cleanup. Removing Azure Pipelines agent..." -ForegroundColor Cyan
  .\config.cmd remove --unattended `
    --auth PAT `
    --token "$(Get-Content ${Env:AZP_TOKEN_FILE})"
}

5). Creating the Dockerfile

Create the docker file G:\VMAN\AzureAgentContainer-W2K22\1.0\DockerFile and copy in the following contents, make sure to correct the version of the azure agent with the one you have downloaded.

FROM mcr.microsoft.com/windows/servercore:ltsc2022
WORKDIR /azp

#Disable UAC
RUN powershell "Set-ItemProperty -Path REGISTRY::HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Policies\System -Name ConsentPromptBehaviorAdmin -Value 0"

#Upload Azure Agent
COPY vsts-agent-win-x64-2.213.2.zip .
RUN powershell "Expand-Archive -Path vsts-agent-win-x64-2.213.2.zip -DestinationPath '\azp\agent'"

#Install NuGet
RUN powershell "Install-PackageProvider -Name NuGet -Force"

#Install Powershell Dependencies from Powershell Gallery
RUN powershell "Install-WindowsFeature -Name RSAT-AD-PowerShell"
RUN powershell "Install-WindowsFeature -Name RSAT-DNS-Server"
RUN powershell "Install-WindowsFeature -Name Hyper-V-PowerShell"
RUN powershell "Install-Module -Name VMware.PowerCLI -Force -SkipPublisherCheck -AllowClobber"
RUN powershell "Install-Module -Name Posh-SSH -Force"
RUN powershell "Install-Module -Name Join-Object -Force"
RUN powershell "Install-Module -Name ImportExcel -Force"
RUN powershell "Install-Module -Name Az -Force"
RUN powershell "Install-Module -Name MicrosoftPowerBIMgmt -Force"
RUN powershell "Install-Module -Name EnhancedHTML2 -Force"

#Cleanup
RUN powershell "Remove-Item vsts-agent-win-x64-2.213.2.zip"

#Enable UAC
RUN powershell "Set-ItemProperty -Path REGISTRY::HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Policies\System -Name ConsentPromptBehaviorAdmin -Value 1"

#Run the Script on Container Start
COPY RunAgent.ps1 .
CMD powershell .\RunAgent.ps1

6). Building the Docker Image

open a Administrator command prompt and change to the correct directory

cd G:\VMAN\AzureAgentContainer-W2K22\1.0

Now to build the image type the following command to build the image

docker build -t dockerazureagent:latest .

Once complete we can run the following command to check if the image is ready

docker image list

8). Now that the image is ready, let’s spawn some containers

Run the following command, exchanging your details below, I append _0, _1, etc… for each container so I know which one runs where.

docker run -d –restart unless-stopped –name linsrv01_0 -e AZP_URL=https://dev.azure.com/YOURORGHERE -e AZP_TOKEN=YOURAZUREPATHERE -e AZP_POOL=YOURPOOLNAMEHERE -e AZP_AGENT_NAME=winsrv11_0

And there you have it, multiple AzureDevops Agents running on the same host allowing for more parallel pipelines without having to build more and more servers.

My post above was heavily influenced by this Microsoft post (give credit where credit is due!)

Hope you found this helpful.

vMan