Private/DownloadNuGetPackage.ps1
<#
.SYNOPSIS The DownloadNuGetPackage function download and unzips the specified NuGetPackage using the v3 NuGet API. It also indicated which assembly file (.dll) you should probably use for the PowerShell version (Windows or Core) you are using. .DESCRIPTION See .SYNOPSIS .PARAMETER AssemblyName This parameter is MANDATORY. TODO .PARAMETER NuGetPkgDownloadDirectory This parameter is OPTIONAL. TODO .PARAMETER AllowPreRelease This parameter is OPTIONAL. TODO .PARAMETER Silent This parameter is OPTIONAL. TODO .EXAMPLE # Open an elevated PowerShell Session, import the module, and - PS C:\Users\zeroadmin> DownloadNuGetPackage -AssemblyName Newtonsoft.Json -NuGetPkgDownloadDirectory "$HOME\Downloads" -Silent #> function DownloadNuGetPackage { [CmdletBinding()] Param( [Parameter(Mandatory=$True)] [string]$AssemblyName, [Parameter(Mandatory=$False)] [string]$NuGetPkgDownloadDirectory, [Parameter(Mandatory=$False)] [switch]$AllowPreRelease, [Parameter(Mandatory=$False)] [switch]$Silent ) ##### BEGIN Helper Native Functions ##### function Get-NativePath { [CmdletBinding()] Param( [Parameter(Mandatory=$True)] [string[]]$PathAsStringArray ) $PathAsStringArray = foreach ($pathPart in $PathAsStringArray) { $SplitAttempt = $pathPart -split [regex]::Escape([IO.Path]::DirectorySeparatorChar) if ($SplitAttempt.Count -gt 1) { foreach ($obj in $SplitAttempt) { $obj } } else { $pathPart } } $PathAsStringArray = $PathAsStringArray -join [IO.Path]::DirectorySeparatorChar $PathAsStringArray } ##### END Helper Native Functions ##### ##### BEGIN Parameter Validation ##### if ($PSVersionTable.Platform -ne $null -and $PSVersionTable.Platform -ne "Win32NT" -and !$NuGetPkgDownloadDirectory) { Write-Error "On this OS Platform (i.e. $($PSVersionTable.Platform)), the -NuGetPkgDownloadDirectory parameter is required! Halting!" $global:FunctionResult = "1" return } <# if ($PSVersionTable.PSEdition -eq "Desktop" -and $NuGetPkgDownloadDirectory) { Write-Error "The -NuGetPkgDownloadPath parameter is only meant to be used with PowerShell Core! Halting!" $global:FunctionResult = "1" return } #> ##### END Parameter Validation ##### ##### BEGIN Variable/Parameter Transforms and PreRun Prep ##### $s = [IO.Path]::DirectorySeparatorChar if ($($PSVersionTable.Platform -ne $null -and $PSVersionTable.Platform -ne "Win32NT") -or $NuGetPkgDownloadDirectory) { #$NuGetPackageUri = "https://www.nuget.org/api/v2/package/$AssemblyName" #$NuGetPackageUri = "https://api.nuget.org/v3-flatcontainer/{id-lower}/{version-lower}/{id-lower}.{version-lower}.nupkg" if ($AllowPreRelease) { $SearchNuGetPackageUri = "https://api-v2v3search-0.nuget.org/query?q=$AssemblyName&prerelease=true" } else { $SearchNuGetPackageUri = "https://api-v2v3search-0.nuget.org/query?q=$AssemblyName&prerelease=false" } $VersionCheckPrep = $($(Invoke-RestMethod -Uri $SearchNuGetPackageUri).data | Where-Object {$_.id -eq $AssemblyName}).versions $LatestVersion = $VersionCheckPrep[-1].Version $LowercaseAssemblyName = $AssemblyName.ToLowerInvariant() $NuGetPackageUri = "https://api.nuget.org/v3-flatcontainer/$LowercaseAssemblyName/$LatestVersion/$LowercaseAssemblyName.$LatestVersion.nupkg" $OutFileBaseName = "$LowercaseAssemblyName.$LatestVersion.zip" $DllFileName = $OutFileBaseName -replace "zip","dll" if ($NuGetPkgDownloadDirectory) { $NuGetPkgDownloadPath = Join-Path $NuGetPkgDownloadDirectory $OutFileBaseName $NuGetPkgExtractionDirectory = Join-Path $NuGetPkgDownloadDirectory $AssemblyName if (!$(Test-Path $NuGetPkgDownloadDirectory)) { $null = New-Item -ItemType Directory -Path $NuGetPkgDownloadDirectory -Force } if (!$(Test-Path $NuGetPkgExtractionDirectory)) { $null = New-Item -ItemType Directory -Path $NuGetPkgExtractionDirectory -Force } } <# $TestPath = $NuGetPkgDownloadDirectory $BrokenDir = while (-not (Test-Path $TestPath)) { $CurrentPath = $TestPath $TestPath = Split-Path $TestPath if (Test-Path $TestPath) {$CurrentPath} } if ([String]::IsNullOrWhitespace([System.IO.Path]::GetExtension($NuGetPkgDownloadDirectory))) { # Assume it's a directory if ($BrokenDir) { if ($BrokenDir -eq $NuGetPkgDownloadDirectory) { $null = New-Item -ItemType Directory -Path $BrokenDir -Force } else { Write-Error "The path $TestPath was not found! Halting!" $global:FunctionResult = "1" return } $NuGetPkgDownloadPath = Get-NativePath @($BrokenDir, $OutFileBaseName) } else { if ($(Get-ChildItem $NuGetPkgDownloadDirectory).Count -ne 0) { $NewDir = Get-NativePath @($NuGetPkgDownloadDirectory, [System.IO.Path]::GetFileNameWithoutExtension($OutFileBaseName)) $null = New-Item -ItemType Directory -Path $NewDir -Force } $NuGetPkgDownloadPath = Get-NativePath @($NewDir, $OutFileBaseName) } } else { # Assume it's a file $OutFileBaseName = $NuGetPkgDownloadDirectory | Split-Path -Leaf $extension = [System.IO.Path]::GetExtension($OutFileBaseName) if ($extension -ne ".zip") { $OutFileBaseName = $OutFileBaseName -replace "$extension",".zip" } if ($BrokenDir) { Write-Host "BrokenDir is $BrokenDir" if ($BrokenDir -eq $($NuGetPkgDownloadDirectory | Split-Path -Parent)) { $null = New-Item -ItemType Directory -Path $BrokenDir -Force } else { Write-Error "The path $TestPath was not found! Halting!" $global:FunctionResult = "1" return } $NuGetPkgDownloadPath = Get-NativePath @($BrokenDir, $OutFileBaseName) } else { if ($(Get-ChildItem $($NuGetPkgDownloadDirectory | Split-Path -Parent)).Count -ne 0) { $NewDir = Get-NativePath @($($NuGetPkgDownloadDirectory | Split-Path -Parent), [System.IO.Path]::GetFileNameWithoutExtension($OutFileBaseName)) $null = New-Item -ItemType Directory -Path $NewDir -Force } $NuGetPkgDownloadPath = Get-NativePath @($NewDir, $OutFileBaseName) } } #> #$NuGetPkgExtractionDirectory = $NuGetPkgDownloadPath | Split-Path -Parent } if ($($PSVersionTable.PSEdition -eq "Desktop" -or $PSVersionTable.Platform -eq "Win32NT") -and !$NuGetPkgDownloadDirectory) { $NuGetConfigContent = Get-Content $(Get-NativePath @($env:AppData, "NuGet", "nuget.config")) $NuGetRepoPathCheck = $NuGetConfigContent | Select-String -Pattern '<add key="repositoryPath" value=' -ErrorAction SilentlyContinue if ($NuGetRepoPathCheck -ne $null) { $NuGetPackagesPath = $($($NuGetRepoPathCheck.Line.Trim() -split 'value=')[-1] -split ' ')[0] -replace '"','' } else { $NuGetPackagesPath = Get-NativePath @($HOME, ".nuget", "packages") } if (!$(Test-Path $NuGetPackagesPath)) { $null = New-Item -ItemType Directory -Path $NuGetPackagesPath -Force } $NuGetPkgExtractionDirectory = Get-NativePath @($NuGetPackagesPath, $AssemblyName) } if ($PSVersionTable.PSEdition -eq "Core") { $PossibleSubDirs = @( [pscustomobject]@{ Preference = 3 SubDirectory = $(Get-NativePath @("lib", "netstandard1.3")) } [pscustomobject]@{ Preference = 3 SubDirectory = $(Get-NativePath @("lib", "netstandard1.6")) } [pscustomobject]@{ Preference = 1 SubDirectory = $(Get-NativePath @("lib", "netstandard2.0")) } [pscustomobject]@{ Preference = 2 SubDirectory = $(Get-NativePath @("lib", "netcoreapp2.0")) } ) } else { $PossibleSubDirs = @( [pscustomobject]@{ Preference = 8 SubDirectory = $(Get-NativePath @("lib", "net40")) } [pscustomobject]@{ Preference = 7 SubDirectory = $(Get-NativePath @("lib", "net45")) } [pscustomobject]@{ Preference = 6 SubDirectory = $(Get-NativePath @("lib", "net451")) } [pscustomobject]@{ Preference = 5 SubDirectory = $(Get-NativePath @("lib", "net46")) } [pscustomobject]@{ Preference = 4 SubDirectory = $(Get-NativePath @("lib", "net461")) } [pscustomobject]@{ Preference = 3 SubDirectory = $(Get-NativePath @("lib", "net462")) } [pscustomobject]@{ Preference = 2 SubDirectory = $(Get-NativePath @("lib", "net47")) } [pscustomobject]@{ Preference = 1 SubDirectory = $(Get-NativePath @("lib", "net471")) } [pscustomobject]@{ Preference = 15 SubDirectory = $(Get-NativePath @("lib", "netstandard1.0")) } [pscustomobject]@{ Preference = 14 SubDirectory = $(Get-NativePath @("lib", "netstandard1.1")) } [pscustomobject]@{ Preference = 13 SubDirectory = $(Get-NativePath @("lib", "netstandard1.2")) } [pscustomobject]@{ Preference = 12 SubDirectory = $(Get-NativePath @("lib", "netstandard1.3")) } [pscustomobject]@{ Preference = 11 SubDirectory = $(Get-NativePath @("lib", "netstandard1.4")) } [pscustomobject]@{ Preference = 10 SubDirectory = $(Get-NativePath @("lib", "netstandard1.5")) } [pscustomobject]@{ Preference = 9 SubDirectory = $(Get-NativePath @("lib", "netstandard1.6")) } [pscustomobject]@{ Preference = 16 SubDirectory = $(Get-NativePath @("lib", "netstandard2.0")) } [pscustomobject]@{ Preference = 17 SubDirectory = $(Get-NativePath @("lib", "netcoreapp2.0")) } ) } ##### END Variable/Parameter Transforms and PreRun Prep ##### ##### BEGIN Main Body ##### if ($($PSVersionTable.PSEdition -eq "Desktop" -or $PSVersionTable.Platform -eq "Win32NT") -and !$NuGetPkgDownloadDirectory) { #$null = Update-PackageManagement -InstallNuGetCmdLine if (!$(Get-Command nuget.exe -ErrorAction SilentlyContinue)) { $NugetPath = Join-Path $($NuGetPackagesPath | Split-Path -Parent) nuget.exe if(!$(Test-Path $NugetPath)) { Invoke-WebRequest -uri 'https://dist.nuget.org/win-x86-commandline/latest/nuget.exe' -OutFile $NugetPath } $NugetDir = $NugetPath | Split-Path -Parent # Update PowerShell $env:Path [System.Collections.Arraylist][array]$CurrentEnvPathArray = $env:Path -split ';' | Where-Object {![System.String]::IsNullOrWhiteSpace($_)} | Sort-Object | Get-Unique if ($CurrentEnvPathArray -notcontains $NugetDir) { $CurrentEnvPathArray.Insert(0,$NugetDir) $env:Path = $CurrentEnvPathArray -join ';' } # Update SYSTEM Path $RegistrySystemPath = 'HKLM:\System\CurrentControlSet\Control\Session Manager\Environment' $CurrentSystemPath = $(Get-ItemProperty -Path $RegistrySystemPath -Name PATH).Path [System.Collections.Arraylist][array]$CurrentSystemPathArray = $CurrentSystemPath -split ';' | Where-Object {![System.String]::IsNullOrWhiteSpace($_)} | Sort-Object | Get-Unique if ($CurrentSystemPathArray -notcontains $NugetDir) { $CurrentSystemPathArray.Insert(0,$NugetDir) $UpdatedSystemPath = $CurrentSystemPathArray -join ';' Set-ItemProperty -Path $RegistrySystemPath -Name PATH -Value $UpdatedSystemPath } } try { $ProcessInfo = New-Object System.Diagnostics.ProcessStartInfo #$ProcessInfo.WorkingDirectory = $NuGetPackagesPath $ProcessInfo.FileName = $(Get-Command nuget).Source $ProcessInfo.RedirectStandardError = $true $ProcessInfo.RedirectStandardOutput = $true $ProcessInfo.UseShellExecute = $false if ($AllowPreRelease) { $ProcessInfo.Arguments = "install $AssemblyName -PreRelease" } else { $ProcessInfo.Arguments = "install $AssemblyName" } $Process = New-Object System.Diagnostics.Process $Process.StartInfo = $ProcessInfo $Process.Start() | Out-Null $stdout = $($Process.StandardOutput.ReadToEnd()).Trim() $stderr = $($Process.StandardError.ReadToEnd()).Trim() $AllOutput = $stdout + $stderr $AllOutput = $AllOutput -split "`n" if ($stderr -match "Unable to find package") { throw } $NuGetPkgExtractionDirectory = $(Get-ChildItem -Path $NuGetPackagesPath -Directory | Where-Object {$_.Name -eq $AssemblyName} | Sort-Object -Property CreationTime)[-1].FullName } catch { Write-Error $_ Write-Error "NuGet.exe was unable to find a package called $AssemblyName! Halting!" $global:FunctionResult = "1" return } } if ($($PSVersionTable.Platform -ne $null -and $PSVersionTable.Platform -ne "Win32NT") -or $NuGetPkgDownloadDirectory) { try { # Download the NuGet Package if (!$Silent) { Write-Host "Downloading $AssemblyName NuGet Package to $NuGetPkgDownloadPath ..." } Invoke-WebRequest -Uri $NuGetPackageUri -OutFile $NuGetPkgDownloadPath if (!$Silent) { Write-Host "NuGet Package has been downloaded to $NuGetPkgDownloadPath" } } catch { Write-Error "Unable to find $AssemblyName via the NuGet API! Halting!" $global:FunctionResult = "1" return } # Step through possble Zip File SubDirs and get the most highest available compatible version of the Assembly try { if (!$Silent) { Write-Host "Attempting to extract NuGet zip file $NuGetPkgDownloadPath to $NuGetPkgExtractionDirectory ..." } if ($(Get-ChildItem $NuGetPkgExtractionDirectory).Count -gt 1) { foreach ($item in $(Get-ChildItem $NuGetPkgExtractionDirectory)) { if ($item.Extension -ne ".zip") { $item | Remove-Item -Recurse -Force } } } Expand-Archive -Path $NuGetPkgDownloadPath -DestinationPath $NuGetPkgExtractionDirectory #Unzip-File -PathToZip $NuGetPkgDownloadPath -TargetDir $NuGetPkgExtractionDirectory if (!$Silent) { Write-Host "NuGet Package is available here: $NuGetPkgExtractionDirectory" } } catch { Write-Warning "The Unzip-File function failed with the following error:" Write-Error $$_ $global:FunctionResult = "1" return } } [System.Collections.ArrayList]$NuGetPackageActualSubDirs = @() $(Get-ChildItem -Recurse $NuGetPkgExtractionDirectory -File -Filter "*.dll").DirectoryName | foreach { $null = $NuGetPackageActualSubDirs.Add($_) } [System.Collections.ArrayList]$FoundSubDirsPSObjects = @() foreach ($pdir in $PossibleSubDirs) { foreach ($adir in $NuGetPackageActualSubDirs) { $IndexOfSlash = $pdir.SubDirectory.IndexOf($s) $pdirToRegexPattern = { $UpdatedString = $pdir.SubDirectory.Remove($IndexOfSlash, 1) $UpdatedString.Insert($IndexOfSlash, [regex]::Escape($s)) }.Invoke() if ($adir -match $pdirToRegexPattern) { $FoundDirPSObj = [pscustomobject]@{ Preference = $pdir.Preference Directory = $adir } $null = $FoundSubDirsPSObjects.Add($FoundDirPSObj) } } } $TargetDir = $($FoundSubDirsPSObjects | Sort-Object -Property Preference)[0].Directory $AssemblyPath = Get-NativePath @($TargetDir, $(Get-ChildItem $TargetDir -File -Filter "*.dll").Name) [pscustomobject]@{ NuGetPackageDirectory = $NuGetPkgExtractionDirectory AssemblyToLoad = $AssemblyPath } <# $CurrentLoadedAssemblies = [System.AppDomain]::CurrentDomain.GetAssemblies() $CheckAssemblyIsLoaded = $CurrentLoadedAssemblies | Where-Object {$_.FullName -like "$AssemblyName*"} if ($CheckAssemblyIsLoaded -eq $null) { Add-Type -Path $AssemblyPath } else { Write-Warning "The Assembly $AssemblyName is already loaded!" } #> ##### END Main Body ##### } |