Skip to content

Instantly share code, notes, and snippets.

@jschlackman
Last active March 6, 2025 22:06
Show Gist options
  • Save jschlackman/dfd06a69250606edfa080aae503aecfc to your computer and use it in GitHub Desktop.
Save jschlackman/dfd06a69250606edfa080aae503aecfc to your computer and use it in GitHub Desktop.
<#
.SYNOPSIS
Starts automatic update for all installed Visual Studio instances.
.DESCRIPTION
Gets details of all current Visual Studio installs on this machine and attempts to run the updater for each installation found.
This script can be run using Task Scheduler or an RMM to periodicially check for and apply Visual Studio updates.
Author: James Schlackman <[email protected]>
Last Modified: March 6 2025
.PARAMETER ForceUpdate
Whether to forcibly close any running processes if they need updating.
.LINK
https://learn.microsoft.com/en-us/visualstudio/install/tools-for-managing-visual-studio-instances
.LINK
https://learn.microsoft.com/en-us/visualstudio/install/use-command-line-parameters-to-install-visual-studio
#>
#Requires -RunAsAdministrator
Param(
[Parameter()] [Switch] $ForceUpdate
)
# Set update param according to whether forced update flag is set
If ($ForceUpdate) {
Write-Warning 'Forced update is enabled. Any running instances of Visual Studio will be closed without prompting.'
$updateParam = '--force'
} Else {
$updateParam = '--norestart'
}
$vsWhere = "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.exe"
# If vswhere command was found, run it and parse the output
If (Test-Path $vsWhere) {
$vsInstalls = (. $vsWhere -prerelease -format json) | ConvertFrom-Json
} Else {
$vsInstalls = $null
Write-Warning 'vswhere.exe not found.'
}
# If vshwere reports at least one installed instance
If ($vsInstalls) {
$installFields = 'displayName', 'installationName', 'installationVersion', 'isRebootRequired'
Write-Host ('Installs found: {0}' -f $vsInstalls.Count)
Write-Host ($vsInstalls | Select $installFields | Out-String)
# Now run the updater for each installation
$vsInstalls | Where-Object {$_} | ForEach-Object {
Write-Host ("`nStarting update for {0}, version {1} (last updated {2})`n" -f $_.displayName, $_.installationVersion, (Get-Date($_.updateDate)).ToShortDateString()) -ForegroundColor Cyan
$updateTask = Start-Process -PassThru -Wait -FilePath $_.properties.setupEngineFilePath -ArgumentList ('update --quiet {0} --installPath "{1}"' -f $updateParam, $_.installationPath)
Write-Host
$resultText = "Updater exited with code {0} (Start Time: {1}, End Time: {2})`n" -f $updateTask.ExitCode, $updateTask.StartTime, $updateTask.ExitTime
# Output update task summary
If ($updateTask.ExitCode -eq 0) {
Write-Host $resultText -ForegroundColor Green
} Else {
Write-Warning $resultText
}
}
# Now get installed version info again
$vsInstalls = (. $vsWhere -prerelease -format json) | ConvertFrom-Json
Write-Host 'Update results:' -ForegroundColor Cyan
Write-Host ($vsInstalls | Select $installFields | Out-String)
If ($vsInstalls.isRebootRequired -contains $true) {
Write-Warning 'A reboot is required but has been suppressed'
}
} Else {
Write-Host 'No instances of Visual Studio found.'
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment