Skip to content

Instantly share code, notes, and snippets.

@ShepardToTheStars
Last active September 21, 2022 13:19
Show Gist options
  • Save ShepardToTheStars/0d05f53724dc9064c33ef44ca9ca6c90 to your computer and use it in GitHub Desktop.
Save ShepardToTheStars/0d05f53724dc9064c33ef44ca9ca6c90 to your computer and use it in GitHub Desktop.
TeamCity Build Agent Automated Install
#https://vanessa.louwagie.io/2017/09/08/automated-teamcity-build-agent-install-for-windows-server/
#Agent requires Java to be installed, and have the java bin directory exist in the path directory.
Param(
#The parent installation directory. Will create [$NumberOfBuildAgents] directories, one for each build agent.
[Parameter(Mandatory=$true)]
$InstallationDiskDrive = "C:\",
#The path to the Java Runtime Environment which the build agent runs on top of.
[Parameter(Mandatory=$true)]
$JavaPath = "C:\JRE",
#The number of build agents to install.
[Parameter(Mandatory=$false)]
[ValidateRange(1,100)]
[int] $NumberOfBuildAgents = 3,
#The TeamCity server to download the build agent install from, and connect the agent to.
[Parameter(Mandatory=$false)]
$TeamCityServerUrl = "http://localhost",
[Parameter(Mandatory=$false)]
$TeamCityServerPort = "80",
#If no service user or password is provided, will install under local system
[Parameter(Mandatory=$false)]
$NtServiceUser = "",
[Parameter(Mandatory=$false)]
$NtServicePassword = "",
#The start port of the range of ports to set the build agents to
[Parameter(Mandatory=$false)]
$BuildAgentStartPort = 9091,
#Prefix the agent service names with a short string. Ex: abbv-
[Parameter(Mandatory=$false)]
$SmallPrefix = ""
)
$ErrorActionPreference = "Stop"
function Download-Agent {
[Cmdletbinding()]
Param
(
[Parameter(Mandatory=$true)]
[string] $InstallDirectory,
[Parameter()]
[string] $TeamCityServerUrl = "http://localhost",
[Parameter()]
[string] $TeamCityServerPort = 80
)
#Download the agent
$_zipFile = "$env:Temp\buildAgent.zip"
if(!(Test-Path -Path $_zipFile)) {
Write-Host "Downloading build agent zip file from TeamCity server."
Start-BitsTransfer -Source "$($TeamCityServerUrl):$TeamCityServerPort/update/buildAgent.zip" -Destination "$env:Temp"
}
else {
Write-Host "Build agent already downloaded. Re-using zip file."
}
if(!(Test-Path -Path $InstallDirectory)) {
Write-Host "Creating installation folder: $InstallDirectory"
New-Item -Path $InstallDirectory -ItemType Directory
}
Write-Host "Expanding the zip file into the installation location."
#TODO: Adapt extract method for PowerShell versions under v5
Expand-Archive -Path "$_zipFile" -DestinationPath "$InstallDirectory" -Force
}
function Configure-AgentProperties {
[Cmdletbinding()]
Param (
[Parameter(Mandatory=$true)]
[string] $BuildAgentRootFolder,
[Parameter(Mandatory=$true)]
[string] $BuildAgentId,
[Parameter(Mandatory=$true)]
[string] $BuildAgentPort,
[Parameter(Mandatory=$true)]
[string] $JavaPath,
[Parameter()]
[string] $TeamCityServerUrl = "http://localhost",
[Parameter()]
[string] $TeamCityServerPort = 80
)
$_propertiesFile = "$BuildAgentRootFolder\conf\buildAgent.properties"
$_distPropertiesFile = "$BuildAgentRootFolder\conf\buildAgent.dist.properties"
$_propertiesContent = Get-Content "$_distPropertiesFile"
Write-Host "Editing buildAgent.properties file..."
Write-Host " Updating serverUrl: $($TeamCityServerUrl):$TeamCityServerPort"
$_propertiesContent = $_propertiesContent -replace "serverUrl=http://localhost:8111/", "serverUrl=$($TeamCityServerUrl):$TeamCityServerPort"
Write-Host " Updating name: $BuildAgentId"
$_propertiesContent = $_propertiesContent -replace "name=", "name=$BuildAgentId"
Write-Host " Adding ownPort: $BuildAgentPort"
$_propertiesContent = $_propertiesContent -replace "#env.exampleEnvVar=example Env Value", "#env.exampleEnvVar=example Env Value`r`nownPort=$BuildAgentPort"
Write-Host " Adding env.TEAMCITY_JRE: $JavaPath"
$_propertiesContent = $_propertiesContent -replace "#env.exampleEnvVar=example Env Value", "#env.exampleEnvVar=example Env Value`r`nenv.TEAMCITY_JRE=$JavaPath"
Write-Host "Writing changes to file: $_propertiesFile`n"
$_propertiesContent | Set-Content "$_propertiesFile"
}
function Configure-AgentServiceWrapper() {
[Cmdletbinding()]
Param (
[Parameter(Mandatory=$true)]
[string] $BuildAgentRootFolder,
[Parameter(Mandatory=$true)]
[string] $BuildAgentId,
#TODO: Add parameter set
[Parameter()]
[string] $NtServiceUser = "",
[Parameter()]
[string] $NtServicePassword = ""
)
$_wrapperConfigFile = "$BuildAgentRootFolder\launcher\conf\wrapper.conf"
$_wrapperConfigContent = Get-Content "$_wrapperConfigFile"
Write-Host "Editing wrapper.conf file..."
#
$_consoleTitle = "TeamCity Build Agent $BuildAgentId"
Write-Host " Updating wrapper.console.title: $_consoleTitle"
$_wrapperConfigContent = $_wrapperConfigContent -replace "wrapper.console.title=TeamCity Build Agent", "wrapper.console.title=$_consoleTitle"
#
$_ntServiceName = "TCBuildAgent-$BuildAgentId"
Write-Host " Updating wrapper.ntservice.name: $_ntServiceName"
$_wrapperConfigContent = $_wrapperConfigContent -replace "wrapper.ntservice.name=TCBuildAgent", "wrapper.ntservice.name=$_ntServiceName"
$_ntServiceDescription = "TeamCity Build Agent Service - $BuildAgentId"
Write-Host " Updating wrapper.ntservice.description: $_ntServiceDescription"
$_wrapperConfigContent = $_wrapperConfigContent -replace "wrapper.ntservice.description=TeamCity Build Agent Service", "wrapper.ntservice.description=$_ntServiceDescription"
Write-Host " Updating wrapper.ntservice.displayname: $_ntServiceDescription"
$_wrapperConfigContent = $_wrapperConfigContent -replace "wrapper.ntservice.displayname=TeamCity Build Agent", "wrapper.ntservice.displayname=$_ntServiceDescription"
if(!([string]::IsNullOrEmpty($NtServiceUser))) {
Write-Host " Adding wrapper.ntservice.account: $NtServiceUser"
$_wrapperConfigContent = $_wrapperConfigContent + "`r`nwrapper.ntservice.account=$NtServiceUser"
Write-Host " Adding wrapper.ntservice.password: ********"
$_wrapperConfigContent = $_wrapperConfigContent + "`r`nwrapper.ntservice.password=$NtServicePassword"
}
Write-Host "Writing changes to file: $_wrapperConfigFile`n"
$_wrapperConfigContent | Set-Content "$_wrapperConfigFile"
}
function Set-FolderPermissions() {
[Cmdletbinding()]
Param (
[Parameter(Mandatory=$true)]
[string] $BuildAgentRootFolder,
[Parameter(Mandatory=$true)]
[string] $NtServiceUser = ""
)
$Acl = Get-Acl "$BuildAgentRootFolder"
$Ar = New-Object System.Security.AccessControl.FileSystemAccessRule("$NtServiceUser","FullControl","Allow")
$Acl.SetAccessRule($Ar)
Set-Acl "$BuildAgentRootFolder" $Acl
}
function Start-AgentService {
[Cmdletbinding()]
Param (
[Parameter(Mandatory=$true)]
[string] $BuildAgentRootFolder
)
Push-Location
& {
Set-Location "$BuildAgentRootFolder\bin"
cmd.exe /c "service.install.bat"
cmd.exe /c "service.start.bat"
}
Pop-Location
}
function Install-BuildAgent {
[Cmdletbinding()]
Param (
[Parameter(Mandatory=$true)]
[string] $BuildAgentRootFolder,
[Parameter(Mandatory=$true)]
[string] $BuildAgentId,
[Parameter(Mandatory=$true)]
[string] $BuildAgentPort,
[Parameter(Mandatory=$true)]
[string] $JavaPath,
[Parameter()]
[string] $TeamCityServerUrl = "http://localhost",
[Parameter()]
[string] $TeamCityServerPort = 80,
[Parameter()]
[string] $NtServiceUser = "",
[Parameter()]
[string] $NtServicePassword = ""
)
Download-Agent -InstallDirectory "$BuildAgentRootFolder" -TeamCityServerUrl "$TeamCityServerUrl" -TeamCityServerPort $TeamCityServerPort
Configure-AgentProperties -BuildAgentRootFolder "$BuildAgentRootFolder" -BuildAgentId "$BuildAgentId" -BuildAgentPort "$BuildAgentPort" -JavaPath "$JavaPath" -TeamCityServerUrl "$TeamCityServerUrl" -TeamCityServerPort "$TeamCityServerPort"
Configure-AgentServiceWrapper -BuildAgentRootFolder "$BuildAgentRootFolder" -BuildAgentId "$BuildAgentId" -NtServiceUser "$NtServiceUser" -NtServicePassword "$NtServicePassword"
#If there was a service user specified, set the permissions for the agent directory.
if(!([string]::IsNullOrEmpty($NtServiceUser))) {
Set-FolderPermissions -BuildAgentRootFolder "$BuildAgentRootFolder" -NtServiceUser "$NtServiceUser"
}
Start-AgentService -BuildAgentRootFolder "$BuildAgentRootFolder"
}
Write-Warning "Make sure that the path variable includes the Java bin folder."
#Escape JavaPath (first \\ is regex, 2nd is not)
$JavaPath = $JavaPath -replace "\\", "\\"
for($i = 0; $i -lt $NumberOfBuildAgents; $i++) {
$agentID = $($i+1)
Write-Host "Installing Build Agent #$($i+1)"
Install-BuildAgent -BuildAgentRootFolder "$($InstallationDiskDrive)\ba$($agentID)" -BuildAgentId "$($SmallPrefix)ba$($agentID)" -BuildAgentPort "$(($BuildAgentStartPort+$i).ToString())" -JavaPath "$JavaPath" -TeamCityServerPort $TeamCityServerPort -NtServiceUser "$NtServiceUser" -NtServicePassword "$NtServicePassword"
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment