internal/functions/Install-NugetPackage.ps1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
function Install-NugetPackage {
    # This function acts similarly to Install-Package -SkipDependencies and downloads nuget packages from nuget.org
    [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = 'High')]
    Param (
        [string]$Name,
        [string]$MinimumVersion,
        [string]$RequiredVersion,
        [string]$MaximumVersion,
        [switch]$SkipPreRelease,
        [ValidateSet('CurrentUser', 'AllUsers')]
        [string]$Scope = 'AllUsers',
        [switch]$Force,
        [string]$Api = 'https://api.nuget.org/v3'
    )
    $packageLowerName = $Name.ToLower()
    $Api = $Api.TrimEnd('/')
    # Get API endpoint URLs
    $index = Invoke-WebRequest "$Api/index.json" -ErrorAction Stop
    $indexObject = $index.Content | ConvertFrom-Json

    # search for package
    $searchUrl = $indexObject.resources | Where-Object { $_.'@type' -eq 'SearchQueryService' } | Select-Object -First 1
    $query = "?q=PackageId:{0}&prerelease={1}" -f $Name, (-Not $SkipPreRelease).ToString().ToLower()
    $packageInfoResponse = Invoke-WebRequest -Uri "$($searchUrl.'@id')$query" -ErrorAction Stop
    $packageInfoObject = $packageInfoResponse.Content | ConvertFrom-Json
    $packageInfo = $packageInfoObject.data | Select-Object -First 1
    if (-Not $packageInfo) {
        Stop-PSFFunction -Message "Package $Name was not found"
    }
    $packageName = $packageInfo.id
    $packageLowerName = $packageName.ToLower()
    if ($RequiredVersion) {
        $versionList = @($RequiredVersion)
        Write-PSFMessage -Level Verbose -Message "Using RequiredVersion $RequiredVersion of $packageName"
    }
    else {
        [array]$versionList = $packageInfo.versions.version
        Write-PSFMessage -Level Verbose -Message "Found a total of $($versionList.Count) versions of $packageName"

        # filter out the versions we don't need based on parameters
        if ($versionList -and $MinimumVersion) {
            $position = $versionList.IndexOf($MinimumVersion)
            if ($position -eq -1) {
                $versionList = $versionList | Where-Object { try { [version]$_ -ge $MinimumVersion } catch { $false } }
            }
            else {
                $versionList = $versionList[$position..($versionList.Count - 1)]
            }
        }
        if ($versionList -and $MaximumVersion) {
            $position = $versionList.IndexOf($MaximumVersion)
            if ($position -eq -1) {
                $versionList = $versionList | Where-Object { try { [version]$_ -le $MaximumVersion } catch { $false } }
            }
            else {
                $versionList = $versionList[0..$position]
            }
        }
        Write-PSFMessage -Level Verbose -Message "$($versionList.Count) versions left after applying filters"
    }

    $selectedVersion = $versionList | Select-Object -Last 1
    if (-Not $selectedVersion) {
        Stop-PSFFunction -Message "Version could not be found using current parameters" -EnableException $true
    }

    # download and extract the files
    Write-PSFMessage -Level Verbose -Message "Version $selectedVersion of $packageName was selected"
    $fileName = "$packageName.$selectedVersion.nupkg"
    # Path reference: https://github.com/OneGet/oneget/blob/master/src/Microsoft.PackageManagement/Utility/Platform/OSInformation.cs
    $scopePath = switch ($Scope) {
        'AllUsers' {
            switch ($IsWindows) {
                $false { "/usr/local/share/PackageManagement/NuGet/Packages" }
                default { Join-PSFPath $env:ProgramFiles "PackageManagement\NuGet\packages" }
            }
        }
        'CurrentUser' {
            switch ($IsWindows) {
                $false { Join-PSFPath $env:HOME ".local/share/PackageManagement/NuGet/Packages" }
                default { Join-PSFPath $env:LOCALAPPDATA "PackageManagement\NuGet\packages" }
            }
        }
    }
    $path = Join-PSFPath $scopePath "$packageName.$selectedVersion"
    $packagePath = Join-PSFPath $path $fileName
    if ($PSCmdlet.ShouldProcess($fileName, "Download package")) {
        if (Test-Path $path) {
            if ($Force) {
                Remove-Item $path -Recurse -Force
            }
            else {
                Write-PSFMessage -Level Critical -Message "$packageName.$selectedVersion already exists at destination" -EnableException $true
            }
        }
        $folder = New-Item -ItemType Directory -Path $path -Force

        $baseAddressUrl = $indexObject.resources | Where-Object { $_.'@type' -eq 'PackageBaseAddress/3.0.0' } | Select-Object -First 1
        $downloadUrl = "$($baseAddressUrl.'@id')$packageLowerName/$selectedVersion/$fileName"
        Invoke-WebRequest -Uri $downloadUrl -OutFile $packagePath -ErrorAction Stop
        Write-PSFMessage -Level Verbose -Message "Extracting $fileName to $folder"
        if ($isCoreCLR) {
            [System.IO.Compression.ZipFile]::ExtractToDirectory($packagePath, $folder, $true)
        }
        else {
            [System.IO.Compression.ZipFile]::ExtractToDirectory($packagePath, $folder)
        }

        #return output
        [PSCustomObject]@{
            Name    = $packageName
            Source  = $packagePath
            Version = $selectedVersion
            Uri     = $downloadUrl
        } | Select-Object *
    }
}