application-workloads/visualstudio/vm-vsts-agent/DeployVSTSAgent.config.ps1 (150 lines of code) (raw):

<# .DESCRIPTION The DSC will configure a VSTS agent on a VM using Windows PowerShell DSC. .NOTES Version: 1.0 Author: Sampanna Mohite / Nazakat Hussain Creation Date: 12/03/2018 Purpose/Change: Automated Deployments of VSTS Agents #> Configuration DeployVSTSAgent { param ( [Parameter(Mandatory=$false)] [string]$MachineName, [Parameter(Mandatory=$true)] [string]$UserName, [Parameter(Mandatory=$true)] [string]$Password, [Parameter(Mandatory=$false)] [string]$VSTSAccount, [Parameter(Mandatory=$true)] [string]$PersonalAccessToken, [Parameter(Mandatory=$true)] [string]$AgentName, [Parameter(Mandatory=$true)] [string]$PoolName, [Parameter(Mandatory=$true)] [int]$AgentCount, [Parameter(Mandatory=$true)] [string[]]$Modules ) Import-DscResource -ModuleName PsDesiredStateConfiguration Node ($MachineName) { Script SetVstsAgents{ GetScript = {@{ Result = "" }} TestScript = { $false } SetScript ={ #md c:\TestFolder01 Write-Verbose "VSTSAccounbt - $using:VSTSAccount" -verbose Write-Verbose "Token" -verbose Write-Verbose "Agent count - $using:AgentCount" -verbose Write-Verbose "Entering DeployVSTSAgent.config.ps1" -verbose #$currentLocation = Split-Path -parent $MyInvocation.MyCommand.Definition #Write-Verbose "Current folder: $currentLocation" -verbose #Create a temporary directory where to download from VSTS the agent package (vsts-agent.zip) and then launch the configuration. $agentTempFolderName = Join-Path $env:temp ([System.IO.Path]::GetRandomFileName()).replace('.','') New-Item -ItemType Directory -Force -Path $agentTempFolderName Write-Verbose "Temporary Agent download folder: $agentTempFolderName" -verbose $serverUrl = "https://dev.azure.com/$using:VSTSAccount" Write-Verbose "Server URL: $serverUrl" -verbose $retryCount = 3 $retries = 1 Write-Verbose "Downloading Agent install files" -verbose [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 do { try { Write-Verbose "Trying to get download URL for latest VSTS agent release..." $latestRelease = Invoke-RestMethod -Uri "https://api.github.com/repos/Microsoft/vsts-agent/releases" $latestRelease = $latestRelease | Where-Object assets -ne $null | Sort-Object created_at -Descending | Select-Object -First 1 $assetsURL = ($latestRelease.assets).browser_download_url $latestReleaseDownloadUrl = ((Invoke-RestMethod -Uri $assetsURL) -match 'win-x64').downloadurl Invoke-WebRequest -Uri $latestReleaseDownloadUrl -Method Get -OutFile "$agentTempFolderName\agent.zip" Write-Verbose "Downloaded agent successfully on attempt $retries" -verbose break } catch { $exceptionText = ($_ | Out-String).Trim() Write-Verbose "Exception occurred downloading agent: $exceptionText in try number $retries" -verbose $retries++ Start-Sleep -Seconds 30 } } while ($retries -le $retryCount) Write-Verbose "Installing agents $using:AgentCount" -verbose Write-Verbose "Installing agents $using:AgentCount" -verbose Write-Verbose "VSTSAccounbt - $using:VSTSAccount" -verbose Write-Verbose "Token" -verbose Write-Verbose "Agent count - $using:AgentCount" -verbose Write-Verbose "Entering InstallVSOAgent.ps1" -verbose $serverUrl = "https://dev.azure.com/$using:VSTSAccount" Write-Verbose "$serverUrl" -verbose for ($i=0; $i -lt $using:AgentCount; $i++) { $Agent = ($using:AgentName + "-" + ($i + 1)) Write-Verbose "Installing agents $Agent" -verbose # Construct the agent folder under the main (hardcoded) C: drive. $agentInstallationPath = Join-Path "C:" $Agent # Create the directory for this agent. New-Item -ItemType Directory -Force -Path $agentInstallationPath # Set the current directory to the agent dedicated one previously created. Push-Location -Path $agentInstallationPath Write-Verbose "Extracting the zip file for the agent" -verbose $destShellFolder = (new-object -com shell.application).namespace("$agentInstallationPath") $destShellFolder.CopyHere((new-object -com shell.application).namespace("$agentTempFolderName\agent.zip").Items(),16) # Removing the ZoneIdentifier from files downloaded from the internet so the plugins can be loaded # Don't recurse down _work or _diag, those files are not blocked and cause the process to take much longer Write-Verbose "Unblocking files" -verbose Get-ChildItem -Recurse -Path $agentInstallationPath | Unblock-File | out-null # Retrieve the path to the config.cmd file. $agentConfigPath = [System.IO.Path]::Combine($agentInstallationPath, 'config.cmd') Write-Verbose "Agent Location = $agentConfigPath" -Verbose if (![System.IO.File]::Exists($agentConfigPath)) { Write-Error "File not found: $agentConfigPath" -Verbose return } # Call the agent with the configure command and all the options (this creates the settings file) without prompting # the user or blocking the cmd execution Write-Verbose "Configuring agent '$($Agent)'" -Verbose $pat = $using:PersonalAccessToken #Write-Verbose "Configuring agent '$($pat)'" -Verbose .\config.cmd --unattended --url $serverUrl --auth PAT --token $pat --pool $using:PoolName --agent $Agent --runasservice Write-Verbose "Agent install output: $LASTEXITCODE" -Verbose Pop-Location } # Adding new Path to PSModulePath environment variable $CurrentValue = [Environment]::GetEnvironmentVariable("PSModulePath", "Machine") [Environment]::SetEnvironmentVariable("PSModulePath", $CurrentValue + ";C:\Modules", "Machine") $NewValue = [Environment]::GetEnvironmentVariable("PSModulePath", "Machine") Write-Verbose "new Path is: $($NewValue)" -verbose # Creating new Path if (!(Test-Path -Path C:\Modules -ErrorAction SilentlyContinue)) { New-Item -ItemType Directory -Name Modules -Path C:\ -Verbose } # Installing New Modules and Removing Old #Foreach ($Module in $using:Modules) { Find-Module -Name $Module.Name -RequiredVersion $Module.Version -Repository PSGallery -Verbose | Save-Module -Path C:\Modules -Verbose } #$DefaultModules = "PowerShellGet", "PackageManagement","Pester" Foreach ($Module in $DefaultModules) { if ($tmp = Get-Module $Module -ErrorAction SilentlyContinue) { Remove-Module $Module -Force } Find-Module -Name $Module -Repository PSGallery -Verbose | Install-Module -Force -Confirm:$false -SkipPublisherCheck -Verbose } # Uninstalling old Azure PowerShell Modules #$programName = "Microsoft Azure PowerShell" #$app = Get-WmiObject -Class Win32_Product -Filter "Name Like '$($programName)%'" -Verbose #$app.Uninstall() Write-Verbose "Exiting DeployVSTSAgent.Config.ps1" -Verbose } } } }