InstallVisualStudio.ps1 6.4 KB

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