InstallVisualStudio.ps1 7.0 KB

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