InstallVisualStudio.ps1 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  1. <#
  2. .SYNOPSIS
  3. Installs or updates Visual Studio on a local developer machine.
  4. .DESCRIPTION
  5. This installs Visual Studio along with all the workloads required to contribute to this repository.
  6. .PARAMETER Edition
  7. Selects which 'offering' of Visual Studio to install. Must be one of these values:
  8. BuildTools
  9. Community (the default)
  10. Professional
  11. Enterprise
  12. .PARAMETER Channel
  13. Selects which channel of Visual Studio to install. Must be one of these values:
  14. Release/Stable (the default)
  15. Preview/Insiders
  16. .PARAMETER Version
  17. Selects which version of Visual Studio to install. Must be one of these values:
  18. 2026
  19. .PARAMETER InstallPath
  20. The location on disk where Visual Studio should be installed or updated. Default path is location of latest
  21. existing installation of the specified edition, if any. If that VS edition is not currently installed, default
  22. path is '${env:ProgramFiles}\Microsoft Visual Studio\`$Version\`$Edition".
  23. .PARAMETER Passive
  24. Run the installer without requiring interaction.
  25. .PARAMETER Quiet
  26. Run the installer without UI and wait for installation to complete.
  27. .LINK
  28. https://visualstudio.com
  29. https://github.com/dotnet/aspnetcore/blob/main/docs/BuildFromSource.md
  30. .EXAMPLE
  31. To install VS 2026 Community, run this command in PowerShell:
  32. .\InstallVisualStudio.ps1
  33. #>
  34. param(
  35. [ValidateSet('BuildTools','Community', 'Professional', 'Enterprise')]
  36. [string]$Edition = 'Community',
  37. [ValidateSet('Release', 'Stable', 'Preview', 'Insiders', 'IntPreview', 'Dogfood')]
  38. [string]$Channel = 'Release',
  39. [ValidateSet('2026')]
  40. [string]$Version = '2026',
  41. [string]$InstallPath,
  42. [switch]$Passive,
  43. [switch]$Quiet
  44. )
  45. if ($env:TF_BUILD) {
  46. Write-Error 'This script is not intended for use on CI. It is only meant to be used to install a local developer environment. If you need to change Visual Studio requirements in CI agents, contact the @aspnet/build team.'
  47. exit 1
  48. }
  49. if ($Passive -and $Quiet) {
  50. Write-Host -ForegroundColor Red "Error: The -Passive and -Quiet options cannot be used together."
  51. Write-Host -ForegroundColor Red "Run ``Get-Help $PSCommandPath`` for more details."
  52. exit 1
  53. }
  54. $ErrorActionPreference = 'Stop'
  55. Set-StrictMode -Version 1
  56. $intermedateDir = "$PSScriptRoot\obj"
  57. mkdir $intermedateDir -ErrorAction Ignore | Out-Null
  58. $bootstrapper = "$intermedateDir\vsinstaller.exe"
  59. $ProgressPreference = 'SilentlyContinue' # Workaround PowerShell/PowerShell#2138
  60. $vsversion = 18;
  61. # Normalize channel names (Stable=Release, Insiders=Preview, Dogfood=IntPreview)
  62. switch ($Channel) {
  63. 'Stable' { $Channel = 'Release' }
  64. 'Insiders' { $Channel = 'Preview' }
  65. 'Dogfood' { $Channel = 'IntPreview' }
  66. }
  67. $responseFileName = "vs.$vsversion"
  68. if ("$Edition" -eq "BuildTools") {
  69. $responseFileName += ".buildtools"
  70. }
  71. if ("$Channel" -eq "Preview") {
  72. $responseFileName += ".preview"
  73. $channelUri = "https://aka.ms/vs/$vsversion/insiders"
  74. } elseif ("$Channel" -eq "IntPreview") {
  75. $responseFileName += ".intpreview"
  76. $channelUri = "https://aka.ms/vs/$vsversion/intpreview"
  77. } else {
  78. # Release channel
  79. $channelUri = "https://aka.ms/vs/$vsversion/stable"
  80. }
  81. $responseFile = "$PSScriptRoot\$responseFileName.json"
  82. $channelId = (Get-Content $responseFile | ConvertFrom-Json).channelId
  83. $bootstrapperUri = "$channelUri/vs_$($Edition.ToLowerInvariant()).exe"
  84. Write-Host "Downloading Visual Studio $Version $Edition ($Channel) bootstrapper from $bootstrapperUri"
  85. Invoke-WebRequest -Uri $bootstrapperUri -OutFile $bootstrapper
  86. $productId = "Microsoft.VisualStudio.Product.$Edition"
  87. if (-not $InstallPath) {
  88. $vsWhere = "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.exe"
  89. if (Test-Path $vsWhere)
  90. {
  91. $installations = & $vsWhere -version "[$vsversion,$($vsversion+1))" -format json -prerelease -products $productId | ConvertFrom-Json |Sort-Object -Descending -Property installationVersion, installDate
  92. foreach ($installation in $installations) {
  93. Write-Host "Found '$($installation.installationName)' in '$($installation.installationPath)', channel = '$($installation.channelId)'"
  94. if ($installation.channelId -eq $channelId) {
  95. $InstallPath = $installation.installationPath
  96. break
  97. }
  98. }
  99. }
  100. }
  101. if (-not $InstallPath) {
  102. $pathPrefix = "${env:ProgramFiles}";
  103. if ("$Channel" -eq "Preview") {
  104. $InstallPath = "$pathPrefix\Microsoft Visual Studio\$Version\${Edition}_Insiders"
  105. } elseif ("$Channel" -eq "IntPreview") {
  106. $InstallPath = "$pathPrefix\Microsoft Visual Studio\$Version\${Edition}_IntPre"
  107. } else {
  108. $InstallPath = "$pathPrefix\Microsoft Visual Studio\$Version\$Edition"
  109. }
  110. }
  111. # no backslashes - this breaks the installer
  112. $InstallPath = $InstallPath.TrimEnd('\')
  113. [string[]] $arguments = @()
  114. if (Test-path $InstallPath) {
  115. $arguments += 'modify'
  116. }
  117. $arguments += `
  118. '--productId', $productId, `
  119. '--installPath', "`"$InstallPath`"", `
  120. '--in', "`"$responseFile`""
  121. if ($Passive) {
  122. $arguments += '--passive', '--norestart'
  123. }
  124. if ($Quiet) {
  125. $arguments += '--quiet', '--wait', '--norestart'
  126. }
  127. Write-Host
  128. Write-Host "Installing Visual Studio $Version $Edition ($Channel)" -f Magenta
  129. Write-Host
  130. Write-Host "Running '$bootstrapper $arguments'"
  131. foreach ($i in 0, 1, 2) {
  132. if ($i -ne 0) {
  133. Write-Host "Retrying..."
  134. }
  135. $process = Start-Process -FilePath "$bootstrapper" -ArgumentList $arguments -ErrorAction Continue -PassThru `
  136. -RedirectStandardError "$intermedateDir\errors.txt" -Verbose -Wait
  137. Write-Host "Exit code = $($process.ExitCode)."
  138. if ($process.ExitCode -eq 0) {
  139. break
  140. } else {
  141. # https://learn.microsoft.com/visualstudio/install/use-command-line-parameters-to-install-visual-studio#error-codes
  142. if ($process.ExitCode -eq 3010) {
  143. Write-Host -ForegroundColor Red "Error: Installation requires restart to finish the VS update."
  144. break
  145. }
  146. elseif ($process.ExitCode -eq 5007) {
  147. Write-Host -ForegroundColor Red "Error: Operation was blocked - the computer does not meet the requirements."
  148. break
  149. }
  150. elseif (($process.ExitCode -eq 5004) -or ($process.ExitCode -eq 1602)) {
  151. Write-Host -ForegroundColor Red "Error: Operation was canceled."
  152. }
  153. else {
  154. Write-Host -ForegroundColor Red "Error: Installation failed for an unknown reason."
  155. }
  156. Write-Host
  157. Write-Host "Errors:"
  158. Get-Content "$intermedateDir\errors.txt" | Write-Warning
  159. Write-Host
  160. Get-ChildItem $env:Temp\dd_bootstrapper_*.log |Sort-Object CreationTime -Descending |Select-Object -First 1 |% {
  161. Write-Host "${_}:"
  162. Get-Content "$_"
  163. Write-Host
  164. }
  165. $clientLogs = Get-ChildItem $env:Temp\dd_client_*.log |Sort-Object CreationTime -Descending |Select-Object -First 1 |% {
  166. Write-Host "${_}:"
  167. Get-Content "$_"
  168. Write-Host
  169. }
  170. $setupLogs = Get-ChildItem $env:Temp\dd_setup_*.log |Sort-Object CreationTime -Descending |Select-Object -First 1 |% {
  171. Write-Host "${_}:"
  172. Get-Content "$_"
  173. Write-Host
  174. }
  175. }
  176. }
  177. Remove-Item "$intermedateDir\errors.txt" -errorAction SilentlyContinue
  178. exit $process.ExitCode