Skip to content

Instantly share code, notes, and snippets.

@michael-baker
Created September 7, 2021 09:27
Show Gist options
  • Save michael-baker/4a6b9815d8aeb63bed66d1810123f9ed to your computer and use it in GitHub Desktop.
Save michael-baker/4a6b9815d8aeb63bed66d1810123f9ed to your computer and use it in GitHub Desktop.
TFS Build Agent - Update Visual Studio 2019 Installation
# This script queries the default agent pool, gets all agents in that pool
# and executes setup.exe (Visual Studio Installer) and begins a silent update of Visual Studio 2019
# For TFS 2018
# Get all pools
$pools = Invoke-RestMethod -UseDefaultCredentials -Method Get -Uri "https://tfs.com/tfs/_apis/distributedtask/pools" -UseBasicParsing
# Find the ID of the pool we want
$id = $pools.value | Where-Object { $_.name -eq "Default" } | Select-Object -ExpandProperty id -Unique
$agents = Invoke-RestMethod -UseDefaultCredentials -Method Get -Uri "https://tfs.com/tfs/_apis/distributedtask/pools/$id/agents?includeCapabilities=false&includeAssignedRequest=true"
$hosts = $agents.value | Select-Object -ExpandProperty name | % { $_.Split('_')[0] }
foreach ($hostComputer in $hosts) {
Invoke-Command -ComputerName $hostComputer -ScriptBlock {
function Start-Process($filePath, $argumentList) {
Write-information "Starting $filePath $argumentList"
$psi = [System.Diagnostics.ProcessStartInfo]::new()
$psi.CreateNoWindow = $true
$psi.UseShellExecute = $false
$psi.RedirectStandardOutput = $true
$psi.RedirectStandardError = $true
$psi.FileName = $filePath
$psi.Arguments = $argumentList
$process = [System.Diagnostics.Process]::new()
# Adding event handers for stdout and stderr.
$scripBlock = {
if (![String]::IsNullOrEmpty($EventArgs.Data))
{
Write-Host $EventArgs.Data
}
}
$stdOutEvent = Register-ObjectEvent `
-InputObject $process `
-Action $scripBlock `
-EventName 'OutputDataReceived'
$stdErrEvent = Register-ObjectEvent `
-InputObject $process `
-Action $scripBlock `
-EventName 'ErrorDataReceived'
$process.StartInfo = $psi
try {
[void]$process.Start()
$process.BeginOutputReadLine()
$process.BeginErrorReadLine()
while (-not $process.WaitForExit(100)) {
# Allow interrupts like CTRL + C by doing a non-blocking wait
}
$process.WaitForExit()
} finally {
Unregister-Event -SourceIdentifier $stdOutEvent.Name
Unregister-Event -SourceIdentifier $stdErrEvent.Name
$Global:LASTEXITCODE = $process.ExitCode
$process.Dispose()
}
return $process
}
$isAdmin = [Security.Principal.WindowsPrincipal]::new(
[Security.Principal.WindowsIdentity]::GetCurrent()
).IsInRole([Security.Principal.WindowsBuiltinRole]::Administrator)
if (-not $isAdmin) {
throw "Not an administrator"
return
}
$InformationPreference = 'Continue'
$instance = Get-CimInstance MSFT_VSInstance | Where-Object { $_.Version -ge 16 } | Select-Object -First 1
$installer = [System.IO.Path]::Combine($instance.InstallLocation, "..\..\Installer\setup.exe")
Write-Information "Update Visual Studio"
$vsUpdateProcess = Start-Process -FilePath "$installer" -ArgumentList @(
"update",
"--installPath `"$($instance.InstallLocation)`"",
"--force",
"--quiet"
)
Write-Information "vs_installer.exe exited with code: $LASTEXITCODE"
Write-Information "Remove Components"
$vsUpdateProcess = Start-Process -FilePath "$installer" -ArgumentList @(
"modify",
"--installPath `"$($instance.InstallLocation)`"",
"--force",
"--quiet",
"--remove Component.IncredibuildMenu",
"--remove Component.IncredibuildMenu"
)
Write-Information "vs_installer.exe exited with code: $LASTEXITCODE"
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment