Skip to content

Commit 8b02c4c

Browse files
authored
Merge pull request #705 from dotnet/scriptUpdates
Update Install-DotNetSdk.ps1 script
2 parents 553bd06 + f2e167e commit 8b02c4c

File tree

1 file changed

+108
-35
lines changed

1 file changed

+108
-35
lines changed

tools/Install-DotNetSdk.ps1

Lines changed: 108 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,19 @@
22

33
<#
44
.SYNOPSIS
5-
Installs the .NET SDK specified in the global.json file at the root of this repository,
6-
along with supporting .NET Core runtimes used for testing.
5+
Installs the .NET SDK specified in the global.json file at the root of this repository,
6+
along with supporting .NET Core runtimes used for testing.
77
.DESCRIPTION
8-
This MAY not require elevation, as the SDK and runtimes are installed locally to this repo location,
9-
unless `-InstallLocality machine` is specified.
8+
This MAY not require elevation, as the SDK and runtimes are installed locally to this repo location,
9+
unless `-InstallLocality machine` is specified.
1010
.PARAMETER InstallLocality
11-
A value indicating whether dependencies should be installed locally to the repo or at a per-user location.
12-
Per-user allows sharing the installed dependencies across repositories and allows use of a shared expanded package cache.
13-
Visual Studio will only notice and use these SDKs/runtimes if VS is launched from the environment that runs this script.
14-
Per-repo allows for high isolation, allowing for a more precise recreation of the environment within an Azure Pipelines build.
15-
When using 'repo', environment variables are set to cause the locally installed dotnet SDK to be used.
16-
Per-repo can lead to file locking issues when dotnet.exe is left running as a build server and can be mitigated by running `dotnet build-server shutdown`.
17-
Per-machine requires elevation and will download and install all SDKs and runtimes to machine-wide locations so all applications can find it.
11+
A value indicating whether dependencies should be installed locally to the repo or at a per-user location.
12+
Per-user allows sharing the installed dependencies across repositories and allows use of a shared expanded package cache.
13+
Visual Studio will only notice and use these SDKs/runtimes if VS is launched from the environment that runs this script.
14+
Per-repo allows for high isolation, allowing for a more precise recreation of the environment within an Azure Pipelines build.
15+
When using 'repo', environment variables are set to cause the locally installed dotnet SDK to be used.
16+
Per-repo can lead to file locking issues when dotnet.exe is left running as a build server and can be mitigated by running `dotnet build-server shutdown`.
17+
Per-machine requires elevation and will download and install all SDKs and runtimes to machine-wide locations so all applications can find it.
1818
#>
1919
[CmdletBinding(SupportsShouldProcess=$true,ConfirmImpact='Medium')]
2020
Param (
@@ -29,20 +29,43 @@ $DotNetInstallScriptRoot = Resolve-Path $DotNetInstallScriptRoot
2929
# Look up actual required .NET Core SDK version from global.json
3030
$sdkVersion = & "$PSScriptRoot/../azure-pipelines/variables/DotNetSdkVersion.ps1"
3131

32+
$arch = [System.Runtime.InteropServices.RuntimeInformation]::ProcessArchitecture
33+
if (!$arch) { # Windows Powershell leaves this blank
34+
$arch = 'x64'
35+
if ($env:PROCESSOR_ARCHITECTURE -eq 'ARM64') { $arch = 'ARM64' }
36+
}
37+
3238
# Search for all .NET Core runtime versions referenced from MSBuild projects and arrange to install them.
3339
$runtimeVersions = @()
40+
$windowsDesktopRuntimeVersions = @()
3441
Get-ChildItem "$PSScriptRoot\..\src\*.*proj","$PSScriptRoot\..\Directory.Build.props" -Recurse |% {
3542
$projXml = [xml](Get-Content -Path $_)
36-
$targetFrameworks = $projXml.Project.PropertyGroup.TargetFramework
37-
if (!$targetFrameworks) {
38-
$targetFrameworks = $projXml.Project.PropertyGroup.TargetFrameworks
39-
if ($targetFrameworks) {
40-
$targetFrameworks = $targetFrameworks -Split ';'
43+
$pg = $projXml.Project.PropertyGroup
44+
if ($pg) {
45+
$targetFrameworks = $pg.TargetFramework
46+
if (!$targetFrameworks) {
47+
$targetFrameworks = $pg.TargetFrameworks
48+
if ($targetFrameworks) {
49+
$targetFrameworks = $targetFrameworks -Split ';'
50+
}
4151
}
4252
}
43-
$targetFrameworks |? { $_ -match 'netcoreapp(\d+\.\d+)' } |% {
44-
$runtimeVersions += $Matches[1]
53+
$targetFrameworks |? { $_ -match 'net(?:coreapp)?(\d+\.\d+)' } |% {
54+
$v = $Matches[1]
55+
$runtimeVersions += $v
56+
if ($v -ge '3.0' -and -not ($IsMacOS -or $IsLinux)) {
57+
$windowsDesktopRuntimeVersions += $v
58+
}
4559
}
60+
61+
# Add target frameworks of the form: netXX
62+
$targetFrameworks |? { $_ -match 'net(\d+\.\d+)' } |% {
63+
$v = $Matches[1]
64+
$runtimeVersions += $v
65+
if (-not ($IsMacOS -or $IsLinux)) {
66+
$windowsDesktopRuntimeVersions += $v
67+
}
68+
}
4669
}
4770

4871
Function Get-FileFromWeb([Uri]$Uri, $OutDir) {
@@ -69,43 +92,53 @@ Function Get-InstallerExe($Version, [switch]$Runtime) {
6992
$Version = $versionInfo[-1]
7093
}
7194

72-
Get-FileFromWeb -Uri "https://dotnetcli.blob.core.windows.net/dotnet/$sdkOrRuntime/$Version/dotnet-$($sdkOrRuntime.ToLowerInvariant())-$Version-win-x64.exe" -OutDir "$DotNetInstallScriptRoot"
95+
Get-FileFromWeb -Uri "https://dotnetcli.blob.core.windows.net/dotnet/$sdkOrRuntime/$Version/dotnet-$($sdkOrRuntime.ToLowerInvariant())-$Version-win-$arch.exe" -OutDir "$DotNetInstallScriptRoot"
7396
}
7497

7598
Function Install-DotNet($Version, [switch]$Runtime) {
7699
if ($Runtime) { $sdkSubstring = '' } else { $sdkSubstring = 'SDK ' }
77100
Write-Host "Downloading .NET Core $sdkSubstring$Version..."
78101
$Installer = Get-InstallerExe -Version $Version -Runtime:$Runtime
79102
Write-Host "Installing .NET Core $sdkSubstring$Version..."
80-
cmd /c start /wait $Installer /install /quiet
81-
if ($LASTEXITCODE -ne 0) {
103+
cmd /c start /wait $Installer /install /passive /norestart
104+
if ($LASTEXITCODE -eq 3010) {
105+
Write-Verbose "Restart required"
106+
} elseif ($LASTEXITCODE -ne 0) {
82107
throw "Failure to install .NET Core SDK"
83108
}
84109
}
85110

86111
$switches = @(
87-
'-Architecture','x64'
112+
'-Architecture',$arch
88113
)
89114
$envVars = @{
90115
# For locally installed dotnet, skip first time experience which takes a long time
91116
'DOTNET_SKIP_FIRST_TIME_EXPERIENCE' = 'true';
92117
}
93118

94119
if ($InstallLocality -eq 'machine') {
95-
if ($IsWindows) {
120+
if ($IsMacOS -or $IsLinux) {
121+
$DotNetInstallDir = '/usr/share/dotnet'
122+
} else {
123+
$restartRequired = $false
96124
if ($PSCmdlet.ShouldProcess(".NET Core SDK $sdkVersion", "Install")) {
97125
Install-DotNet -Version $sdkVersion
126+
$restartRequired = $restartRequired -or ($LASTEXITCODE -eq 3010)
98127
}
99128

100129
$runtimeVersions | Get-Unique |% {
101130
if ($PSCmdlet.ShouldProcess(".NET Core runtime $_", "Install")) {
102131
Install-DotNet -Version $_ -Runtime
132+
$restartRequired = $restartRequired -or ($LASTEXITCODE -eq 3010)
103133
}
104134
}
105135

136+
if ($restartRequired) {
137+
Write-Host -ForegroundColor Yellow "System restart required"
138+
Exit 3010
139+
}
140+
106141
return
107-
} else {
108-
$DotNetInstallDir = '/usr/share/dotnet'
109142
}
110143
} elseif ($InstallLocality -eq 'repo') {
111144
$DotNetInstallDir = "$DotNetInstallScriptRoot/.dotnet"
@@ -118,16 +151,16 @@ if ($InstallLocality -eq 'machine') {
118151
Write-Host "Installing .NET Core SDK and runtimes to $DotNetInstallDir" -ForegroundColor Blue
119152

120153
if ($DotNetInstallDir) {
121-
$switches += '-InstallDir',$DotNetInstallDir
154+
$switches += '-InstallDir',"`"$DotNetInstallDir`""
122155
$envVars['DOTNET_MULTILEVEL_LOOKUP'] = '0'
123156
$envVars['DOTNET_ROOT'] = $DotNetInstallDir
124157
}
125158

126159
if ($IsMacOS -or $IsLinux) {
127-
$DownloadUri = "https://dot.net/v1/dotnet-install.sh"
160+
$DownloadUri = "https://raw.githubusercontent.com/dotnet/install-scripts/781752509a890ca7520f1182e8bae71f9a53d754/src/dotnet-install.sh"
128161
$DotNetInstallScriptPath = "$DotNetInstallScriptRoot/dotnet-install.sh"
129162
} else {
130-
$DownloadUri = "https://dot.net/v1/dotnet-install.ps1"
163+
$DownloadUri = "https://raw.githubusercontent.com/dotnet/install-scripts/781752509a890ca7520f1182e8bae71f9a53d754/src/dotnet-install.ps1"
131164
$DotNetInstallScriptPath = "$DotNetInstallScriptRoot/dotnet-install.ps1"
132165
}
133166

@@ -138,22 +171,62 @@ if (-not (Test-Path $DotNetInstallScriptPath)) {
138171
}
139172
}
140173

174+
# In case the script we invoke is in a directory with spaces, wrap it with single quotes.
175+
# In case the path includes single quotes, escape them.
176+
$DotNetInstallScriptPathExpression = $DotNetInstallScriptPath.Replace("'", "''")
177+
$DotNetInstallScriptPathExpression = "& '$DotNetInstallScriptPathExpression'"
178+
179+
$anythingInstalled = $false
180+
$global:LASTEXITCODE = 0
181+
141182
if ($PSCmdlet.ShouldProcess(".NET Core SDK $sdkVersion", "Install")) {
142-
Invoke-Expression -Command "$DotNetInstallScriptPath -Version $sdkVersion $switches"
183+
$anythingInstalled = $true
184+
Invoke-Expression -Command "$DotNetInstallScriptPathExpression -Version $sdkVersion $switches"
185+
186+
if ($LASTEXITCODE -ne 0) {
187+
Write-Error ".NET SDK installation failure: $LASTEXITCODE"
188+
exit $LASTEXITCODE
189+
}
143190
} else {
144-
Invoke-Expression -Command "$DotNetInstallScriptPath -Version $sdkVersion $switches -DryRun"
191+
Invoke-Expression -Command "$DotNetInstallScriptPathExpression -Version $sdkVersion $switches -DryRun"
145192
}
146193

147-
$switches += '-Runtime','dotnet'
194+
$dotnetRuntimeSwitches = $switches + '-Runtime','dotnet'
148195

149-
$runtimeVersions | Get-Unique |% {
196+
$runtimeVersions | Sort-Object -Unique |% {
150197
if ($PSCmdlet.ShouldProcess(".NET Core runtime $_", "Install")) {
151-
Invoke-Expression -Command "$DotNetInstallScriptPath -Channel $_ $switches"
198+
$anythingInstalled = $true
199+
Invoke-Expression -Command "$DotNetInstallScriptPathExpression -Channel $_ $dotnetRuntimeSwitches"
200+
201+
if ($LASTEXITCODE -ne 0) {
202+
Write-Error ".NET SDK installation failure: $LASTEXITCODE"
203+
exit $LASTEXITCODE
204+
}
152205
} else {
153-
Invoke-Expression -Command "$DotNetInstallScriptPath -Channel $_ $switches -DryRun"
206+
Invoke-Expression -Command "$DotNetInstallScriptPathExpression -Channel $_ $dotnetRuntimeSwitches -DryRun"
207+
}
208+
}
209+
210+
$windowsDesktopRuntimeSwitches = $switches + '-Runtime','windowsdesktop'
211+
212+
$windowsDesktopRuntimeVersions | Sort-Object -Unique |% {
213+
if ($PSCmdlet.ShouldProcess(".NET Core WindowsDesktop runtime $_", "Install")) {
214+
$anythingInstalled = $true
215+
Invoke-Expression -Command "$DotNetInstallScriptPathExpression -Channel $_ $windowsDesktopRuntimeSwitches"
216+
217+
if ($LASTEXITCODE -ne 0) {
218+
Write-Error ".NET SDK installation failure: $LASTEXITCODE"
219+
exit $LASTEXITCODE
220+
}
221+
} else {
222+
Invoke-Expression -Command "$DotNetInstallScriptPathExpression -Channel $_ $windowsDesktopRuntimeSwitches -DryRun"
154223
}
155224
}
156225

157226
if ($PSCmdlet.ShouldProcess("Set DOTNET environment variables to discover these installed runtimes?")) {
158-
& "$PSScriptRoot/../azure-pipelines/Set-EnvVars.ps1" -Variables $envVars -PrependPath $DotNetInstallDir | Out-Null
227+
& "$PSScriptRoot/Set-EnvVars.ps1" -Variables $envVars -PrependPath $DotNetInstallDir | Out-Null
228+
}
229+
230+
if ($anythingInstalled -and ($InstallLocality -ne 'machine') -and !$env:TF_BUILD -and !$env:GITHUB_ACTIONS) {
231+
Write-Warning ".NET Core runtimes or SDKs were installed to a non-machine location. Perform your builds or open Visual Studio from this same environment in order for tools to discover the location of these dependencies."
159232
}

0 commit comments

Comments
 (0)