You've already forked setup-dotnet
							
							
				mirror of
				https://github.com/actions/setup-dotnet.git
				synced 2025-11-04 08:56:35 +07:00 
			
		
		
		
	New cdn url changes
This commit is contained in:
		
							
								
								
									
										2
									
								
								.github/workflows/check-dist.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.github/workflows/check-dist.yml
									
									
									
									
										vendored
									
									
								
							@ -44,7 +44,7 @@ jobs:
 | 
			
		||||
        id: diff
 | 
			
		||||
 | 
			
		||||
      # If index.js was different than expected, upload the expected version as an artifact
 | 
			
		||||
      - uses: actions/upload-artifact@v2
 | 
			
		||||
      - uses: actions/upload-artifact@v4
 | 
			
		||||
        if: ${{ failure() && steps.diff.conclusion == 'failure' }}
 | 
			
		||||
        with:
 | 
			
		||||
          name: dist
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										2
									
								
								.github/workflows/test-dotnet.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.github/workflows/test-dotnet.yml
									
									
									
									
										vendored
									
									
								
							@ -17,7 +17,7 @@ jobs:
 | 
			
		||||
    strategy:
 | 
			
		||||
      fail-fast: false
 | 
			
		||||
      matrix:
 | 
			
		||||
        operating-system: [ubuntu-latest, windows-latest, macOS-latest]
 | 
			
		||||
        operating-system: [ubuntu-22.04, windows-latest, macOS-latest]
 | 
			
		||||
        dotnet-version: ['2.1', '2.2', '3.0', '3.1', '5.0']
 | 
			
		||||
    steps:
 | 
			
		||||
      - name: Checkout
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										24
									
								
								.github/workflows/workflow.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										24
									
								
								.github/workflows/workflow.yml
									
									
									
									
										vendored
									
									
								
							@ -17,7 +17,7 @@ jobs:
 | 
			
		||||
    strategy:
 | 
			
		||||
      fail-fast: false
 | 
			
		||||
      matrix:
 | 
			
		||||
        operating-system: [ubuntu-latest, windows-latest, macOS-latest]
 | 
			
		||||
        operating-system: [ubuntu-22.04, windows-latest, macOS-latest]
 | 
			
		||||
    steps:
 | 
			
		||||
    - name: Checkout
 | 
			
		||||
      uses: actions/checkout@v2
 | 
			
		||||
@ -38,7 +38,7 @@ jobs:
 | 
			
		||||
    strategy:
 | 
			
		||||
      fail-fast: false
 | 
			
		||||
      matrix:
 | 
			
		||||
        operating-system: [ubuntu-latest, windows-latest, macOS-latest]
 | 
			
		||||
        operating-system: [ubuntu-22.04, windows-latest, macOS-latest]
 | 
			
		||||
    steps:
 | 
			
		||||
      - name: Checkout
 | 
			
		||||
        uses: actions/checkout@v2
 | 
			
		||||
@ -61,7 +61,7 @@ jobs:
 | 
			
		||||
    strategy:
 | 
			
		||||
      fail-fast: false
 | 
			
		||||
      matrix:
 | 
			
		||||
        operating-system: [ubuntu-latest, windows-latest, macOS-latest]
 | 
			
		||||
        operating-system: [ubuntu-22.04, windows-latest, macos-13]
 | 
			
		||||
    steps:
 | 
			
		||||
      - name: Checkout
 | 
			
		||||
        uses: actions/checkout@v2
 | 
			
		||||
@ -94,7 +94,7 @@ jobs:
 | 
			
		||||
    strategy:
 | 
			
		||||
      fail-fast: false
 | 
			
		||||
      matrix:
 | 
			
		||||
        operating-system: [ubuntu-latest, windows-latest, macOS-latest]
 | 
			
		||||
        operating-system: [ubuntu-22.04, windows-latest, macOS-latest]
 | 
			
		||||
    steps:
 | 
			
		||||
      - name: Checkout
 | 
			
		||||
        uses: actions/checkout@v2
 | 
			
		||||
@ -119,7 +119,7 @@ jobs:
 | 
			
		||||
    strategy:
 | 
			
		||||
      fail-fast: false
 | 
			
		||||
      matrix:
 | 
			
		||||
        operating-system: [ubuntu-latest, windows-latest, macOS-latest]
 | 
			
		||||
        operating-system: [ubuntu-22.04, windows-latest, macOS-latest]
 | 
			
		||||
    steps:
 | 
			
		||||
      - name: Checkout
 | 
			
		||||
        uses: actions/checkout@v2
 | 
			
		||||
@ -143,7 +143,7 @@ jobs:
 | 
			
		||||
    strategy:
 | 
			
		||||
      fail-fast: false
 | 
			
		||||
      matrix:
 | 
			
		||||
        operating-system: [ubuntu-latest, windows-latest, macOS-latest]
 | 
			
		||||
        operating-system: [ubuntu-22.04, windows-latest, macOS-latest]
 | 
			
		||||
    steps:
 | 
			
		||||
      - name: Checkout
 | 
			
		||||
        uses: actions/checkout@v2
 | 
			
		||||
@ -163,18 +163,20 @@ jobs:
 | 
			
		||||
        run: __tests__/verify-dotnet.ps1 3.1 2.2
 | 
			
		||||
 | 
			
		||||
  test-proxy:
 | 
			
		||||
    runs-on: ubuntu-latest
 | 
			
		||||
    runs-on: ubuntu-22.04
 | 
			
		||||
    container:
 | 
			
		||||
      image: mcr.microsoft.com/dotnet/core/runtime-deps:3.0-bionic
 | 
			
		||||
      image: ubuntu:latest
 | 
			
		||||
      options: --dns 127.0.0.1
 | 
			
		||||
    services:
 | 
			
		||||
      squid-proxy:
 | 
			
		||||
        image: datadog/squid:latest
 | 
			
		||||
        image: ubuntu/squid:latest
 | 
			
		||||
        ports:
 | 
			
		||||
          - 3128:3128
 | 
			
		||||
    env:
 | 
			
		||||
      https_proxy: http://squid-proxy:3128
 | 
			
		||||
      http_proxy: http://squid-proxy:3128
 | 
			
		||||
      DOTNET_SYSTEM_GLOBALIZATION_INVARIANT: true
 | 
			
		||||
 | 
			
		||||
    steps:
 | 
			
		||||
      - name: Checkout
 | 
			
		||||
        uses: actions/checkout@v2
 | 
			
		||||
@ -183,7 +185,7 @@ jobs:
 | 
			
		||||
      - name: Install curl
 | 
			
		||||
        run: |
 | 
			
		||||
          apt update
 | 
			
		||||
          apt -y install curl
 | 
			
		||||
          apt -y install curl libssl-dev
 | 
			
		||||
      - name: Setup dotnet 3.1.201
 | 
			
		||||
        uses: ./
 | 
			
		||||
        with:
 | 
			
		||||
@ -195,7 +197,7 @@ jobs:
 | 
			
		||||
        run: __tests__/verify-dotnet.sh 3.1.201
 | 
			
		||||
 | 
			
		||||
  test-bypass-proxy:
 | 
			
		||||
    runs-on: ubuntu-latest
 | 
			
		||||
    runs-on: ubuntu-22.04
 | 
			
		||||
    env:
 | 
			
		||||
      https_proxy: http://no-such-proxy:3128
 | 
			
		||||
      no_proxy: github.com,dotnetcli.blob.core.windows.net,download.visualstudio.microsoft.com,api.nuget.org,dotnetcli.azureedge.net
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										531
									
								
								externals/install-dotnet.ps1
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										531
									
								
								externals/install-dotnet.ps1
									
									
									
									
										vendored
									
									
								
							@ -9,27 +9,34 @@
 | 
			
		||||
.DESCRIPTION
 | 
			
		||||
    Installs dotnet cli. If dotnet installation already exists in the given directory
 | 
			
		||||
    it will update it only if the requested version differs from the one already installed.
 | 
			
		||||
 | 
			
		||||
    Note that the intended use of this script is for Continuous Integration (CI) scenarios, where:
 | 
			
		||||
    - The SDK needs to be installed without user interaction and without admin rights.
 | 
			
		||||
    - The SDK installation doesn't need to persist across multiple CI runs.
 | 
			
		||||
    To set up a development environment or to run apps, use installers rather than this script. Visit https://dotnet.microsoft.com/download to get the installer.
 | 
			
		||||
 | 
			
		||||
.PARAMETER Channel
 | 
			
		||||
    Default: LTS
 | 
			
		||||
    Download from the Channel specified. Possible values:
 | 
			
		||||
    - Current - most current release
 | 
			
		||||
    - LTS - most current supported release
 | 
			
		||||
    - STS - the most recent Standard Term Support release
 | 
			
		||||
    - LTS - the most recent Long Term Support release
 | 
			
		||||
    - 2-part version in a format A.B - represents a specific release
 | 
			
		||||
          examples: 2.0, 1.0
 | 
			
		||||
    - 3-part version in a format A.B.Cxx - represents a specific SDK release
 | 
			
		||||
          examples: 5.0.1xx, 5.0.2xx
 | 
			
		||||
          Supported since 5.0 release
 | 
			
		||||
    Warning: Value "Current" is deprecated for the Channel parameter. Use "STS" instead.
 | 
			
		||||
    Note: The version parameter overrides the channel parameter when any version other than 'latest' is used.
 | 
			
		||||
.PARAMETER Quality
 | 
			
		||||
    Download the latest build of specified quality in the channel. The possible values are: daily, signed, validated, preview, GA.
 | 
			
		||||
    Works only in combination with channel. Not applicable for current and LTS channels and will be ignored if those channels are used. 
 | 
			
		||||
    Works only in combination with channel. Not applicable for STS and LTS channels and will be ignored if those channels are used. 
 | 
			
		||||
    For SDK use channel in A.B.Cxx format: using quality together with channel in A.B format is not supported.
 | 
			
		||||
    Supported since 5.0 release.
 | 
			
		||||
    Note: The version parameter overrides the channel parameter when any version other than 'latest' is used, and therefore overrides the quality.     
 | 
			
		||||
.PARAMETER Version
 | 
			
		||||
    Default: latest
 | 
			
		||||
    Represents a build version on specific channel. Possible values:
 | 
			
		||||
    - latest - most latest build on specific channel
 | 
			
		||||
    - latest - the latest build on specific channel
 | 
			
		||||
    - 3-part version in a format A.B.C - represents specific version of build
 | 
			
		||||
          examples: 2.0.0-preview2-006120, 1.1.0
 | 
			
		||||
.PARAMETER Internal
 | 
			
		||||
@ -91,6 +98,16 @@
 | 
			
		||||
.PARAMETER DownloadTimeout
 | 
			
		||||
    Determines timeout duration in seconds for dowloading of the SDK file
 | 
			
		||||
    Default: 1200 seconds (20 minutes)
 | 
			
		||||
.PARAMETER KeepZip
 | 
			
		||||
    If set, downloaded file is kept
 | 
			
		||||
.PARAMETER ZipPath
 | 
			
		||||
    Use that path to store installer, generated by default
 | 
			
		||||
.EXAMPLE
 | 
			
		||||
    dotnet-install.ps1 -Version 7.0.401
 | 
			
		||||
    Installs the .NET SDK version 7.0.401
 | 
			
		||||
.EXAMPLE
 | 
			
		||||
    dotnet-install.ps1 -Channel 8.0 -Quality GA
 | 
			
		||||
    Installs the latest GA (general availability) version of the .NET 8.0 SDK
 | 
			
		||||
#>
 | 
			
		||||
[cmdletbinding()]
 | 
			
		||||
param(
 | 
			
		||||
@ -114,7 +131,10 @@ param(
 | 
			
		||||
    [string[]]$ProxyBypassList = @(),
 | 
			
		||||
    [switch]$SkipNonVersionedFiles,
 | 
			
		||||
    [switch]$NoCdn,
 | 
			
		||||
   [int]$DownloadTimeout=1200
 | 
			
		||||
    [int]$DownloadTimeout = 1200,
 | 
			
		||||
    [switch]$KeepZip,
 | 
			
		||||
    [string]$ZipPath = [System.IO.Path]::combine([System.IO.Path]::GetTempPath(), [System.IO.Path]::GetRandomFileName()),
 | 
			
		||||
    [switch]$Help
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
Set-StrictMode -Version Latest
 | 
			
		||||
@ -163,6 +183,29 @@ function Say-Verbose($str) {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function Measure-Action($name, $block) {
 | 
			
		||||
    $time = Measure-Command $block
 | 
			
		||||
    $totalSeconds = $time.TotalSeconds
 | 
			
		||||
    Say-Verbose "Action '$name' took $totalSeconds seconds"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function Get-Remote-File-Size($zipUri) {
 | 
			
		||||
    try {
 | 
			
		||||
        $response = Invoke-WebRequest -Uri $zipUri -Method Head
 | 
			
		||||
        $fileSize = $response.Headers["Content-Length"]
 | 
			
		||||
        if ((![string]::IsNullOrEmpty($fileSize))) {
 | 
			
		||||
            Say "Remote file $zipUri size is $fileSize bytes."
 | 
			
		||||
        
 | 
			
		||||
            return $fileSize
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    catch {
 | 
			
		||||
        Say-Verbose "Content-Length header was not extracted for $zipUri."
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return $null
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function Say-Invocation($Invocation) {
 | 
			
		||||
    $command = $Invocation.MyCommand;
 | 
			
		||||
    $args = (($Invocation.BoundParameters.Keys | foreach { "-$_ `"$($Invocation.BoundParameters[$_])`"" }) -join " ")
 | 
			
		||||
@ -171,6 +214,7 @@ function Say-Invocation($Invocation) {
 | 
			
		||||
 | 
			
		||||
function Invoke-With-Retry([ScriptBlock]$ScriptBlock, [System.Threading.CancellationToken]$cancellationToken = [System.Threading.CancellationToken]::None, [int]$MaxAttempts = 3, [int]$SecondsBetweenAttempts = 1) {
 | 
			
		||||
    $Attempts = 0
 | 
			
		||||
    $local:startTime = $(get-date)
 | 
			
		||||
 | 
			
		||||
    while ($true) {
 | 
			
		||||
        try {
 | 
			
		||||
@ -182,7 +226,11 @@ function Invoke-With-Retry([ScriptBlock]$ScriptBlock, [System.Threading.Cancella
 | 
			
		||||
                Start-Sleep $SecondsBetweenAttempts
 | 
			
		||||
            }
 | 
			
		||||
            else {
 | 
			
		||||
                throw
 | 
			
		||||
                $local:elapsedTime = $(get-date) - $local:startTime
 | 
			
		||||
                if (($local:elapsedTime.TotalSeconds - $DownloadTimeout) -gt 0 -and -not $cancellationToken.IsCancellationRequested) {
 | 
			
		||||
                    throw New-Object System.TimeoutException("Failed to reach the server: connection timeout: default timeout is $DownloadTimeout second(s)");
 | 
			
		||||
                }
 | 
			
		||||
                throw;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
@ -199,6 +247,18 @@ function Get-Machine-Architecture() {
 | 
			
		||||
        return $ENV:PROCESSOR_ARCHITEW6432
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    try {        
 | 
			
		||||
        if ( ((Get-CimInstance -ClassName CIM_OperatingSystem).OSArchitecture) -like "ARM*") {
 | 
			
		||||
            if ( [Environment]::Is64BitOperatingSystem ) {
 | 
			
		||||
                return "arm64"
 | 
			
		||||
            }  
 | 
			
		||||
            return "arm"
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    catch {
 | 
			
		||||
        # Machine doesn't support Get-CimInstance
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return $ENV:PROCESSOR_ARCHITECTURE
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -218,13 +278,13 @@ function Get-CLIArchitecture-From-Architecture([string]$Architecture) {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function ValidateFeedCredential([string] $FeedCredential)
 | 
			
		||||
{
 | 
			
		||||
function ValidateFeedCredential([string] $FeedCredential) {
 | 
			
		||||
    if ($Internal -and [string]::IsNullOrWhitespace($FeedCredential)) {
 | 
			
		||||
        $message = "Provide credentials via -FeedCredential parameter."
 | 
			
		||||
        if ($DryRun) {
 | 
			
		||||
            Say-Warning "$message"
 | 
			
		||||
        } else {
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
            throw "$message"
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
@ -259,13 +319,18 @@ function Get-NormalizedChannel([string]$Channel) {
 | 
			
		||||
        return ""
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if ($Channel.Contains("Current")) {
 | 
			
		||||
        Say-Warning 'Value "Current" is deprecated for -Channel option. Use "STS" instead.'
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if ($Channel.StartsWith('release/')) {
 | 
			
		||||
        Say-Warning 'Using branch name with -Channel option is no longer supported with newer releases. Use -Quality option with a channel in X.Y format instead, such as "-Channel 5.0 -Quality Daily."'
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    switch ($Channel) {
 | 
			
		||||
        { $_ -eq "lts" } { return "LTS" }
 | 
			
		||||
        { $_ -eq "current" } { return "current" }
 | 
			
		||||
        { $_ -eq "sts" } { return "STS" }
 | 
			
		||||
        { $_ -eq "current" } { return "STS" }
 | 
			
		||||
        default { return $Channel.ToLowerInvariant() }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -311,8 +376,7 @@ function Load-Assembly([string] $Assembly) {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function GetHTTPResponse([Uri] $Uri, [bool]$HeaderOnly, [bool]$DisableRedirect, [bool]$DisableFeedCredential)
 | 
			
		||||
{
 | 
			
		||||
function GetHTTPResponse([Uri] $Uri, [bool]$HeaderOnly, [bool]$DisableRedirect, [bool]$DisableFeedCredential) {
 | 
			
		||||
    $cts = New-Object System.Threading.CancellationTokenSource
 | 
			
		||||
 | 
			
		||||
    $downloadScript = {
 | 
			
		||||
@ -330,12 +394,14 @@ function GetHTTPResponse([Uri] $Uri, [bool]$HeaderOnly, [bool]$DisableRedirect,
 | 
			
		||||
                    if ($DefaultProxy -and (-not $DefaultProxy.IsBypassed($Uri))) {
 | 
			
		||||
                        if ($null -ne $DefaultProxy.GetProxy($Uri)) {
 | 
			
		||||
                            $ProxyAddress = $DefaultProxy.GetProxy($Uri).OriginalString
 | 
			
		||||
                        } else {
 | 
			
		||||
                        }
 | 
			
		||||
                        else {
 | 
			
		||||
                            $ProxyAddress = $null
 | 
			
		||||
                        }
 | 
			
		||||
                        $ProxyUseDefaultCredentials = $true
 | 
			
		||||
                    }
 | 
			
		||||
                } catch {
 | 
			
		||||
                }
 | 
			
		||||
                catch {
 | 
			
		||||
                    # Eat the exception and move forward as the above code is an attempt
 | 
			
		||||
                    #    at resolving the DefaultProxy that may not have been a problem.
 | 
			
		||||
                    $ProxyAddress = $null
 | 
			
		||||
@ -351,8 +417,7 @@ function GetHTTPResponse([Uri] $Uri, [bool]$HeaderOnly, [bool]$DisableRedirect,
 | 
			
		||||
                    BypassList            = $ProxyBypassList;
 | 
			
		||||
                }
 | 
			
		||||
            }       
 | 
			
		||||
            if ($DisableRedirect)
 | 
			
		||||
            {
 | 
			
		||||
            if ($DisableRedirect) {
 | 
			
		||||
                $HttpClientHandler.AllowAutoRedirect = $false
 | 
			
		||||
            }
 | 
			
		||||
            $HttpClient = New-Object System.Net.Http.HttpClient -ArgumentList $HttpClientHandler
 | 
			
		||||
@ -386,8 +451,7 @@ function GetHTTPResponse([Uri] $Uri, [bool]$HeaderOnly, [bool]$DisableRedirect,
 | 
			
		||||
                    $DownloadException.Data["StatusCode"] = [int] $Response.StatusCode
 | 
			
		||||
                    $DownloadException.Data["ErrorMessage"] = "Unable to download $Uri. Returned HTTP status code: " + $DownloadException.Data["StatusCode"]
 | 
			
		||||
 | 
			
		||||
                    if (404 -eq [int] $Response.StatusCode)
 | 
			
		||||
                    {
 | 
			
		||||
                    if (404 -eq [int] $Response.StatusCode) {
 | 
			
		||||
                        $cts.Cancel()
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
@ -426,10 +490,8 @@ function GetHTTPResponse([Uri] $Uri, [bool]$HeaderOnly, [bool]$DisableRedirect,
 | 
			
		||||
    try {
 | 
			
		||||
        return Invoke-With-Retry $downloadScript $cts.Token
 | 
			
		||||
    }
 | 
			
		||||
    finally
 | 
			
		||||
    {
 | 
			
		||||
        if ($null -ne $cts)
 | 
			
		||||
        {
 | 
			
		||||
    finally {
 | 
			
		||||
        if ($null -ne $cts) {
 | 
			
		||||
            $cts.Dispose()
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
@ -547,11 +609,9 @@ function Get-Download-Link([string]$AzureFeed, [string]$SpecificVersion, [string
 | 
			
		||||
    elseif ($Runtime -eq "windowsdesktop") {
 | 
			
		||||
        # The windows desktop runtime is part of the core runtime layout prior to 5.0
 | 
			
		||||
        $PayloadURL = "$AzureFeed/Runtime/$SpecificVersion/windowsdesktop-runtime-$SpecificProductVersion-win-$CLIArchitecture.zip"
 | 
			
		||||
        if ($SpecificVersion -match '^(\d+)\.(.*)$')
 | 
			
		||||
        {
 | 
			
		||||
        if ($SpecificVersion -match '^(\d+)\.(.*)$') {
 | 
			
		||||
            $majorVersion = [int]$Matches[1]
 | 
			
		||||
            if ($majorVersion -ge 5)
 | 
			
		||||
            {
 | 
			
		||||
            if ($majorVersion -ge 5) {
 | 
			
		||||
                $PayloadURL = "$AzureFeed/WindowsDesktop/$SpecificVersion/windowsdesktop-runtime-$SpecificProductVersion-win-$CLIArchitecture.zip"
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
@ -601,8 +661,7 @@ function Get-Product-Version([string]$AzureFeed, [string]$SpecificVersion, [stri
 | 
			
		||||
 | 
			
		||||
            if ($productVersionResponse.StatusCode -eq 200) {
 | 
			
		||||
                $productVersion = $productVersionResponse.Content.ReadAsStringAsync().Result.Trim()
 | 
			
		||||
                if ($productVersion -ne $SpecificVersion)
 | 
			
		||||
                {
 | 
			
		||||
                if ($productVersion -ne $SpecificVersion) {
 | 
			
		||||
                    Say "Using alternate version $productVersion found in $ProductVersionTxtURL"
 | 
			
		||||
                }
 | 
			
		||||
                return $productVersion
 | 
			
		||||
@ -617,8 +676,7 @@ function Get-Product-Version([string]$AzureFeed, [string]$SpecificVersion, [stri
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    # Getting the version number with productVersion.txt has failed. Try parsing the download link for a version number.
 | 
			
		||||
    if ([string]::IsNullOrEmpty($PackageDownloadLink))
 | 
			
		||||
    {
 | 
			
		||||
    if ([string]::IsNullOrEmpty($PackageDownloadLink)) {
 | 
			
		||||
        Say-Verbose "Using the default value '$SpecificVersion' as the product version."
 | 
			
		||||
        return $SpecificVersion
 | 
			
		||||
    }
 | 
			
		||||
@ -678,16 +736,14 @@ function Get-Product-Version-Url([string]$AzureFeed, [string]$SpecificVersion, [
 | 
			
		||||
    return $ProductVersionTxtURL
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function Get-ProductVersionFromDownloadLink([string]$PackageDownloadLink, [string]$SpecificVersion)
 | 
			
		||||
{
 | 
			
		||||
function Get-ProductVersionFromDownloadLink([string]$PackageDownloadLink, [string]$SpecificVersion) {
 | 
			
		||||
    Say-Invocation $MyInvocation
 | 
			
		||||
 | 
			
		||||
    #product specific version follows the product name
 | 
			
		||||
    #for filename 'dotnet-sdk-3.1.404-win-x64.zip': the product version is 3.1.400
 | 
			
		||||
    $filename = $PackageDownloadLink.Substring($PackageDownloadLink.LastIndexOf("/") + 1)
 | 
			
		||||
    $filenameParts = $filename.Split('-')
 | 
			
		||||
    if ($filenameParts.Length -gt 2)
 | 
			
		||||
    {
 | 
			
		||||
    if ($filenameParts.Length -gt 2) {
 | 
			
		||||
        $productVersion = $filenameParts[2]
 | 
			
		||||
        Say-Verbose "Extracted product version '$productVersion' from download link '$PackageDownloadLink'."
 | 
			
		||||
    }
 | 
			
		||||
@ -705,6 +761,9 @@ function Get-User-Share-Path() {
 | 
			
		||||
    if (!$InstallRoot) {
 | 
			
		||||
        $InstallRoot = "$env:LocalAppData\Microsoft\dotnet"
 | 
			
		||||
    }
 | 
			
		||||
    elseif ($InstallRoot -like "$env:ProgramFiles\dotnet\?*") {
 | 
			
		||||
        Say-Warning "The install root specified by the environment variable DOTNET_INSTALL_DIR points to the sub folder of $env:ProgramFiles\dotnet which is the default dotnet install root using .NET SDK installer. It is better to keep aligned with .NET SDK installer."
 | 
			
		||||
    }
 | 
			
		||||
    return $InstallRoot
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -717,6 +776,19 @@ function Resolve-Installation-Path([string]$InstallDir) {
 | 
			
		||||
    return $InstallDir
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function Test-User-Write-Access([string]$InstallDir) {
 | 
			
		||||
    try {
 | 
			
		||||
        $tempFileName = [guid]::NewGuid().ToString()
 | 
			
		||||
        $tempFilePath = Join-Path -Path $InstallDir -ChildPath $tempFileName
 | 
			
		||||
        New-Item -Path $tempFilePath -ItemType File -Force
 | 
			
		||||
        Remove-Item $tempFilePath -Force
 | 
			
		||||
        return $true
 | 
			
		||||
    }
 | 
			
		||||
    catch {
 | 
			
		||||
        return $false
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function Is-Dotnet-Package-Installed([string]$InstallRoot, [string]$RelativePathToPackage, [string]$SpecificVersion) {
 | 
			
		||||
    Say-Invocation $MyInvocation
 | 
			
		||||
 | 
			
		||||
@ -800,6 +872,10 @@ function Extract-Dotnet-Package([string]$ZipPath, [string]$OutPath) {
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    catch {
 | 
			
		||||
        Say-Error "Failed to extract package. Exception: $_"
 | 
			
		||||
        throw;
 | 
			
		||||
    }
 | 
			
		||||
    finally {
 | 
			
		||||
        if ($null -ne $Zip) {
 | 
			
		||||
            $Zip.Dispose()
 | 
			
		||||
@ -828,6 +904,8 @@ function DownloadFile($Source, [string]$OutPath) {
 | 
			
		||||
        $File = [System.IO.File]::Create($OutPath)
 | 
			
		||||
        $Stream.CopyTo($File)
 | 
			
		||||
        $File.Close()
 | 
			
		||||
 | 
			
		||||
        ValidateRemoteLocalFileSizes -LocalFileOutPath $OutPath -SourceUri $Source
 | 
			
		||||
    }
 | 
			
		||||
    finally {
 | 
			
		||||
        if ($null -ne $Stream) {
 | 
			
		||||
@ -836,19 +914,40 @@ function DownloadFile($Source, [string]$OutPath) {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function ValidateRemoteLocalFileSizes([string]$LocalFileOutPath, $SourceUri) {
 | 
			
		||||
    try {
 | 
			
		||||
        $remoteFileSize = Get-Remote-File-Size -zipUri $SourceUri
 | 
			
		||||
        $fileSize = [long](Get-Item $LocalFileOutPath).Length
 | 
			
		||||
        Say "Downloaded file $SourceUri size is $fileSize bytes."
 | 
			
		||||
    
 | 
			
		||||
        if ((![string]::IsNullOrEmpty($remoteFileSize)) -and !([string]::IsNullOrEmpty($fileSize)) ) {
 | 
			
		||||
            if ($remoteFileSize -ne $fileSize) {
 | 
			
		||||
                Say "The remote and local file sizes are not equal. Remote file size is $remoteFileSize bytes and local size is $fileSize bytes. The local package may be corrupted."
 | 
			
		||||
            }
 | 
			
		||||
            else {
 | 
			
		||||
                Say "The remote and local file sizes are equal."
 | 
			
		||||
            }   
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
            Say "Either downloaded or local package size can not be measured. One of them may be corrupted."
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    catch {
 | 
			
		||||
        Say "Either downloaded or local package size can not be measured. One of them may be corrupted."
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function SafeRemoveFile($Path) {
 | 
			
		||||
    try {
 | 
			
		||||
        if (Test-Path $Path) {
 | 
			
		||||
            Remove-Item $Path
 | 
			
		||||
            Say-Verbose "The temporary file `"$Path`" was removed."
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
        else {
 | 
			
		||||
            Say-Verbose "The temporary file `"$Path`" does not exist, therefore is not removed."
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    catch
 | 
			
		||||
    {
 | 
			
		||||
    catch {
 | 
			
		||||
        Say-Warning "Failed to remove the temporary file: `"$Path`", remove it manually."
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -860,7 +959,8 @@ function Prepend-Sdk-InstallRoot-To-Path([string]$InstallRoot) {
 | 
			
		||||
        if (-Not $env:path.Contains($SuffixedBinPath)) {
 | 
			
		||||
            Say "Adding to current process PATH: `"$BinPath`". Note: This change will not be visible if PowerShell was run as a child process."
 | 
			
		||||
            $env:path = $SuffixedBinPath + $env:path
 | 
			
		||||
        } else {
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
            Say-Verbose "Current process PATH already contains `"$BinPath`""
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
@ -869,8 +969,7 @@ function Prepend-Sdk-InstallRoot-To-Path([string]$InstallRoot) {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function PrintDryRunOutput($Invocation, $DownloadLinks)
 | 
			
		||||
{
 | 
			
		||||
function PrintDryRunOutput($Invocation, $DownloadLinks) {
 | 
			
		||||
    Say "Payload URLs:"
 | 
			
		||||
    
 | 
			
		||||
    for ($linkIndex = 0; $linkIndex -lt $DownloadLinks.count; $linkIndex++) {
 | 
			
		||||
@ -893,19 +992,44 @@ function PrintDryRunOutput($Invocation, $DownloadLinks)
 | 
			
		||||
        $RepeatableCommand += " -FeedCredential `"<feedCredential>`""
 | 
			
		||||
    }
 | 
			
		||||
    Say "Repeatable invocation: $RepeatableCommand"
 | 
			
		||||
    if ($SpecificVersion -ne $EffectiveVersion)
 | 
			
		||||
    {
 | 
			
		||||
    if ($SpecificVersion -ne $EffectiveVersion) {
 | 
			
		||||
        Say "NOTE: Due to finding a version manifest with this runtime, it would actually install with version '$EffectiveVersion'"
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# grab the 'stem' of the redirect and check it against all of our configured feeds, 
 | 
			
		||||
# if it matches, we can be sure that the redirect is valid and we should use it for
 | 
			
		||||
# subsequent processing
 | 
			
		||||
function Sanitize-RedirectUrl([string]$url) {
 | 
			
		||||
    $urlSegments = ([System.Uri]$url).Segments;
 | 
			
		||||
    $urlStem = $urlSegments[2..($urlSegments.Length - 1)] -join "";
 | 
			
		||||
    Write-Verbose "Checking configured feeds for the asset at $urlStem"
 | 
			
		||||
    foreach ($prospectiveFeed in $feeds) {
 | 
			
		||||
        $trialUrl = "$prospectiveFeed/$urlStem";
 | 
			
		||||
        Write-Verbose "Checking $trialUrl"
 | 
			
		||||
        try {
 | 
			
		||||
            $trialResponse = Invoke-WebRequest -Uri $trialUrl -Method HEAD
 | 
			
		||||
            if ($trialResponse.StatusCode -eq 200) {
 | 
			
		||||
                Write-Verbose "Found a match at $trialUrl"
 | 
			
		||||
                return $trialUrl;
 | 
			
		||||
            }
 | 
			
		||||
            else {
 | 
			
		||||
                Write-Verbose "No match at $trialUrl"
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        catch {
 | 
			
		||||
            Write-Verbose "Failed to check $trialUrl"
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function Get-AkaMSDownloadLink([string]$Channel, [string]$Quality, [bool]$Internal, [string]$Product, [string]$Architecture) {
 | 
			
		||||
    Say-Invocation $MyInvocation 
 | 
			
		||||
 | 
			
		||||
    #quality is not supported for LTS or current channel
 | 
			
		||||
    if (![string]::IsNullOrEmpty($Quality) -and (@("LTS", "current") -contains $Channel)) {
 | 
			
		||||
    #quality is not supported for LTS or STS channel
 | 
			
		||||
    if (![string]::IsNullOrEmpty($Quality) -and (@("LTS", "STS") -contains $Channel)) {
 | 
			
		||||
        $Quality = ""
 | 
			
		||||
        Say-Warning "Specifying quality for current or LTS channel is not supported, the quality will be ignored."
 | 
			
		||||
        Say-Warning "Specifying quality for STS or LTS channel is not supported, the quality will be ignored."
 | 
			
		||||
    }
 | 
			
		||||
    Say-Verbose "Retrieving primary payload URL from aka.ms link for channel: '$Channel', quality: '$Quality' product: '$Product', os: 'win', architecture: '$Architecture'." 
 | 
			
		||||
   
 | 
			
		||||
@ -922,8 +1046,7 @@ function Get-AkaMSDownloadLink([string]$Channel, [string]$Quality, [bool]$Intern
 | 
			
		||||
    Say-Verbose  "Constructed aka.ms link: '$akaMsLink'."
 | 
			
		||||
    $akaMsDownloadLink = $null
 | 
			
		||||
 | 
			
		||||
    for ($maxRedirections = 9; $maxRedirections -ge 0; $maxRedirections--)
 | 
			
		||||
    {
 | 
			
		||||
    for ($maxRedirections = 9; $maxRedirections -ge 0; $maxRedirections--) {
 | 
			
		||||
        #get HTTP response
 | 
			
		||||
        #do not pass credentials as a part of the $akaMsLink and do not apply credentials in the GetHTTPResponse function
 | 
			
		||||
        #otherwise the redirect link would have credentials as well
 | 
			
		||||
@ -937,8 +1060,7 @@ function Get-AkaMSDownloadLink([string]$Channel, [string]$Quality, [bool]$Intern
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        #if HTTP code is 301 (Moved Permanently), the redirect link exists
 | 
			
		||||
        if  ($Response.StatusCode -eq 301)
 | 
			
		||||
        {
 | 
			
		||||
        if ($Response.StatusCode -eq 301) {
 | 
			
		||||
            try {
 | 
			
		||||
                $akaMsDownloadLink = $Response.Headers.GetValues("Location")[0]
 | 
			
		||||
 | 
			
		||||
@ -957,9 +1079,13 @@ function Get-AkaMSDownloadLink([string]$Channel, [string]$Quality, [bool]$Intern
 | 
			
		||||
                return $null
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        elseif ((($Response.StatusCode -lt 300) -or ($Response.StatusCode -ge 400)) -and (-not [string]::IsNullOrEmpty($akaMsDownloadLink)))
 | 
			
		||||
        {
 | 
			
		||||
        elseif ((($Response.StatusCode -lt 300) -or ($Response.StatusCode -ge 400)) -and (-not [string]::IsNullOrEmpty($akaMsDownloadLink))) {
 | 
			
		||||
            # Redirections have ended.
 | 
			
		||||
            $actualRedirectUrl = Sanitize-RedirectUrl $akaMsDownloadLink
 | 
			
		||||
            if ($null -ne $actualRedirectUrl) {
 | 
			
		||||
                $akaMsDownloadLink = $actualRedirectUrl
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return $akaMsDownloadLink
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@ -1008,10 +1134,11 @@ function Get-AkaMsLink-And-Version([string] $NormalizedChannel, [string] $Normal
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function Get-Feeds-To-Use()
 | 
			
		||||
{
 | 
			
		||||
function Get-Feeds-To-Use() {
 | 
			
		||||
    $feeds = @(
 | 
			
		||||
    "https://dotnetcli.azureedge.net/dotnet",
 | 
			
		||||
        "https://builds.dotnet.microsoft.com/dotnet"
 | 
			
		||||
        "https://dotnetcli.azureedge.net/dotnet"
 | 
			
		||||
        "https://ci.dot.net/public"
 | 
			
		||||
        "https://dotnetbuilds.azureedge.net/public"
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
@ -1030,6 +1157,8 @@ function Get-Feeds-To-Use()
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    Write-Verbose "Initialized feeds: $feeds"
 | 
			
		||||
 | 
			
		||||
    return $feeds
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1059,6 +1188,13 @@ function Resolve-AssetName-And-RelativePath([string] $Runtime) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function Prepare-Install-Directory {
 | 
			
		||||
    $diskSpaceWarning = "Failed to check the disk space. Installation will continue, but it may fail if you do not have enough disk space.";
 | 
			
		||||
 | 
			
		||||
    if ($PSVersionTable.PSVersion.Major -lt 7) {
 | 
			
		||||
        Say-Verbose $diskSpaceWarning
 | 
			
		||||
        return
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    New-Item -ItemType Directory -Force -Path $InstallRoot | Out-Null
 | 
			
		||||
 | 
			
		||||
    $installDrive = $((Get-Item $InstallRoot -Force).PSDrive.Name);
 | 
			
		||||
@ -1067,18 +1203,24 @@ function Prepare-Install-Directory {
 | 
			
		||||
        $diskInfo = Get-PSDrive -Name $installDrive
 | 
			
		||||
    }
 | 
			
		||||
    catch {
 | 
			
		||||
        Say-Warning "Failed to check the disk space. Installation will continue, but it may fail if you do not have enough disk space."
 | 
			
		||||
        Say-Warning $diskSpaceWarning
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    # The check is relevant for PS version >= 7, the result can be irrelevant for older versions. See https://github.com/PowerShell/PowerShell/issues/12442.
 | 
			
		||||
    if ( ($null -ne $diskInfo) -and ($diskInfo.Free / 1MB -le 100)) {
 | 
			
		||||
        throw "There is not enough disk space on drive ${installDrive}:"
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Say "Note that the intended use of this script is for Continuous Integration (CI) scenarios, where:"
 | 
			
		||||
Say "- The SDK needs to be installed without user interaction and without admin rights."
 | 
			
		||||
Say "- The SDK installation doesn't need to persist across multiple CI runs."
 | 
			
		||||
Say "To set up a development environment or to run apps, use installers rather than this script. Visit https://dotnet.microsoft.com/download to get the installer.`r`n"
 | 
			
		||||
if ($Help) {
 | 
			
		||||
    Get-Help $PSCommandPath -Examples
 | 
			
		||||
    exit
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Say-Verbose "Note that the intended use of this script is for Continuous Integration (CI) scenarios, where:"
 | 
			
		||||
Say-Verbose "- The SDK needs to be installed without user interaction and without admin rights."
 | 
			
		||||
Say-Verbose "- The SDK installation doesn't need to persist across multiple CI runs."
 | 
			
		||||
Say-Verbose "To set up a development environment or to run apps, use installers rather than this script. Visit https://dotnet.microsoft.com/download to get the installer.`r`n"
 | 
			
		||||
 | 
			
		||||
if ($SharedRuntime -and (-not $Runtime)) {
 | 
			
		||||
    $Runtime = "dotnet"
 | 
			
		||||
@ -1086,16 +1228,22 @@ if ($SharedRuntime -and (-not $Runtime)) {
 | 
			
		||||
 | 
			
		||||
$OverrideNonVersionedFiles = !$SkipNonVersionedFiles
 | 
			
		||||
 | 
			
		||||
$CLIArchitecture = Get-CLIArchitecture-From-Architecture $Architecture
 | 
			
		||||
$NormalizedQuality = Get-NormalizedQuality $Quality
 | 
			
		||||
Measure-Action "Product discovery" {
 | 
			
		||||
    $script:CLIArchitecture = Get-CLIArchitecture-From-Architecture $Architecture
 | 
			
		||||
    $script:NormalizedQuality = Get-NormalizedQuality $Quality
 | 
			
		||||
    Say-Verbose "Normalized quality: '$NormalizedQuality'"
 | 
			
		||||
$NormalizedChannel = Get-NormalizedChannel $Channel
 | 
			
		||||
    $script:NormalizedChannel = Get-NormalizedChannel $Channel
 | 
			
		||||
    Say-Verbose "Normalized channel: '$NormalizedChannel'"
 | 
			
		||||
$NormalizedProduct = Get-NormalizedProduct $Runtime
 | 
			
		||||
    $script:NormalizedProduct = Get-NormalizedProduct $Runtime
 | 
			
		||||
    Say-Verbose "Normalized product: '$NormalizedProduct'"
 | 
			
		||||
$FeedCredential = ValidateFeedCredential $FeedCredential
 | 
			
		||||
    $script:FeedCredential = ValidateFeedCredential $FeedCredential
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
$InstallRoot = Resolve-Installation-Path $InstallDir
 | 
			
		||||
if (-not (Test-User-Write-Access $InstallRoot)) {
 | 
			
		||||
    Say-Error "The current user doesn't have write access to the installation root '$InstallRoot' to install .NET. Please try specifying a different installation directory using the -InstallDir parameter, or ensure the selected directory has the appropriate permissions."
 | 
			
		||||
    throw
 | 
			
		||||
}
 | 
			
		||||
Say-Verbose "InstallRoot: $InstallRoot"
 | 
			
		||||
$ScriptName = $MyInvocation.MyCommand.Name
 | 
			
		||||
($assetName, $dotnetPackageRelativePath) = Resolve-AssetName-And-RelativePath -Runtime $Runtime
 | 
			
		||||
@ -1103,6 +1251,10 @@ $ScriptName = $MyInvocation.MyCommand.Name
 | 
			
		||||
$feeds = Get-Feeds-To-Use
 | 
			
		||||
$DownloadLinks = @()
 | 
			
		||||
 | 
			
		||||
if ($Version.ToLowerInvariant() -ne "latest" -and -not [string]::IsNullOrEmpty($Quality)) {
 | 
			
		||||
    throw "Quality and Version options are not allowed to be specified simultaneously. See https:// learn.microsoft.com/dotnet/core/tools/dotnet-install-script#options for details."
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# aka.ms links can only be used if the user did not request a specific version via the command line or a global.json file.
 | 
			
		||||
if ([string]::IsNullOrEmpty($JSonFile) -and ($Version -eq "latest")) {
 | 
			
		||||
    ($DownloadLink, $SpecificVersion, $EffectiveVersion) = Get-AkaMsLink-And-Version $NormalizedChannel $NormalizedQuality $Internal $NormalizedProduct $CLIArchitecture
 | 
			
		||||
@ -1113,8 +1265,7 @@ if ([string]::IsNullOrEmpty($JSonFile) -and ($Version -eq "latest")) {
 | 
			
		||||
        
 | 
			
		||||
        if (-Not $DryRun) {
 | 
			
		||||
            Say-Verbose "Checking if the version $EffectiveVersion is already installed"
 | 
			
		||||
            if (Is-Dotnet-Package-Installed -InstallRoot $InstallRoot -RelativePathToPackage $dotnetPackageRelativePath -SpecificVersion $EffectiveVersion)
 | 
			
		||||
            {
 | 
			
		||||
            if (Is-Dotnet-Package-Installed -InstallRoot $InstallRoot -RelativePathToPackage $dotnetPackageRelativePath -SpecificVersion $EffectiveVersion) {
 | 
			
		||||
                Say "$assetName with version '$EffectiveVersion' is already installed."
 | 
			
		||||
                Prepend-Sdk-InstallRoot-To-Path -InstallRoot $InstallRoot
 | 
			
		||||
                return
 | 
			
		||||
@ -1125,8 +1276,7 @@ if ([string]::IsNullOrEmpty($JSonFile) -and ($Version -eq "latest")) {
 | 
			
		||||
 | 
			
		||||
# Primary and legacy links cannot be used if a quality was specified.
 | 
			
		||||
# If we already have an aka.ms link, no need to search the blob feeds.
 | 
			
		||||
if ([string]::IsNullOrEmpty($NormalizedQuality) -and 0 -eq $DownloadLinks.count)
 | 
			
		||||
{
 | 
			
		||||
if ([string]::IsNullOrEmpty($NormalizedQuality) -and 0 -eq $DownloadLinks.count) {
 | 
			
		||||
    foreach ($feed in $feeds) {
 | 
			
		||||
        try {
 | 
			
		||||
            $SpecificVersion = Get-Specific-Version-From-Version -AzureFeed $feed -Channel $Channel -Version $Version -JSonFile $JSonFile
 | 
			
		||||
@ -1143,16 +1293,14 @@ if ([string]::IsNullOrEmpty($NormalizedQuality) -and 0 -eq $DownloadLinks.count)
 | 
			
		||||
    
 | 
			
		||||
            if (-Not $DryRun) {
 | 
			
		||||
                Say-Verbose "Checking if the version $EffectiveVersion is already installed"
 | 
			
		||||
                if (Is-Dotnet-Package-Installed -InstallRoot $InstallRoot -RelativePathToPackage $dotnetPackageRelativePath -SpecificVersion $EffectiveVersion)
 | 
			
		||||
                {
 | 
			
		||||
                if (Is-Dotnet-Package-Installed -InstallRoot $InstallRoot -RelativePathToPackage $dotnetPackageRelativePath -SpecificVersion $EffectiveVersion) {
 | 
			
		||||
                    Say "$assetName with version '$EffectiveVersion' is already installed."
 | 
			
		||||
                    Prepend-Sdk-InstallRoot-To-Path -InstallRoot $InstallRoot
 | 
			
		||||
                    return
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        catch
 | 
			
		||||
        {
 | 
			
		||||
        catch {
 | 
			
		||||
            Say-Verbose "Failed to acquire download links from feed $feed. Exception: $_"
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
@ -1167,21 +1315,19 @@ if ($DryRun) {
 | 
			
		||||
    return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Prepare-Install-Directory
 | 
			
		||||
Measure-Action "Installation directory preparation" { Prepare-Install-Directory }
 | 
			
		||||
 | 
			
		||||
$ZipPath = [System.IO.Path]::combine([System.IO.Path]::GetTempPath(), [System.IO.Path]::GetRandomFileName())
 | 
			
		||||
Say-Verbose "Zip path: $ZipPath"
 | 
			
		||||
 | 
			
		||||
$DownloadSucceeded = $false
 | 
			
		||||
$DownloadedLink = $null
 | 
			
		||||
$ErrorMessages = @()
 | 
			
		||||
 | 
			
		||||
foreach ($link in $DownloadLinks)
 | 
			
		||||
{
 | 
			
		||||
foreach ($link in $DownloadLinks) {
 | 
			
		||||
    Say-Verbose "Downloading `"$($link.type)`" link $($link.downloadLink)"
 | 
			
		||||
 | 
			
		||||
    try {
 | 
			
		||||
        DownloadFile -Source $link.downloadLink -OutPath $ZipPath
 | 
			
		||||
        Measure-Action "Package download" { DownloadFile -Source $link.downloadLink -OutPath $ZipPath }
 | 
			
		||||
        Say-Verbose "Download succeeded."
 | 
			
		||||
        $DownloadSucceeded = $true
 | 
			
		||||
        $DownloadedLink = $link
 | 
			
		||||
@ -1197,7 +1343,8 @@ foreach ($link in $DownloadLinks)
 | 
			
		||||
    
 | 
			
		||||
        if ($PSItem.Exception.Data.Contains("ErrorMessage")) {
 | 
			
		||||
            $ErrorMessage = $PSItem.Exception.Data["ErrorMessage"]
 | 
			
		||||
        } else {
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
            $ErrorMessage = $PSItem.Exception.Message
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@ -1218,7 +1365,7 @@ if (-not $DownloadSucceeded) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Say "Extracting the archive."
 | 
			
		||||
Extract-Dotnet-Package -ZipPath $ZipPath -OutPath $InstallRoot
 | 
			
		||||
Measure-Action "Package extraction" { Extract-Dotnet-Package -ZipPath $ZipPath -OutPath $InstallRoot }
 | 
			
		||||
 | 
			
		||||
#  Check if the SDK version is installed; if not, fail the installation.
 | 
			
		||||
$isAssetInstalled = $false
 | 
			
		||||
@ -1242,225 +1389,13 @@ if (!$isAssetInstalled) {
 | 
			
		||||
    throw "`"$assetName`" with version = $($DownloadedLink.effectiveVersion) failed to install with an unknown error."
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
if (-not $KeepZip) {
 | 
			
		||||
    SafeRemoveFile -Path $ZipPath
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Prepend-Sdk-InstallRoot-To-Path -InstallRoot $InstallRoot
 | 
			
		||||
Measure-Action "Setting up shell environment" { Prepend-Sdk-InstallRoot-To-Path -InstallRoot $InstallRoot }
 | 
			
		||||
 | 
			
		||||
Say "Note that the script does not resolve dependencies during installation."
 | 
			
		||||
Say "To check the list of dependencies, go to https://docs.microsoft.com/dotnet/core/install/windows#dependencies"
 | 
			
		||||
Say "Note that the script does not ensure your Windows version is supported during the installation."
 | 
			
		||||
Say "To check the list of supported versions, go to https://learn.microsoft.com/dotnet/core/install/windows#supported-versions"
 | 
			
		||||
Say "Installed version is $($DownloadedLink.effectiveVersion)"
 | 
			
		||||
Say "Installation finished"
 | 
			
		||||
 | 
			
		||||
# SIG # Begin signature block
 | 
			
		||||
# MIInoQYJKoZIhvcNAQcCoIInkjCCJ44CAQExDzANBglghkgBZQMEAgEFADB5Bgor
 | 
			
		||||
# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
 | 
			
		||||
# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCAuo3sRWvfrJ+Bd
 | 
			
		||||
# sIQ2zLeO20Ij33Vb5ljtEhxAYYSEc6CCDYEwggX/MIID56ADAgECAhMzAAACUosz
 | 
			
		||||
# qviV8znbAAAAAAJSMA0GCSqGSIb3DQEBCwUAMH4xCzAJBgNVBAYTAlVTMRMwEQYD
 | 
			
		||||
# VQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNy
 | 
			
		||||
# b3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01pY3Jvc29mdCBDb2RlIFNpZ25p
 | 
			
		||||
# bmcgUENBIDIwMTEwHhcNMjEwOTAyMTgzMjU5WhcNMjIwOTAxMTgzMjU5WjB0MQsw
 | 
			
		||||
# CQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9u
 | 
			
		||||
# ZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMR4wHAYDVQQDExVNaWNy
 | 
			
		||||
# b3NvZnQgQ29ycG9yYXRpb24wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB
 | 
			
		||||
# AQDQ5M+Ps/X7BNuv5B/0I6uoDwj0NJOo1KrVQqO7ggRXccklyTrWL4xMShjIou2I
 | 
			
		||||
# sbYnF67wXzVAq5Om4oe+LfzSDOzjcb6ms00gBo0OQaqwQ1BijyJ7NvDf80I1fW9O
 | 
			
		||||
# L76Kt0Wpc2zrGhzcHdb7upPrvxvSNNUvxK3sgw7YTt31410vpEp8yfBEl/hd8ZzA
 | 
			
		||||
# v47DCgJ5j1zm295s1RVZHNp6MoiQFVOECm4AwK2l28i+YER1JO4IplTH44uvzX9o
 | 
			
		||||
# RnJHaMvWzZEpozPy4jNO2DDqbcNs4zh7AWMhE1PWFVA+CHI/En5nASvCvLmuR/t8
 | 
			
		||||
# q4bc8XR8QIZJQSp+2U6m2ldNAgMBAAGjggF+MIIBejAfBgNVHSUEGDAWBgorBgEE
 | 
			
		||||
# AYI3TAgBBggrBgEFBQcDAzAdBgNVHQ4EFgQUNZJaEUGL2Guwt7ZOAu4efEYXedEw
 | 
			
		||||
# UAYDVR0RBEkwR6RFMEMxKTAnBgNVBAsTIE1pY3Jvc29mdCBPcGVyYXRpb25zIFB1
 | 
			
		||||
# ZXJ0byBSaWNvMRYwFAYDVQQFEw0yMzAwMTIrNDY3NTk3MB8GA1UdIwQYMBaAFEhu
 | 
			
		||||
# ZOVQBdOCqhc3NyK1bajKdQKVMFQGA1UdHwRNMEswSaBHoEWGQ2h0dHA6Ly93d3cu
 | 
			
		||||
# bWljcm9zb2Z0LmNvbS9wa2lvcHMvY3JsL01pY0NvZFNpZ1BDQTIwMTFfMjAxMS0w
 | 
			
		||||
# Ny0wOC5jcmwwYQYIKwYBBQUHAQEEVTBTMFEGCCsGAQUFBzAChkVodHRwOi8vd3d3
 | 
			
		||||
# Lm1pY3Jvc29mdC5jb20vcGtpb3BzL2NlcnRzL01pY0NvZFNpZ1BDQTIwMTFfMjAx
 | 
			
		||||
# MS0wNy0wOC5jcnQwDAYDVR0TAQH/BAIwADANBgkqhkiG9w0BAQsFAAOCAgEAFkk3
 | 
			
		||||
# uSxkTEBh1NtAl7BivIEsAWdgX1qZ+EdZMYbQKasY6IhSLXRMxF1B3OKdR9K/kccp
 | 
			
		||||
# kvNcGl8D7YyYS4mhCUMBR+VLrg3f8PUj38A9V5aiY2/Jok7WZFOAmjPRNNGnyeg7
 | 
			
		||||
# l0lTiThFqE+2aOs6+heegqAdelGgNJKRHLWRuhGKuLIw5lkgx9Ky+QvZrn/Ddi8u
 | 
			
		||||
# TIgWKp+MGG8xY6PBvvjgt9jQShlnPrZ3UY8Bvwy6rynhXBaV0V0TTL0gEx7eh/K1
 | 
			
		||||
# o8Miaru6s/7FyqOLeUS4vTHh9TgBL5DtxCYurXbSBVtL1Fj44+Od/6cmC9mmvrti
 | 
			
		||||
# yG709Y3Rd3YdJj2f3GJq7Y7KdWq0QYhatKhBeg4fxjhg0yut2g6aM1mxjNPrE48z
 | 
			
		||||
# 6HWCNGu9gMK5ZudldRw4a45Z06Aoktof0CqOyTErvq0YjoE4Xpa0+87T/PVUXNqf
 | 
			
		||||
# 7Y+qSU7+9LtLQuMYR4w3cSPjuNusvLf9gBnch5RqM7kaDtYWDgLyB42EfsxeMqwK
 | 
			
		||||
# WwA+TVi0HrWRqfSx2olbE56hJcEkMjOSKz3sRuupFCX3UroyYf52L+2iVTrda8XW
 | 
			
		||||
# esPG62Mnn3T8AuLfzeJFuAbfOSERx7IFZO92UPoXE1uEjL5skl1yTZB3MubgOA4F
 | 
			
		||||
# 8KoRNhviFAEST+nG8c8uIsbZeb08SeYQMqjVEmkwggd6MIIFYqADAgECAgphDpDS
 | 
			
		||||
# AAAAAAADMA0GCSqGSIb3DQEBCwUAMIGIMQswCQYDVQQGEwJVUzETMBEGA1UECBMK
 | 
			
		||||
# V2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0
 | 
			
		||||
# IENvcnBvcmF0aW9uMTIwMAYDVQQDEylNaWNyb3NvZnQgUm9vdCBDZXJ0aWZpY2F0
 | 
			
		||||
# ZSBBdXRob3JpdHkgMjAxMTAeFw0xMTA3MDgyMDU5MDlaFw0yNjA3MDgyMTA5MDla
 | 
			
		||||
# MH4xCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdS
 | 
			
		||||
# ZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMT
 | 
			
		||||
# H01pY3Jvc29mdCBDb2RlIFNpZ25pbmcgUENBIDIwMTEwggIiMA0GCSqGSIb3DQEB
 | 
			
		||||
# AQUAA4ICDwAwggIKAoICAQCr8PpyEBwurdhuqoIQTTS68rZYIZ9CGypr6VpQqrgG
 | 
			
		||||
# OBoESbp/wwwe3TdrxhLYC/A4wpkGsMg51QEUMULTiQ15ZId+lGAkbK+eSZzpaF7S
 | 
			
		||||
# 35tTsgosw6/ZqSuuegmv15ZZymAaBelmdugyUiYSL+erCFDPs0S3XdjELgN1q2jz
 | 
			
		||||
# y23zOlyhFvRGuuA4ZKxuZDV4pqBjDy3TQJP4494HDdVceaVJKecNvqATd76UPe/7
 | 
			
		||||
# 4ytaEB9NViiienLgEjq3SV7Y7e1DkYPZe7J7hhvZPrGMXeiJT4Qa8qEvWeSQOy2u
 | 
			
		||||
# M1jFtz7+MtOzAz2xsq+SOH7SnYAs9U5WkSE1JcM5bmR/U7qcD60ZI4TL9LoDho33
 | 
			
		||||
# X/DQUr+MlIe8wCF0JV8YKLbMJyg4JZg5SjbPfLGSrhwjp6lm7GEfauEoSZ1fiOIl
 | 
			
		||||
# XdMhSz5SxLVXPyQD8NF6Wy/VI+NwXQ9RRnez+ADhvKwCgl/bwBWzvRvUVUvnOaEP
 | 
			
		||||
# 6SNJvBi4RHxF5MHDcnrgcuck379GmcXvwhxX24ON7E1JMKerjt/sW5+v/N2wZuLB
 | 
			
		||||
# l4F77dbtS+dJKacTKKanfWeA5opieF+yL4TXV5xcv3coKPHtbcMojyyPQDdPweGF
 | 
			
		||||
# RInECUzF1KVDL3SV9274eCBYLBNdYJWaPk8zhNqwiBfenk70lrC8RqBsmNLg1oiM
 | 
			
		||||
# CwIDAQABo4IB7TCCAekwEAYJKwYBBAGCNxUBBAMCAQAwHQYDVR0OBBYEFEhuZOVQ
 | 
			
		||||
# BdOCqhc3NyK1bajKdQKVMBkGCSsGAQQBgjcUAgQMHgoAUwB1AGIAQwBBMAsGA1Ud
 | 
			
		||||
# DwQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFHItOgIxkEO5FAVO
 | 
			
		||||
# 4eqnxzHRI4k0MFoGA1UdHwRTMFEwT6BNoEuGSWh0dHA6Ly9jcmwubWljcm9zb2Z0
 | 
			
		||||
# LmNvbS9wa2kvY3JsL3Byb2R1Y3RzL01pY1Jvb0NlckF1dDIwMTFfMjAxMV8wM18y
 | 
			
		||||
# Mi5jcmwwXgYIKwYBBQUHAQEEUjBQME4GCCsGAQUFBzAChkJodHRwOi8vd3d3Lm1p
 | 
			
		||||
# Y3Jvc29mdC5jb20vcGtpL2NlcnRzL01pY1Jvb0NlckF1dDIwMTFfMjAxMV8wM18y
 | 
			
		||||
# Mi5jcnQwgZ8GA1UdIASBlzCBlDCBkQYJKwYBBAGCNy4DMIGDMD8GCCsGAQUFBwIB
 | 
			
		||||
# FjNodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpb3BzL2RvY3MvcHJpbWFyeWNw
 | 
			
		||||
# cy5odG0wQAYIKwYBBQUHAgIwNB4yIB0ATABlAGcAYQBsAF8AcABvAGwAaQBjAHkA
 | 
			
		||||
# XwBzAHQAYQB0AGUAbQBlAG4AdAAuIB0wDQYJKoZIhvcNAQELBQADggIBAGfyhqWY
 | 
			
		||||
# 4FR5Gi7T2HRnIpsLlhHhY5KZQpZ90nkMkMFlXy4sPvjDctFtg/6+P+gKyju/R6mj
 | 
			
		||||
# 82nbY78iNaWXXWWEkH2LRlBV2AySfNIaSxzzPEKLUtCw/WvjPgcuKZvmPRul1LUd
 | 
			
		||||
# d5Q54ulkyUQ9eHoj8xN9ppB0g430yyYCRirCihC7pKkFDJvtaPpoLpWgKj8qa1hJ
 | 
			
		||||
# Yx8JaW5amJbkg/TAj/NGK978O9C9Ne9uJa7lryft0N3zDq+ZKJeYTQ49C/IIidYf
 | 
			
		||||
# wzIY4vDFLc5bnrRJOQrGCsLGra7lstnbFYhRRVg4MnEnGn+x9Cf43iw6IGmYslmJ
 | 
			
		||||
# aG5vp7d0w0AFBqYBKig+gj8TTWYLwLNN9eGPfxxvFX1Fp3blQCplo8NdUmKGwx1j
 | 
			
		||||
# NpeG39rz+PIWoZon4c2ll9DuXWNB41sHnIc+BncG0QaxdR8UvmFhtfDcxhsEvt9B
 | 
			
		||||
# xw4o7t5lL+yX9qFcltgA1qFGvVnzl6UJS0gQmYAf0AApxbGbpT9Fdx41xtKiop96
 | 
			
		||||
# eiL6SJUfq/tHI4D1nvi/a7dLl+LrdXga7Oo3mXkYS//WsyNodeav+vyL6wuA6mk7
 | 
			
		||||
# r/ww7QRMjt/fdW1jkT3RnVZOT7+AVyKheBEyIXrvQQqxP/uozKRdwaGIm1dxVk5I
 | 
			
		||||
# RcBCyZt2WwqASGv9eZ/BvW1taslScxMNelDNMYIZdjCCGXICAQEwgZUwfjELMAkG
 | 
			
		||||
# A1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQx
 | 
			
		||||
# HjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEoMCYGA1UEAxMfTWljcm9z
 | 
			
		||||
# b2Z0IENvZGUgU2lnbmluZyBQQ0EgMjAxMQITMwAAAlKLM6r4lfM52wAAAAACUjAN
 | 
			
		||||
# BglghkgBZQMEAgEFAKCBrjAZBgkqhkiG9w0BCQMxDAYKKwYBBAGCNwIBBDAcBgor
 | 
			
		||||
# BgEEAYI3AgELMQ4wDAYKKwYBBAGCNwIBFTAvBgkqhkiG9w0BCQQxIgQgBzhh8wf+
 | 
			
		||||
# /kA/CamFNwS1K9Nt0wsjATKS8Y66iHQTKrIwQgYKKwYBBAGCNwIBDDE0MDKgFIAS
 | 
			
		||||
# AE0AaQBjAHIAbwBzAG8AZgB0oRqAGGh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbTAN
 | 
			
		||||
# BgkqhkiG9w0BAQEFAASCAQAruzFwahFXWsJ9eny7iY/KyWolnqJ9+cvDD1QaJ0qJ
 | 
			
		||||
# tHlTLP8pr0GPPtitwuk+3JME7wkx80+AZXl/ocO39tdhy1Ucd6yiyV3M1Ub/Eo4D
 | 
			
		||||
# 37L1saazNomWeeMD6oX3FboVe1Ql17MX1SscTW5QRx8ytYgUOUIbrxFybODcdVn9
 | 
			
		||||
# YG7mlkgsJr2lhUhTnHtq7jV/jEu6Sk9o+g15Pbu90VncsCoNerg9aEziui6/W3/g
 | 
			
		||||
# Wvt4WhfCPanppzWVmsvTUp5MAt5cpdNBr9b8CV/alI3TGnNwC8RuWMCK6CS4963l
 | 
			
		||||
# f4AiLZW/fgD8UQYtl+tAyYfSerpX0sDB039jymj1FkqHoYIXADCCFvwGCisGAQQB
 | 
			
		||||
# gjcDAwExghbsMIIW6AYJKoZIhvcNAQcCoIIW2TCCFtUCAQMxDzANBglghkgBZQME
 | 
			
		||||
# AgEFADCCAVEGCyqGSIb3DQEJEAEEoIIBQASCATwwggE4AgEBBgorBgEEAYRZCgMB
 | 
			
		||||
# MDEwDQYJYIZIAWUDBAIBBQAEIEcy5EvHdubbPngOS1BSZ6xt9xSMrt3OLtUyfQaT
 | 
			
		||||
# IyRBAgZh+unPYkgYEzIwMjIwMjA4MTAyMjE5LjM1OVowBIACAfSggdCkgc0wgcox
 | 
			
		||||
# CzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRt
 | 
			
		||||
# b25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xJTAjBgNVBAsTHE1p
 | 
			
		||||
# Y3Jvc29mdCBBbWVyaWNhIE9wZXJhdGlvbnMxJjAkBgNVBAsTHVRoYWxlcyBUU1Mg
 | 
			
		||||
# RVNOOkREOEMtRTMzNy0yRkFFMSUwIwYDVQQDExxNaWNyb3NvZnQgVGltZS1TdGFt
 | 
			
		||||
# cCBTZXJ2aWNloIIRVzCCBwwwggT0oAMCAQICEzMAAAGcD6ZNYdKeSygAAQAAAZww
 | 
			
		||||
# DQYJKoZIhvcNAQELBQAwfDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0
 | 
			
		||||
# b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3Jh
 | 
			
		||||
# dGlvbjEmMCQGA1UEAxMdTWljcm9zb2Z0IFRpbWUtU3RhbXAgUENBIDIwMTAwHhcN
 | 
			
		||||
# MjExMjAyMTkwNTE5WhcNMjMwMjI4MTkwNTE5WjCByjELMAkGA1UEBhMCVVMxEzAR
 | 
			
		||||
# BgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1p
 | 
			
		||||
# Y3Jvc29mdCBDb3Jwb3JhdGlvbjElMCMGA1UECxMcTWljcm9zb2Z0IEFtZXJpY2Eg
 | 
			
		||||
# T3BlcmF0aW9uczEmMCQGA1UECxMdVGhhbGVzIFRTUyBFU046REQ4Qy1FMzM3LTJG
 | 
			
		||||
# QUUxJTAjBgNVBAMTHE1pY3Jvc29mdCBUaW1lLVN0YW1wIFNlcnZpY2UwggIiMA0G
 | 
			
		||||
# CSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDbUioMGV1JFj+s612s02mKu23KPUNs
 | 
			
		||||
# 71OjDeJGtxkTF9rSWTiuA8XgYkAAi/5+2Ff7Ck7JcKQ9H/XD1OKwg1/bH3E1qO1z
 | 
			
		||||
# 8XRy0PlpGhmyilgE7KsOvW8PIZCf243KdldgOrxrL8HKiQodOwStyT5lLWYpMsuT
 | 
			
		||||
# 2fH8k8oihje4TlpWiFPaCKLnFDaAB0Ccy6vIdtHjYB1Ie3iOZPisquL+vNdCx7gO
 | 
			
		||||
# hB8iiTmTdsU8OSUpC8tBTeTIYPzmhaxQZd4moNk6qeCJyi7fiW4fyXdHrZ3otmgx
 | 
			
		||||
# xa5pXz5pUUr+cEjV+cwIYBMkaY5kHM9c6dEGkgHn0ZDJvdt/54FOdSG61WwHh4+e
 | 
			
		||||
# vUhwvXaB4LCMZIdCt5acOfNvtDjV3CHyFOp5AU/qgAwGftHU9brv4EUwcuteEAKH
 | 
			
		||||
# 46NufE20l/WjlNUh7gAvt2zKMjO4zXRxCUTh/prBQwXJiUZeFSrEXiOfkuvSlBni
 | 
			
		||||
# yAYYZp5kOnaxfCKdGYjvr4QLA93vQJ6p2Ox3IHvOdCPaCr8LsKVcFpyp8MEhhJTM
 | 
			
		||||
# +1LwqHJqFDF5O1Z9mjbYvm3R9vPhkG+RDLKoTpr7mTgkaTljd9xvm94Obp8BD9Hk
 | 
			
		||||
# 4mPi51mtgLiuN8/6aZVESVZXtvSuNkD5DnIJQerIy5jaRKW/W2rCe9ngNDJadS7R
 | 
			
		||||
# 96GGRl7IIE37lwIDAQABo4IBNjCCATIwHQYDVR0OBBYEFLtpCWdTXY5dtddkspy+
 | 
			
		||||
# oxjCA/qyMB8GA1UdIwQYMBaAFJ+nFV0AXmJdg/Tl0mWnG1M1GelyMF8GA1UdHwRY
 | 
			
		||||
# MFYwVKBSoFCGTmh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2lvcHMvY3JsL01p
 | 
			
		||||
# Y3Jvc29mdCUyMFRpbWUtU3RhbXAlMjBQQ0ElMjAyMDEwKDEpLmNybDBsBggrBgEF
 | 
			
		||||
# BQcBAQRgMF4wXAYIKwYBBQUHMAKGUGh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9w
 | 
			
		||||
# a2lvcHMvY2VydHMvTWljcm9zb2Z0JTIwVGltZS1TdGFtcCUyMFBDQSUyMDIwMTAo
 | 
			
		||||
# MSkuY3J0MAwGA1UdEwEB/wQCMAAwEwYDVR0lBAwwCgYIKwYBBQUHAwgwDQYJKoZI
 | 
			
		||||
# hvcNAQELBQADggIBAKcAKqYjGEczTWMs9z0m7Yo23sgqVF3LyK6gOMz7TCHAJN+F
 | 
			
		||||
# vbvZkQ53VkvrZUd1sE6a9ToGldcJnOmBc6iuhBlpvdN1BLBRO8QSTD1433VTj4XC
 | 
			
		||||
# Qd737wND1+eqKG3BdjrzbDksEwfG4v57PgrN/T7s7PkEjUGXfIgFQQkr8TQi+/HZ
 | 
			
		||||
# Z9kRlNccgeACqlfb4uGPxn5sdhQPoxdMvmC3qG9DONJ5UsS9KtO+bey+ohUTDa9L
 | 
			
		||||
# vEToc4Qzy5fuHj2H1JsmCaKG78nXpfWpwBLBxZYSpfml29onN8jcG7KD8nGSS/76
 | 
			
		||||
# PDlb2GMQsvv+Ra0JgL6FtGRGgYmHCpM6zVrf4V/a+SoHcC+tcdGYk2aKU5KOlv+f
 | 
			
		||||
# FE3n024V+z54tDAKR9z78rejdCBWqfvy5cBUQ9c5+3unHD08BEp7qP2rgpoD856v
 | 
			
		||||
# NDgEwO77n7EWT76nl/IyrbK2kjbHLzUMphFpXKnV1fYWJI2+E/0LHvXFGGqF4OvM
 | 
			
		||||
# BRxbrJVn03T2Dy5db6s5TzJzSaQvCrXYqA4HKvstQWkqkpvBHTX8M09+/vyRbVXN
 | 
			
		||||
# xrPdeXw6oD2Q4DksykCFfn8N2j2LdixE9wG5iilv69dzsvHIN/g9A9+thkAQCVb9
 | 
			
		||||
# DUSOTaMIGgsOqDYFjhT6ze9lkhHHGv/EEIkxj9l6S4hqUQyWerFkaUWDXcnZMIIH
 | 
			
		||||
# cTCCBVmgAwIBAgITMwAAABXF52ueAptJmQAAAAAAFTANBgkqhkiG9w0BAQsFADCB
 | 
			
		||||
# iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1Jl
 | 
			
		||||
# ZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEyMDAGA1UEAxMp
 | 
			
		||||
# TWljcm9zb2Z0IFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIwMTAwHhcNMjEw
 | 
			
		||||
# OTMwMTgyMjI1WhcNMzAwOTMwMTgzMjI1WjB8MQswCQYDVQQGEwJVUzETMBEGA1UE
 | 
			
		||||
# CBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9z
 | 
			
		||||
# b2Z0IENvcnBvcmF0aW9uMSYwJAYDVQQDEx1NaWNyb3NvZnQgVGltZS1TdGFtcCBQ
 | 
			
		||||
# Q0EgMjAxMDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAOThpkzntHIh
 | 
			
		||||
# C3miy9ckeb0O1YLT/e6cBwfSqWxOdcjKNVf2AX9sSuDivbk+F2Az/1xPx2b3lVNx
 | 
			
		||||
# WuJ+Slr+uDZnhUYjDLWNE893MsAQGOhgfWpSg0S3po5GawcU88V29YZQ3MFEyHFc
 | 
			
		||||
# UTE3oAo4bo3t1w/YJlN8OWECesSq/XJprx2rrPY2vjUmZNqYO7oaezOtgFt+jBAc
 | 
			
		||||
# nVL+tuhiJdxqD89d9P6OU8/W7IVWTe/dvI2k45GPsjksUZzpcGkNyjYtcI4xyDUo
 | 
			
		||||
# veO0hyTD4MmPfrVUj9z6BVWYbWg7mka97aSueik3rMvrg0XnRm7KMtXAhjBcTyzi
 | 
			
		||||
# YrLNueKNiOSWrAFKu75xqRdbZ2De+JKRHh09/SDPc31BmkZ1zcRfNN0Sidb9pSB9
 | 
			
		||||
# fvzZnkXftnIv231fgLrbqn427DZM9ituqBJR6L8FA6PRc6ZNN3SUHDSCD/AQ8rdH
 | 
			
		||||
# GO2n6Jl8P0zbr17C89XYcz1DTsEzOUyOArxCaC4Q6oRRRuLRvWoYWmEBc8pnol7X
 | 
			
		||||
# KHYC4jMYctenIPDC+hIK12NvDMk2ZItboKaDIV1fMHSRlJTYuVD5C4lh8zYGNRiE
 | 
			
		||||
# R9vcG9H9stQcxWv2XFJRXRLbJbqvUAV6bMURHXLvjflSxIUXk8A8FdsaN8cIFRg/
 | 
			
		||||
# eKtFtvUeh17aj54WcmnGrnu3tz5q4i6tAgMBAAGjggHdMIIB2TASBgkrBgEEAYI3
 | 
			
		||||
# FQEEBQIDAQABMCMGCSsGAQQBgjcVAgQWBBQqp1L+ZMSavoKRPEY1Kc8Q/y8E7jAd
 | 
			
		||||
# BgNVHQ4EFgQUn6cVXQBeYl2D9OXSZacbUzUZ6XIwXAYDVR0gBFUwUzBRBgwrBgEE
 | 
			
		||||
# AYI3TIN9AQEwQTA/BggrBgEFBQcCARYzaHR0cDovL3d3dy5taWNyb3NvZnQuY29t
 | 
			
		||||
# L3BraW9wcy9Eb2NzL1JlcG9zaXRvcnkuaHRtMBMGA1UdJQQMMAoGCCsGAQUFBwMI
 | 
			
		||||
# MBkGCSsGAQQBgjcUAgQMHgoAUwB1AGIAQwBBMAsGA1UdDwQEAwIBhjAPBgNVHRMB
 | 
			
		||||
# Af8EBTADAQH/MB8GA1UdIwQYMBaAFNX2VsuP6KJcYmjRPZSQW9fOmhjEMFYGA1Ud
 | 
			
		||||
# HwRPME0wS6BJoEeGRWh0dHA6Ly9jcmwubWljcm9zb2Z0LmNvbS9wa2kvY3JsL3By
 | 
			
		||||
# b2R1Y3RzL01pY1Jvb0NlckF1dF8yMDEwLTA2LTIzLmNybDBaBggrBgEFBQcBAQRO
 | 
			
		||||
# MEwwSgYIKwYBBQUHMAKGPmh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2kvY2Vy
 | 
			
		||||
# dHMvTWljUm9vQ2VyQXV0XzIwMTAtMDYtMjMuY3J0MA0GCSqGSIb3DQEBCwUAA4IC
 | 
			
		||||
# AQCdVX38Kq3hLB9nATEkW+Geckv8qW/qXBS2Pk5HZHixBpOXPTEztTnXwnE2P9pk
 | 
			
		||||
# bHzQdTltuw8x5MKP+2zRoZQYIu7pZmc6U03dmLq2HnjYNi6cqYJWAAOwBb6J6Gng
 | 
			
		||||
# ugnue99qb74py27YP0h1AdkY3m2CDPVtI1TkeFN1JFe53Z/zjj3G82jfZfakVqr3
 | 
			
		||||
# lbYoVSfQJL1AoL8ZthISEV09J+BAljis9/kpicO8F7BUhUKz/AyeixmJ5/ALaoHC
 | 
			
		||||
# gRlCGVJ1ijbCHcNhcy4sa3tuPywJeBTpkbKpW99Jo3QMvOyRgNI95ko+ZjtPu4b6
 | 
			
		||||
# MhrZlvSP9pEB9s7GdP32THJvEKt1MMU0sHrYUP4KWN1APMdUbZ1jdEgssU5HLcEU
 | 
			
		||||
# BHG/ZPkkvnNtyo4JvbMBV0lUZNlz138eW0QBjloZkWsNn6Qo3GcZKCS6OEuabvsh
 | 
			
		||||
# VGtqRRFHqfG3rsjoiV5PndLQTHa1V1QJsWkBRH58oWFsc/4Ku+xBZj1p/cvBQUl+
 | 
			
		||||
# fpO+y/g75LcVv7TOPqUxUYS8vwLBgqJ7Fx0ViY1w/ue10CgaiQuPNtq6TPmb/wrp
 | 
			
		||||
# NPgkNWcr4A245oyZ1uEi6vAnQj0llOZ0dFtq0Z4+7X6gMTN9vMvpe784cETRkPHI
 | 
			
		||||
# qzqKOghif9lwY1NNje6CbaUFEMFxBmoQtB1VM1izoXBm8qGCAs4wggI3AgEBMIH4
 | 
			
		||||
# oYHQpIHNMIHKMQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4G
 | 
			
		||||
# A1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSUw
 | 
			
		||||
# IwYDVQQLExxNaWNyb3NvZnQgQW1lcmljYSBPcGVyYXRpb25zMSYwJAYDVQQLEx1U
 | 
			
		||||
# aGFsZXMgVFNTIEVTTjpERDhDLUUzMzctMkZBRTElMCMGA1UEAxMcTWljcm9zb2Z0
 | 
			
		||||
# IFRpbWUtU3RhbXAgU2VydmljZaIjCgEBMAcGBSsOAwIaAxUAzdlp6t3ws/bnErbm
 | 
			
		||||
# 9c0M+9dvU0CggYMwgYCkfjB8MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGlu
 | 
			
		||||
# Z3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBv
 | 
			
		||||
# cmF0aW9uMSYwJAYDVQQDEx1NaWNyb3NvZnQgVGltZS1TdGFtcCBQQ0EgMjAxMDAN
 | 
			
		||||
# BgkqhkiG9w0BAQUFAAIFAOWsqGYwIhgPMjAyMjAyMDgxNjI5MjZaGA8yMDIyMDIw
 | 
			
		||||
# OTE2MjkyNlowdzA9BgorBgEEAYRZCgQBMS8wLTAKAgUA5ayoZgIBADAKAgEAAgIi
 | 
			
		||||
# 7QIB/zAHAgEAAgITmjAKAgUA5a355gIBADA2BgorBgEEAYRZCgQCMSgwJjAMBgor
 | 
			
		||||
# BgEEAYRZCgMCoAowCAIBAAIDB6EgoQowCAIBAAIDAYagMA0GCSqGSIb3DQEBBQUA
 | 
			
		||||
# A4GBAKFiWA9Ov0L2rGOdPitNu60BAeztCagpqKBsGnKaaSmjA/XcSXrtIvcUBBsw
 | 
			
		||||
# WlflwqnKvPDv3ihqUXsxY84IZZaMecGWzN1mXLh00VftiZuzoLMDlSEtvzmxeWYg
 | 
			
		||||
# 4nFHTR5oMqxy06auAM08mVl3P4MywHz4Yp21OIs2KSWQg3DSMYIEDTCCBAkCAQEw
 | 
			
		||||
# gZMwfDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcT
 | 
			
		||||
# B1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEmMCQGA1UE
 | 
			
		||||
# AxMdTWljcm9zb2Z0IFRpbWUtU3RhbXAgUENBIDIwMTACEzMAAAGcD6ZNYdKeSygA
 | 
			
		||||
# AQAAAZwwDQYJYIZIAWUDBAIBBQCgggFKMBoGCSqGSIb3DQEJAzENBgsqhkiG9w0B
 | 
			
		||||
# CRABBDAvBgkqhkiG9w0BCQQxIgQg8oNFH9aqIpzxu29p4VzI2Hh6Hzv2T5HQOlhP
 | 
			
		||||
# W5ksqHkwgfoGCyqGSIb3DQEJEAIvMYHqMIHnMIHkMIG9BCA3D0WFII0syjoRd/Xe
 | 
			
		||||
# EIG0WUIKzzuy6P6hORrb0nqmvDCBmDCBgKR+MHwxCzAJBgNVBAYTAlVTMRMwEQYD
 | 
			
		||||
# VQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNy
 | 
			
		||||
# b3NvZnQgQ29ycG9yYXRpb24xJjAkBgNVBAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1w
 | 
			
		||||
# IFBDQSAyMDEwAhMzAAABnA+mTWHSnksoAAEAAAGcMCIEIOSl7GUcmDL8AU+F0I3A
 | 
			
		||||
# iZQESHSkml1QPlOc3M8uqdF0MA0GCSqGSIb3DQEBCwUABIICAHV226l2xxnkjTdh
 | 
			
		||||
# Q6wi7u8betBvFNfYYn5cXwy+NoU30JjQ3ynnmNSB+TQVlmcthi8duP8dud+NU5xc
 | 
			
		||||
# +1jBTcJTHjWk/TDZUYpB/xNqsgUTJ8fnebVZhioPJhmFJMeQztT4NTD1ZbeJWO4O
 | 
			
		||||
# EABDpRqyns2eQptCrKcPIypjvdDeYfkwjgnUEyyaTZRHPZ2kNOLY6kO9feKfntFW
 | 
			
		||||
# 8YUIaas2IzI5GcGm+kw1efHveG0WvUpeGuFKsTUA6Jb18mOyamafu32ftD5t5LXV
 | 
			
		||||
# +GMgnaJLgdogAAGwK0GiB47YNIvPlKD6bGnyTR3KNYheI1GI38w0knOecCC4NW0k
 | 
			
		||||
# 21qROWJdnkKLKTtBX344yTnJbbKoIPzGgyWCzSINS2SD4JHzgTu8dsmMMJWwcEZh
 | 
			
		||||
# BLyrzmd/vWrjUFQFXVf6RZmJJVvF28s7LWrpXPVTR8Al75j8KqyZKou4fZvyaHtx
 | 
			
		||||
# S6K0jIqavLWqWd4wvx9seCtA0Pz1GWrBZADIRHG8d8cFoY95Z99z84NM81qXB246
 | 
			
		||||
# IsxU2iW+96zMJriMNEKaLHzlgFoWsoXLDQhuQItjwIvzwmwygwx0MxqoFYm+lDWG
 | 
			
		||||
# 8/KtSh47aZicAlwqNVGy3MZHDnX69kysQsrWoe2wDhJ3eHJ4zRL2WHVagz26L7xF
 | 
			
		||||
# oSkLphLv0GiFseJhPvXGQPypnyN8
 | 
			
		||||
# SIG # End signature block
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										438
									
								
								externals/install-dotnet.sh
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										438
									
								
								externals/install-dotnet.sh
									
									
									
									
										vendored
									
									
								
							@ -298,14 +298,43 @@ get_machine_architecture() {
 | 
			
		||||
    if command -v uname > /dev/null; then
 | 
			
		||||
        CPUName=$(uname -m)
 | 
			
		||||
        case $CPUName in
 | 
			
		||||
        armv1*|armv2*|armv3*|armv4*|armv5*|armv6*)
 | 
			
		||||
            echo "armv6-or-below"
 | 
			
		||||
            return 0
 | 
			
		||||
            ;;
 | 
			
		||||
        armv*l)
 | 
			
		||||
            echo "arm"
 | 
			
		||||
            return 0
 | 
			
		||||
            ;;
 | 
			
		||||
        aarch64|arm64)
 | 
			
		||||
            if [ "$(getconf LONG_BIT)" -lt 64 ]; then
 | 
			
		||||
                # This is 32-bit OS running on 64-bit CPU (for example Raspberry Pi OS)
 | 
			
		||||
                echo "arm"
 | 
			
		||||
                return 0
 | 
			
		||||
            fi
 | 
			
		||||
            echo "arm64"
 | 
			
		||||
            return 0
 | 
			
		||||
            ;;
 | 
			
		||||
        s390x)
 | 
			
		||||
            echo "s390x"
 | 
			
		||||
            return 0
 | 
			
		||||
            ;;
 | 
			
		||||
        ppc64le)
 | 
			
		||||
            echo "ppc64le"
 | 
			
		||||
            return 0
 | 
			
		||||
            ;;
 | 
			
		||||
        loongarch64)
 | 
			
		||||
            echo "loongarch64"
 | 
			
		||||
            return 0
 | 
			
		||||
            ;;
 | 
			
		||||
        riscv64)
 | 
			
		||||
            echo "riscv64"
 | 
			
		||||
            return 0
 | 
			
		||||
            ;;
 | 
			
		||||
        powerpc|ppc)
 | 
			
		||||
            echo "ppc"
 | 
			
		||||
            return 0
 | 
			
		||||
            ;;
 | 
			
		||||
        esac
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
@ -322,7 +351,13 @@ get_normalized_architecture_from_architecture() {
 | 
			
		||||
    local architecture="$(to_lowercase "$1")"
 | 
			
		||||
 | 
			
		||||
    if [[ $architecture == \<auto\> ]]; then
 | 
			
		||||
        echo "$(get_machine_architecture)"
 | 
			
		||||
        machine_architecture="$(get_machine_architecture)"
 | 
			
		||||
        if [[ "$machine_architecture" == "armv6-or-below" ]]; then
 | 
			
		||||
            say_err "Architecture \`$machine_architecture\` not supported. If you think this is a bug, report it at https://github.com/dotnet/install-scripts/issues"
 | 
			
		||||
            return 1
 | 
			
		||||
        fi
 | 
			
		||||
 | 
			
		||||
        echo $machine_architecture
 | 
			
		||||
        return 0
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
@ -339,12 +374,72 @@ get_normalized_architecture_from_architecture() {
 | 
			
		||||
            echo "arm64"
 | 
			
		||||
            return 0
 | 
			
		||||
            ;;
 | 
			
		||||
        s390x)
 | 
			
		||||
            echo "s390x"
 | 
			
		||||
            return 0
 | 
			
		||||
            ;;
 | 
			
		||||
        ppc64le)
 | 
			
		||||
            echo "ppc64le"
 | 
			
		||||
            return 0
 | 
			
		||||
            ;;
 | 
			
		||||
        loongarch64)
 | 
			
		||||
            echo "loongarch64"
 | 
			
		||||
            return 0
 | 
			
		||||
            ;;
 | 
			
		||||
    esac
 | 
			
		||||
 | 
			
		||||
    say_err "Architecture \`$architecture\` not supported. If you think this is a bug, report it at https://github.com/dotnet/install-scripts/issues"
 | 
			
		||||
    return 1
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# args:
 | 
			
		||||
# version - $1
 | 
			
		||||
# channel - $2
 | 
			
		||||
# architecture - $3
 | 
			
		||||
get_normalized_architecture_for_specific_sdk_version() {
 | 
			
		||||
    eval $invocation
 | 
			
		||||
 | 
			
		||||
    local is_version_support_arm64="$(is_arm64_supported "$1")"
 | 
			
		||||
    local is_channel_support_arm64="$(is_arm64_supported "$2")"
 | 
			
		||||
    local architecture="$3";
 | 
			
		||||
    local osname="$(get_current_os_name)"
 | 
			
		||||
 | 
			
		||||
    if [ "$osname" == "osx" ] && [ "$architecture" == "arm64" ] && { [ "$is_version_support_arm64" = false ] || [ "$is_channel_support_arm64" = false ]; }; then
 | 
			
		||||
        #check if rosetta is installed
 | 
			
		||||
        if [ "$(/usr/bin/pgrep oahd >/dev/null 2>&1;echo $?)" -eq 0 ]; then 
 | 
			
		||||
            say_verbose "Changing user architecture from '$architecture' to 'x64' because .NET SDKs prior to version 6.0 do not support arm64." 
 | 
			
		||||
            echo "x64"
 | 
			
		||||
            return 0;
 | 
			
		||||
        else
 | 
			
		||||
            say_err "Architecture \`$architecture\` is not supported for .NET SDK version \`$version\`. Please install Rosetta to allow emulation of the \`$architecture\` .NET SDK on this platform"
 | 
			
		||||
            return 1
 | 
			
		||||
        fi
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    echo "$architecture"
 | 
			
		||||
    return 0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# args:
 | 
			
		||||
# version or channel - $1
 | 
			
		||||
is_arm64_supported() {
 | 
			
		||||
    # Extract the major version by splitting on the dot
 | 
			
		||||
    major_version="${1%%.*}"
 | 
			
		||||
 | 
			
		||||
    # Check if the major version is a valid number and less than 6
 | 
			
		||||
    case "$major_version" in
 | 
			
		||||
        [0-9]*)  
 | 
			
		||||
            if [ "$major_version" -lt 6 ]; then
 | 
			
		||||
                echo false
 | 
			
		||||
                return 0
 | 
			
		||||
            fi
 | 
			
		||||
            ;;
 | 
			
		||||
    esac
 | 
			
		||||
 | 
			
		||||
    echo true
 | 
			
		||||
    return 0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# args:
 | 
			
		||||
# user_defined_os - $1
 | 
			
		||||
get_normalized_os() {
 | 
			
		||||
@ -357,8 +452,13 @@ get_normalized_os() {
 | 
			
		||||
                echo "$osname"
 | 
			
		||||
                return 0
 | 
			
		||||
                ;;
 | 
			
		||||
            macos)
 | 
			
		||||
                osname='osx'
 | 
			
		||||
                echo "$osname"
 | 
			
		||||
                return 0
 | 
			
		||||
                ;;
 | 
			
		||||
            *)
 | 
			
		||||
                say_err "'$user_defined_os' is not a supported value for --os option, supported values are: osx, linux, linux-musl, freebsd, rhel.6. If you think this is a bug, report it at https://github.com/dotnet/install-scripts/issues."
 | 
			
		||||
                say_err "'$user_defined_os' is not a supported value for --os option, supported values are: osx, macos, linux, linux-musl, freebsd, rhel.6. If you think this is a bug, report it at https://github.com/dotnet/install-scripts/issues."
 | 
			
		||||
                return 1
 | 
			
		||||
                ;;
 | 
			
		||||
        esac
 | 
			
		||||
@ -401,6 +501,10 @@ get_normalized_channel() {
 | 
			
		||||
 | 
			
		||||
    local channel="$(to_lowercase "$1")"
 | 
			
		||||
 | 
			
		||||
    if [[ $channel == current ]]; then
 | 
			
		||||
        say_warning 'Value "Current" is deprecated for -Channel option. Use "STS" instead.'
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    if [[ $channel == release/* ]]; then
 | 
			
		||||
        say_warning 'Using branch name with -Channel option is no longer supported with newer releases. Use -Quality option with a channel in X.Y format instead.';
 | 
			
		||||
    fi
 | 
			
		||||
@ -411,6 +515,14 @@ get_normalized_channel() {
 | 
			
		||||
                echo "LTS"
 | 
			
		||||
                return 0
 | 
			
		||||
                ;;
 | 
			
		||||
            sts)
 | 
			
		||||
                echo "STS"
 | 
			
		||||
                return 0
 | 
			
		||||
                ;;
 | 
			
		||||
            current)
 | 
			
		||||
                echo "STS"
 | 
			
		||||
                return 0
 | 
			
		||||
                ;;
 | 
			
		||||
            *)
 | 
			
		||||
                echo "$channel"
 | 
			
		||||
                return 0
 | 
			
		||||
@ -476,6 +588,40 @@ is_dotnet_package_installed() {
 | 
			
		||||
    fi
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# args:
 | 
			
		||||
# downloaded file - $1
 | 
			
		||||
# remote_file_size - $2
 | 
			
		||||
validate_remote_local_file_sizes() 
 | 
			
		||||
{
 | 
			
		||||
    eval $invocation
 | 
			
		||||
 | 
			
		||||
    local downloaded_file="$1"
 | 
			
		||||
    local remote_file_size="$2"
 | 
			
		||||
    local file_size=''
 | 
			
		||||
 | 
			
		||||
    if [[ "$OSTYPE" == "linux-gnu"* ]]; then
 | 
			
		||||
        file_size="$(stat -c '%s' "$downloaded_file")"
 | 
			
		||||
    elif [[ "$OSTYPE" == "darwin"* ]]; then
 | 
			
		||||
        # hardcode in order to avoid conflicts with GNU stat
 | 
			
		||||
        file_size="$(/usr/bin/stat -f '%z' "$downloaded_file")"
 | 
			
		||||
    fi  
 | 
			
		||||
    
 | 
			
		||||
    if [ -n "$file_size" ]; then
 | 
			
		||||
        say "Downloaded file size is $file_size bytes."
 | 
			
		||||
 | 
			
		||||
        if [ -n "$remote_file_size" ] && [ -n "$file_size" ]; then
 | 
			
		||||
            if [ "$remote_file_size" -ne "$file_size" ]; then
 | 
			
		||||
                say "The remote and local file sizes are not equal. The remote file size is $remote_file_size bytes and the local size is $file_size bytes. The local package may be corrupted."
 | 
			
		||||
            else
 | 
			
		||||
                say "The remote and local file sizes are equal."
 | 
			
		||||
            fi
 | 
			
		||||
        fi
 | 
			
		||||
        
 | 
			
		||||
    else
 | 
			
		||||
        say "Either downloaded or local package size can not be measured. One of them may be corrupted."      
 | 
			
		||||
    fi 
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# args:
 | 
			
		||||
# azure_feed - $1
 | 
			
		||||
# channel - $2
 | 
			
		||||
@ -515,7 +661,7 @@ parse_globaljson_file_for_version() {
 | 
			
		||||
        return 1
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    sdk_section=$(cat $json_file | awk '/"sdk"/,/}/')
 | 
			
		||||
    sdk_section=$(cat $json_file | tr -d "\r" | awk '/"sdk"/,/}/')
 | 
			
		||||
    if [ -z "$sdk_section" ]; then
 | 
			
		||||
        say_err "Unable to parse the SDK node in \`$json_file\`"
 | 
			
		||||
        return 1
 | 
			
		||||
@ -637,11 +783,13 @@ get_specific_product_version() {
 | 
			
		||||
 | 
			
		||||
        if machine_has "curl"
 | 
			
		||||
        then
 | 
			
		||||
            specific_product_version=$(curl -s --fail "${download_link}${feed_credential}" 2>&1)
 | 
			
		||||
            if [ $? = 0 ]; then
 | 
			
		||||
            if ! specific_product_version=$(curl -s --fail "${download_link}${feed_credential}" 2>&1); then
 | 
			
		||||
                continue
 | 
			
		||||
            else
 | 
			
		||||
                echo "${specific_product_version//[$'\t\r\n']}"
 | 
			
		||||
                return 0
 | 
			
		||||
            fi
 | 
			
		||||
 | 
			
		||||
        elif machine_has "wget"
 | 
			
		||||
        then
 | 
			
		||||
            specific_product_version=$(wget -qO- "${download_link}${feed_credential}" 2>&1)
 | 
			
		||||
@ -808,6 +956,37 @@ get_absolute_path() {
 | 
			
		||||
    return 0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# args:
 | 
			
		||||
# override - $1 (boolean, true or false)
 | 
			
		||||
get_cp_options() {
 | 
			
		||||
    eval $invocation
 | 
			
		||||
 | 
			
		||||
    local override="$1"
 | 
			
		||||
    local override_switch=""
 | 
			
		||||
 | 
			
		||||
    if [ "$override" = false ]; then
 | 
			
		||||
        override_switch="-n"
 | 
			
		||||
 | 
			
		||||
        # create temporary files to check if 'cp -u' is supported
 | 
			
		||||
        tmp_dir="$(mktemp -d)"
 | 
			
		||||
        tmp_file="$tmp_dir/testfile"
 | 
			
		||||
        tmp_file2="$tmp_dir/testfile2"
 | 
			
		||||
 | 
			
		||||
        touch "$tmp_file"
 | 
			
		||||
 | 
			
		||||
        # use -u instead of -n if it's available
 | 
			
		||||
        if cp -u "$tmp_file" "$tmp_file2" 2>/dev/null; then
 | 
			
		||||
            override_switch="-u"
 | 
			
		||||
        fi
 | 
			
		||||
 | 
			
		||||
        # clean up
 | 
			
		||||
        rm -f "$tmp_file" "$tmp_file2"
 | 
			
		||||
        rm -rf "$tmp_dir"
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    echo "$override_switch"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# args:
 | 
			
		||||
# input_files - stdin
 | 
			
		||||
# root_path - $1
 | 
			
		||||
@ -819,15 +998,7 @@ copy_files_or_dirs_from_list() {
 | 
			
		||||
    local root_path="$(remove_trailing_slash "$1")"
 | 
			
		||||
    local out_path="$(remove_trailing_slash "$2")"
 | 
			
		||||
    local override="$3"
 | 
			
		||||
    local osname="$(get_current_os_name)"
 | 
			
		||||
    local override_switch=$(
 | 
			
		||||
        if [ "$override" = false ]; then
 | 
			
		||||
            if [ "$osname" = "linux-musl" ]; then
 | 
			
		||||
                printf -- "-u";
 | 
			
		||||
            else
 | 
			
		||||
                printf -- "-n";
 | 
			
		||||
            fi
 | 
			
		||||
        fi)
 | 
			
		||||
    local override_switch="$(get_cp_options "$override")"
 | 
			
		||||
 | 
			
		||||
    cat | uniq | while read -r file_path; do
 | 
			
		||||
        local path="$(remove_beginning_slash "${file_path#$root_path}")"
 | 
			
		||||
@ -842,14 +1013,39 @@ copy_files_or_dirs_from_list() {
 | 
			
		||||
    done
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# args:
 | 
			
		||||
# zip_uri - $1
 | 
			
		||||
get_remote_file_size() {
 | 
			
		||||
    local zip_uri="$1"
 | 
			
		||||
 | 
			
		||||
    if machine_has "curl"; then
 | 
			
		||||
        file_size=$(curl -sI  "$zip_uri" | grep -i content-length | awk '{ num = $2 + 0; print num }')
 | 
			
		||||
    elif machine_has "wget"; then
 | 
			
		||||
        file_size=$(wget --spider --server-response -O /dev/null "$zip_uri" 2>&1 | grep -i 'Content-Length:' | awk '{ num = $2 + 0; print num }')
 | 
			
		||||
    else
 | 
			
		||||
        say "Neither curl nor wget is available on this system."
 | 
			
		||||
        return
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    if [ -n "$file_size" ]; then
 | 
			
		||||
        say "Remote file $zip_uri size is $file_size bytes."
 | 
			
		||||
        echo "$file_size"
 | 
			
		||||
    else
 | 
			
		||||
        say_verbose "Content-Length header was not extracted for $zip_uri."
 | 
			
		||||
        echo ""
 | 
			
		||||
    fi
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# args:
 | 
			
		||||
# zip_path - $1
 | 
			
		||||
# out_path - $2
 | 
			
		||||
# remote_file_size - $3
 | 
			
		||||
extract_dotnet_package() {
 | 
			
		||||
    eval $invocation
 | 
			
		||||
 | 
			
		||||
    local zip_path="$1"
 | 
			
		||||
    local out_path="$2"
 | 
			
		||||
    local remote_file_size="$3"
 | 
			
		||||
 | 
			
		||||
    local temp_out_path="$(mktemp -d "$temporary_file_template")"
 | 
			
		||||
 | 
			
		||||
@ -860,8 +1056,12 @@ extract_dotnet_package() {
 | 
			
		||||
    find "$temp_out_path" -type f | grep -Eo "$folders_with_version_regex" | sort | copy_files_or_dirs_from_list "$temp_out_path" "$out_path" false
 | 
			
		||||
    find "$temp_out_path" -type f | grep -Ev "$folders_with_version_regex" | copy_files_or_dirs_from_list "$temp_out_path" "$out_path" "$override_non_versioned_files"
 | 
			
		||||
    
 | 
			
		||||
    validate_remote_local_file_sizes "$zip_path" "$remote_file_size"
 | 
			
		||||
    
 | 
			
		||||
    rm -rf "$temp_out_path"
 | 
			
		||||
    rm -f "$zip_path" && say_verbose "Temporary zip file $zip_path was removed"
 | 
			
		||||
    if [ -z ${keep_zip+x} ]; then
 | 
			
		||||
        rm -f "$zip_path" && say_verbose "Temporary archive file $zip_path was removed"
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    if [ "$failed" = true ]; then
 | 
			
		||||
        say_err "Extraction failed"
 | 
			
		||||
@ -921,9 +1121,15 @@ get_http_header_wget() {
 | 
			
		||||
    local remote_path="$1"
 | 
			
		||||
    local disable_feed_credential="$2"
 | 
			
		||||
    local wget_options="-q -S --spider --tries 5 "
 | 
			
		||||
    # Store options that aren't supported on all wget implementations separately.
 | 
			
		||||
    local wget_options_extra="--waitretry 2 --connect-timeout 15 "
 | 
			
		||||
    local wget_result=''
 | 
			
		||||
 | 
			
		||||
    local wget_options_extra=''
 | 
			
		||||
 | 
			
		||||
    # Test for options that aren't supported on all wget implementations.
 | 
			
		||||
    if [[ $(wget -h 2>&1 | grep -E 'waitretry|connect-timeout') ]]; then
 | 
			
		||||
        wget_options_extra="--waitretry 2 --connect-timeout 15 "
 | 
			
		||||
    else
 | 
			
		||||
        say "wget extra options are unavailable for this environment"
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    remote_path_with_credential="$remote_path"
 | 
			
		||||
    if [ "$disable_feed_credential" = false ]; then
 | 
			
		||||
@ -931,15 +1137,8 @@ get_http_header_wget() {
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    wget $wget_options $wget_options_extra "$remote_path_with_credential" 2>&1
 | 
			
		||||
    wget_result=$?
 | 
			
		||||
 | 
			
		||||
    if [[ $wget_result == 2 ]]; then
 | 
			
		||||
        # Parsing of the command has failed. Exclude potentially unrecognized options and retry.
 | 
			
		||||
        wget $wget_options "$remote_path_with_credential" 2>&1
 | 
			
		||||
    return $?
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    return $wget_result
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# args:
 | 
			
		||||
@ -979,8 +1178,6 @@ download() {
 | 
			
		||||
        sleep $((attempts*10))
 | 
			
		||||
    done
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    if [ "$failed" = true ]; then
 | 
			
		||||
        say_verbose "Download failed: $remote_path"
 | 
			
		||||
        return 1
 | 
			
		||||
@ -999,20 +1196,28 @@ downloadcurl() {
 | 
			
		||||
    # Avoid passing URI with credentials to functions: note, most of them echoing parameters of invocation in verbose output.
 | 
			
		||||
    local remote_path_with_credential="${remote_path}${feed_credential}"
 | 
			
		||||
    local curl_options="--retry 20 --retry-delay 2 --connect-timeout 15 -sSL -f --create-dirs "
 | 
			
		||||
    local failed=false
 | 
			
		||||
    local curl_exit_code=0;
 | 
			
		||||
    if [ -z "$out_path" ]; then
 | 
			
		||||
        curl $curl_options "$remote_path_with_credential" 2>&1 || failed=true
 | 
			
		||||
        curl $curl_options "$remote_path_with_credential" 2>&1
 | 
			
		||||
        curl_exit_code=$?
 | 
			
		||||
    else
 | 
			
		||||
        curl $curl_options -o "$out_path" "$remote_path_with_credential" 2>&1 || failed=true
 | 
			
		||||
        curl $curl_options -o "$out_path" "$remote_path_with_credential" 2>&1
 | 
			
		||||
        curl_exit_code=$?
 | 
			
		||||
    fi
 | 
			
		||||
    if [ "$failed" = true ]; then
 | 
			
		||||
    
 | 
			
		||||
    if [ $curl_exit_code -gt 0 ]; then
 | 
			
		||||
        download_error_msg="Unable to download $remote_path."
 | 
			
		||||
        # Check for curl timeout codes
 | 
			
		||||
        if [[ $curl_exit_code == 7 || $curl_exit_code == 28 ]]; then
 | 
			
		||||
            download_error_msg+=" Failed to reach the server: connection timeout."
 | 
			
		||||
        else
 | 
			
		||||
            local disable_feed_credential=false
 | 
			
		||||
            local response=$(get_http_header_curl $remote_path $disable_feed_credential)
 | 
			
		||||
            http_code=$( echo "$response" | awk '/^HTTP/{print $2}' | tail -1 )
 | 
			
		||||
        download_error_msg="Unable to download $remote_path."
 | 
			
		||||
        if  [[ $http_code != 2* ]]; then
 | 
			
		||||
            if  [[ ! -z $http_code && $http_code != 2* ]]; then
 | 
			
		||||
                download_error_msg+=" Returned HTTP status code: $http_code."
 | 
			
		||||
            fi
 | 
			
		||||
        fi
 | 
			
		||||
        say_verbose "$download_error_msg"
 | 
			
		||||
        return 1
 | 
			
		||||
    fi
 | 
			
		||||
@ -1030,10 +1235,17 @@ downloadwget() {
 | 
			
		||||
    # Append feed_credential as late as possible before calling wget to avoid logging feed_credential
 | 
			
		||||
    local remote_path_with_credential="${remote_path}${feed_credential}"
 | 
			
		||||
    local wget_options="--tries 20 "
 | 
			
		||||
    # Store options that aren't supported on all wget implementations separately.
 | 
			
		||||
    local wget_options_extra="--waitretry 2 --connect-timeout 15 "
 | 
			
		||||
 | 
			
		||||
    local wget_options_extra=''
 | 
			
		||||
    local wget_result=''
 | 
			
		||||
 | 
			
		||||
    # Test for options that aren't supported on all wget implementations.
 | 
			
		||||
    if [[ $(wget -h 2>&1 | grep -E 'waitretry|connect-timeout') ]]; then
 | 
			
		||||
        wget_options_extra="--waitretry 2 --connect-timeout 15 "
 | 
			
		||||
    else
 | 
			
		||||
        say "wget extra options are unavailable for this environment"
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    if [ -z "$out_path" ]; then
 | 
			
		||||
        wget -q $wget_options $wget_options_extra -O - "$remote_path_with_credential" 2>&1
 | 
			
		||||
        wget_result=$?
 | 
			
		||||
@ -1042,24 +1254,16 @@ downloadwget() {
 | 
			
		||||
        wget_result=$?
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    if [[ $wget_result == 2 ]]; then
 | 
			
		||||
        # Parsing of the command has failed. Exclude potentially unrecognized options and retry.
 | 
			
		||||
        if [ -z "$out_path" ]; then
 | 
			
		||||
            wget -q $wget_options -O - "$remote_path_with_credential" 2>&1
 | 
			
		||||
            wget_result=$?
 | 
			
		||||
        else
 | 
			
		||||
            wget $wget_options -O "$out_path" "$remote_path_with_credential" 2>&1
 | 
			
		||||
            wget_result=$?
 | 
			
		||||
        fi
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    if [[ $wget_result != 0 ]]; then
 | 
			
		||||
        local disable_feed_credential=false
 | 
			
		||||
        local response=$(get_http_header_wget $remote_path $disable_feed_credential)
 | 
			
		||||
        http_code=$( echo "$response" | awk '/^  HTTP/{print $2}' | tail -1 )
 | 
			
		||||
        download_error_msg="Unable to download $remote_path."
 | 
			
		||||
        if  [[ $http_code != 2* ]]; then
 | 
			
		||||
        if  [[ ! -z $http_code && $http_code != 2* ]]; then
 | 
			
		||||
            download_error_msg+=" Returned HTTP status code: $http_code."
 | 
			
		||||
        # wget exit code 4 stands for network-issue
 | 
			
		||||
        elif [[ $wget_result == 4 ]]; then
 | 
			
		||||
            download_error_msg+=" Failed to reach the server: connection timeout."
 | 
			
		||||
        fi
 | 
			
		||||
        say_verbose "$download_error_msg"
 | 
			
		||||
        return 1
 | 
			
		||||
@ -1068,13 +1272,69 @@ downloadwget() {
 | 
			
		||||
    return 0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
extract_stem() {
 | 
			
		||||
    local url="$1"
 | 
			
		||||
    # extract the protocol
 | 
			
		||||
    proto="$(echo $1 | grep :// | sed -e's,^\(.*://\).*,\1,g')"
 | 
			
		||||
    # remove the protocol
 | 
			
		||||
    url="${1/$proto/}"
 | 
			
		||||
    # extract the path (if any) - since we know all of our feeds have a first path segment, we can skip the first one. otherwise we'd use -f2- to get the full path
 | 
			
		||||
    full_path="$(echo $url | grep / | cut -d/ -f2-)"
 | 
			
		||||
    path="$(echo $full_path | cut -d/ -f2-)"
 | 
			
		||||
    echo $path
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
check_url_exists() {
 | 
			
		||||
    eval $invocation
 | 
			
		||||
    local url="$1"
 | 
			
		||||
 | 
			
		||||
    local code=""
 | 
			
		||||
    if machine_has "curl"
 | 
			
		||||
    then
 | 
			
		||||
        code=$(curl --head -o /dev/null -w "%{http_code}" -s --fail "$url");
 | 
			
		||||
    elif machine_has "wget"
 | 
			
		||||
    then
 | 
			
		||||
        # get the http response, grab the status code
 | 
			
		||||
        server_response=$(wget -qO- --method=HEAD --server-response "$url" 2>&1)
 | 
			
		||||
        code=$(echo "$server_response" | grep "HTTP/" | awk '{print $2}')
 | 
			
		||||
    fi
 | 
			
		||||
    if [ $code = "200" ]; then
 | 
			
		||||
        return 0
 | 
			
		||||
    else
 | 
			
		||||
        return 1
 | 
			
		||||
    fi
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sanitize_redirect_url() {
 | 
			
		||||
    eval $invocation
 | 
			
		||||
 | 
			
		||||
    local url_stem
 | 
			
		||||
    url_stem=$(extract_stem "$1")
 | 
			
		||||
    say_verbose "Checking configured feeds for the asset at ${yellow:-}$url_stem${normal:-}"
 | 
			
		||||
 | 
			
		||||
    for feed in "${feeds[@]}"
 | 
			
		||||
    do
 | 
			
		||||
        local trial_url="$feed/$url_stem"
 | 
			
		||||
        say_verbose "Checking ${yellow:-}$trial_url${normal:-}"
 | 
			
		||||
        if check_url_exists "$trial_url"; then
 | 
			
		||||
            say_verbose "Found a match at ${yellow:-}$trial_url${normal:-}"
 | 
			
		||||
            echo "$trial_url"
 | 
			
		||||
            return 0
 | 
			
		||||
        else
 | 
			
		||||
            say_verbose "No match at ${yellow:-}$trial_url${normal:-}"
 | 
			
		||||
        fi
 | 
			
		||||
    done
 | 
			
		||||
    return 1
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
get_download_link_from_aka_ms() {
 | 
			
		||||
    eval $invocation
 | 
			
		||||
 | 
			
		||||
    #quality is not supported for LTS or current channel
 | 
			
		||||
    if [[ ! -z "$normalized_quality"  && ("$normalized_channel" == "LTS" || "$normalized_channel" == "current") ]]; then
 | 
			
		||||
    #quality is not supported for LTS or STS channel
 | 
			
		||||
    #STS maps to current
 | 
			
		||||
    if [[ ! -z "$normalized_quality"  && ("$normalized_channel" == "LTS" || "$normalized_channel" == "STS") ]]; then
 | 
			
		||||
        normalized_quality=""
 | 
			
		||||
        say_warning "Specifying quality for current or LTS channel is not supported, the quality will be ignored."
 | 
			
		||||
        say_warning "Specifying quality for STS or LTS channel is not supported, the quality will be ignored."
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    say_verbose "Retrieving primary payload URL from aka.ms for channel: '$normalized_channel', quality: '$normalized_quality', product: '$normalized_product', os: '$normalized_os', architecture: '$normalized_architecture'." 
 | 
			
		||||
@ -1103,6 +1363,12 @@ get_download_link_from_aka_ms() {
 | 
			
		||||
    http_codes=$( echo "$response" | awk '$1 ~ /^HTTP/ {print $2}' )
 | 
			
		||||
    # They all need to be 301, otherwise some links are broken (except for the last, which is not a redirect but 200 or 404).
 | 
			
		||||
    broken_redirects=$( echo "$http_codes" | sed '$d' | grep -v '301' )
 | 
			
		||||
    # The response may end without final code 2xx/4xx/5xx somehow, e.g. network restrictions on www.bing.com causes redirecting to bing.com fails with connection refused.
 | 
			
		||||
    # In this case it should not exclude the last.
 | 
			
		||||
    last_http_code=$(  echo "$http_codes" | tail -n 1 )
 | 
			
		||||
    if ! [[ $last_http_code =~ ^(2|4|5)[0-9][0-9]$ ]]; then
 | 
			
		||||
        broken_redirects=$( echo "$http_codes" | grep -v '301' )
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    # All HTTP codes are 301 (Moved Permanently), the redirect link exists.
 | 
			
		||||
    if [[ -z "$broken_redirects" ]]; then
 | 
			
		||||
@ -1113,6 +1379,11 @@ get_download_link_from_aka_ms() {
 | 
			
		||||
            return 1
 | 
			
		||||
        fi
 | 
			
		||||
 | 
			
		||||
        sanitized_redirect_url=$(sanitize_redirect_url "$aka_ms_download_link")
 | 
			
		||||
        if [[ -n "$sanitized_redirect_url" ]]; then
 | 
			
		||||
            aka_ms_download_link="$sanitized_redirect_url"
 | 
			
		||||
        fi
 | 
			
		||||
 | 
			
		||||
        say_verbose "The redirect location retrieved: '$aka_ms_download_link'."
 | 
			
		||||
        return 0
 | 
			
		||||
    else
 | 
			
		||||
@ -1124,7 +1395,9 @@ get_download_link_from_aka_ms() {
 | 
			
		||||
get_feeds_to_use()
 | 
			
		||||
{
 | 
			
		||||
    feeds=(
 | 
			
		||||
    "https://builds.dotnet.microsoft.com/dotnet"
 | 
			
		||||
    "https://dotnetcli.azureedge.net/dotnet"
 | 
			
		||||
    "https://ci.dot.net/public"
 | 
			
		||||
    "https://dotnetbuilds.azureedge.net/public"
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
@ -1182,6 +1455,11 @@ generate_akams_links() {
 | 
			
		||||
    local valid_aka_ms_link=true;
 | 
			
		||||
 | 
			
		||||
    normalized_version="$(to_lowercase "$version")"
 | 
			
		||||
    if [[ "$normalized_version" != "latest" ]] && [ -n "$normalized_quality" ]; then
 | 
			
		||||
        say_err "Quality and Version options are not allowed to be specified simultaneously. See https://learn.microsoft.com/dotnet/core/tools/dotnet-install-script#options for details."
 | 
			
		||||
        return 1
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    if [[ -n "$json_file" || "$normalized_version" != "latest" ]]; then
 | 
			
		||||
        # aka.ms links are not needed when exact version is specified via command or json file
 | 
			
		||||
        return
 | 
			
		||||
@ -1325,6 +1603,8 @@ calculate_vars() {
 | 
			
		||||
    install_root="$(resolve_installation_path "$install_dir")"
 | 
			
		||||
    say_verbose "InstallRoot: '$install_root'."
 | 
			
		||||
 | 
			
		||||
    normalized_architecture="$(get_normalized_architecture_for_specific_sdk_version "$version" "$normalized_channel" "$normalized_architecture")"
 | 
			
		||||
 | 
			
		||||
    if [[ "$runtime" == "dotnet" ]]; then
 | 
			
		||||
        asset_relative_path="shared/Microsoft.NETCore.App"
 | 
			
		||||
        asset_name=".NET Core Runtime"
 | 
			
		||||
@ -1343,10 +1623,11 @@ install_dotnet() {
 | 
			
		||||
    eval $invocation
 | 
			
		||||
    local download_failed=false
 | 
			
		||||
    local download_completed=false
 | 
			
		||||
    local remote_file_size=0
 | 
			
		||||
 | 
			
		||||
    mkdir -p "$install_root"
 | 
			
		||||
    zip_path="$(mktemp "$temporary_file_template")"
 | 
			
		||||
    say_verbose "Zip path: $zip_path"
 | 
			
		||||
    zip_path="${zip_path:-$(mktemp "$temporary_file_template")}"
 | 
			
		||||
    say_verbose "Archive path: $zip_path"
 | 
			
		||||
 | 
			
		||||
    for link_index in "${!download_links[@]}"
 | 
			
		||||
    do
 | 
			
		||||
@ -1370,7 +1651,7 @@ install_dotnet() {
 | 
			
		||||
                say "Failed to download $link_type link '$download_link': $download_error_msg"
 | 
			
		||||
                ;;
 | 
			
		||||
            esac
 | 
			
		||||
            rm -f "$zip_path" 2>&1 && say_verbose "Temporary zip file $zip_path was removed"
 | 
			
		||||
            rm -f "$zip_path" 2>&1 && say_verbose "Temporary archive file $zip_path was removed"
 | 
			
		||||
        else
 | 
			
		||||
            download_completed=true
 | 
			
		||||
            break
 | 
			
		||||
@ -1383,8 +1664,10 @@ install_dotnet() {
 | 
			
		||||
        return 1
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    say "Extracting zip from $download_link"
 | 
			
		||||
    extract_dotnet_package "$zip_path" "$install_root" || return 1
 | 
			
		||||
    remote_file_size="$(get_remote_file_size "$download_link")"
 | 
			
		||||
 | 
			
		||||
    say "Extracting archive from $download_link"
 | 
			
		||||
    extract_dotnet_package "$zip_path" "$install_root" "$remote_file_size" || return 1
 | 
			
		||||
 | 
			
		||||
    #  Check if the SDK version is installed; if not, fail the installation.
 | 
			
		||||
    # if the version contains "RTM" or "servicing"; check if a 'release-type' SDK version is installed.
 | 
			
		||||
@ -1395,6 +1678,7 @@ install_dotnet() {
 | 
			
		||||
        unset IFS;
 | 
			
		||||
        say_verbose "Checking installation: version = $release_version"
 | 
			
		||||
        if is_dotnet_package_installed "$install_root" "$asset_relative_path" "$release_version"; then
 | 
			
		||||
            say "Installed version is $effective_version"
 | 
			
		||||
            return 0
 | 
			
		||||
        fi
 | 
			
		||||
    fi
 | 
			
		||||
@ -1402,6 +1686,7 @@ install_dotnet() {
 | 
			
		||||
    #  Check if the standard SDK version is installed.
 | 
			
		||||
    say_verbose "Checking installation: version = $effective_version"
 | 
			
		||||
    if is_dotnet_package_installed "$install_root" "$asset_relative_path" "$effective_version"; then
 | 
			
		||||
        say "Installed version is $effective_version"
 | 
			
		||||
        return 0
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
@ -1532,36 +1817,53 @@ do
 | 
			
		||||
            override_non_versioned_files=false
 | 
			
		||||
            non_dynamic_parameters+=" $name"
 | 
			
		||||
            ;;
 | 
			
		||||
        --keep-zip|-[Kk]eep[Zz]ip)
 | 
			
		||||
            keep_zip=true
 | 
			
		||||
            non_dynamic_parameters+=" $name"
 | 
			
		||||
            ;;
 | 
			
		||||
        --zip-path|-[Zz]ip[Pp]ath)
 | 
			
		||||
            shift
 | 
			
		||||
            zip_path="$1"
 | 
			
		||||
            ;;
 | 
			
		||||
        -?|--?|-h|--help|-[Hh]elp)
 | 
			
		||||
            script_name="$(basename "$0")"
 | 
			
		||||
            script_name="dotnet-install.sh"
 | 
			
		||||
            echo ".NET Tools Installer"
 | 
			
		||||
            echo "Usage: $script_name [-c|--channel <CHANNEL>] [-v|--version <VERSION>] [-p|--prefix <DESTINATION>]"
 | 
			
		||||
            echo "Usage:"
 | 
			
		||||
            echo "       # Install a .NET SDK of a given Quality from a given Channel"
 | 
			
		||||
            echo "       $script_name [-c|--channel <CHANNEL>] [-q|--quality <QUALITY>]"
 | 
			
		||||
            echo "       # Install a .NET SDK of a specific public version"
 | 
			
		||||
            echo "       $script_name [-v|--version <VERSION>]"
 | 
			
		||||
            echo "       $script_name -h|-?|--help"
 | 
			
		||||
            echo ""
 | 
			
		||||
            echo "$script_name is a simple command line interface for obtaining dotnet cli."
 | 
			
		||||
            echo "    Note that the intended use of this script is for Continuous Integration (CI) scenarios, where:"
 | 
			
		||||
            echo "    - The SDK needs to be installed without user interaction and without admin rights."
 | 
			
		||||
            echo "    - The SDK installation doesn't need to persist across multiple CI runs."
 | 
			
		||||
            echo "    To set up a development environment or to run apps, use installers rather than this script. Visit https://dotnet.microsoft.com/download to get the installer."
 | 
			
		||||
            echo ""
 | 
			
		||||
            echo "Options:"
 | 
			
		||||
            echo "  -c,--channel <CHANNEL>         Download from the channel specified, Defaults to \`$channel\`."
 | 
			
		||||
            echo "      -Channel"
 | 
			
		||||
            echo "          Possible values:"
 | 
			
		||||
            echo "          - Current - most current release"
 | 
			
		||||
            echo "          - LTS - most current supported release"
 | 
			
		||||
            echo "          - STS - the most recent Standard Term Support release"
 | 
			
		||||
            echo "          - LTS - the most recent Long Term Support release"
 | 
			
		||||
            echo "          - 2-part version in a format A.B - represents a specific release"
 | 
			
		||||
            echo "              examples: 2.0; 1.0"
 | 
			
		||||
            echo "          - 3-part version in a format A.B.Cxx - represents a specific SDK release"
 | 
			
		||||
            echo "              examples: 5.0.1xx, 5.0.2xx."
 | 
			
		||||
            echo "              Supported since 5.0 release"
 | 
			
		||||
            echo "          Warning: Value 'Current' is deprecated for the Channel parameter. Use 'STS' instead."
 | 
			
		||||
            echo "          Note: The version parameter overrides the channel parameter when any version other than 'latest' is used."
 | 
			
		||||
            echo "  -v,--version <VERSION>         Use specific VERSION, Defaults to \`$version\`."
 | 
			
		||||
            echo "      -Version"
 | 
			
		||||
            echo "          Possible values:"
 | 
			
		||||
            echo "          - latest - most latest build on specific channel"
 | 
			
		||||
            echo "          - latest - the latest build on specific channel"
 | 
			
		||||
            echo "          - 3-part version in a format A.B.C - represents specific version of build"
 | 
			
		||||
            echo "              examples: 2.0.0-preview2-006120; 1.1.0"
 | 
			
		||||
            echo "  -q,--quality <quality>         Download the latest build of specified quality in the channel."
 | 
			
		||||
            echo "      -Quality"
 | 
			
		||||
            echo "          The possible values are: daily, signed, validated, preview, GA."
 | 
			
		||||
            echo "          Works only in combination with channel. Not applicable for current and LTS channels and will be ignored if those channels are used." 
 | 
			
		||||
            echo "          Works only in combination with channel. Not applicable for STS and LTS channels and will be ignored if those channels are used." 
 | 
			
		||||
            echo "          For SDK use channel in A.B.Cxx format. Using quality for SDK together with channel in A.B format is not supported." 
 | 
			
		||||
            echo "          Supported since 5.0 release." 
 | 
			
		||||
            echo "          Note: The version parameter overrides the channel parameter when any version other than 'latest' is used, and therefore overrides the quality."
 | 
			
		||||
@ -1572,7 +1874,7 @@ do
 | 
			
		||||
            echo "      -InstallDir"
 | 
			
		||||
            echo "  --architecture <ARCHITECTURE>      Architecture of dotnet binaries to be installed, Defaults to \`$architecture\`."
 | 
			
		||||
            echo "      --arch,-Architecture,-Arch"
 | 
			
		||||
            echo "          Possible values: x64, arm, and arm64"
 | 
			
		||||
            echo "          Possible values: x64, arm, arm64, s390x, ppc64le and loongarch64"
 | 
			
		||||
            echo "  --os <system>                    Specifies operating system to be used when selecting the installer."
 | 
			
		||||
            echo "          Overrides the OS determination approach used by the script. Supported values: osx, linux, linux-musl, freebsd, rhel.6."
 | 
			
		||||
            echo "          In case any other value is provided, the platform will be determined by the script based on machine configuration."
 | 
			
		||||
@ -1597,6 +1899,8 @@ do
 | 
			
		||||
            echo "  --no-cdn,-NoCdn                    Disable downloading from the Azure CDN, and use the uncached feed directly."
 | 
			
		||||
            echo "  --jsonfile <JSONFILE>              Determines the SDK version from a user specified global.json file."
 | 
			
		||||
            echo "                                     Note: global.json must have a value for 'SDK:Version'"
 | 
			
		||||
            echo "  --keep-zip,-KeepZip                If set, downloaded file is kept."
 | 
			
		||||
            echo "  --zip-path, -ZipPath               If set, downloaded file is stored at the specified path."
 | 
			
		||||
            echo "  -?,--?,-h,--help,-Help             Shows this help message"
 | 
			
		||||
            echo ""
 | 
			
		||||
            echo "Install Location:"
 | 
			
		||||
@ -1615,10 +1919,10 @@ do
 | 
			
		||||
    shift
 | 
			
		||||
done
 | 
			
		||||
 | 
			
		||||
say "Note that the intended use of this script is for Continuous Integration (CI) scenarios, where:"
 | 
			
		||||
say "- The SDK needs to be installed without user interaction and without admin rights."
 | 
			
		||||
say "- The SDK installation doesn't need to persist across multiple CI runs."
 | 
			
		||||
say "To set up a development environment or to run apps, use installers rather than this script. Visit https://dotnet.microsoft.com/download to get the installer.\n"
 | 
			
		||||
say_verbose "Note that the intended use of this script is for Continuous Integration (CI) scenarios, where:"
 | 
			
		||||
say_verbose "- The SDK needs to be installed without user interaction and without admin rights."
 | 
			
		||||
say_verbose "- The SDK installation doesn't need to persist across multiple CI runs."
 | 
			
		||||
say_verbose "To set up a development environment or to run apps, use installers rather than this script. Visit https://dotnet.microsoft.com/download to get the installer.\n"
 | 
			
		||||
 | 
			
		||||
if [ "$internal" = true ] && [ -z "$(echo $feed_credential)" ]; then
 | 
			
		||||
    message="Provide credentials via --feed-credential parameter."
 | 
			
		||||
@ -1651,5 +1955,5 @@ else
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
say "Note that the script does not resolve dependencies during installation."
 | 
			
		||||
say "To check the list of dependencies, go to https://docs.microsoft.com/dotnet/core/install, select your operating system and check the \"Dependencies\" section."
 | 
			
		||||
say "To check the list of dependencies, go to https://learn.microsoft.com/dotnet/core/install, select your operating system and check the \"Dependencies\" section."
 | 
			
		||||
say "Installation finished successfully."
 | 
			
		||||
		Reference in New Issue
	
	Block a user