Skip to content

Instantly share code, notes, and snippets.

@Jaykul
Last active March 21, 2025 14:48
Show Gist options
  • Select an option

  • Save Jaykul/bfb9cad99a3c067ba807 to your computer and use it in GitHub Desktop.

Select an option

Save Jaykul/bfb9cad99a3c067ba807 to your computer and use it in GitHub Desktop.
(Install and) load the assemblies from a NuGet package into PowerShell
#requires -Module PackageManagement
using namespace NuGet
[CmdletBinding(DefaultParameterSetName = 'MaybeUseExisting')]
param(
[Parameter(Mandatory, Position = 0)]
[String]$Name,
[String]$Destination = "$(Split-Path $Profile)\Libraries",
[switch]$ForceReinstall,
[switch]$AllowPrerelease,
[string]$Version
)
$ErrorActionPreference = "Stop"
if (!(Test-Path $Destination -Type Container)) {
throw "The destination path ($Destination) must point to an existing folder, NuGet will install packages in subdirectories of this folder."
}
if ((Get-Command nuget.exe -ErrorAction Ignore).Version -lt "6.0") {
# Install-WebBinary is in Install-GithubRelease (which I should make into a module, but later)
. Install-GithubRelease.ps1 Jaykul WebBinary
Install-WebBinary https://dist.nuget.org/win-x86-commandline/latest/nuget.exe nuget.exe
}
Add-Type -AssemblyName (Get-Command nuget).Path
$PackagePath = if (Test-Path "$Destination\$Name") {
Convert-Path "$Destination\$Name"
} elseif (Test-Path "$Destination\$Name*") {
Convert-Path "$Destination\$Name*" |
Sort-Object { [SemanticVersion]($_ -replace ".*?\.([\d\.]+(-.*)?)$", '$1') } -Descending |
Select-Object -First 1
}
if ($ForceReinstall -or -not $PackagePath){
$null = $PSBoundParameters.Remove("ForceReinstall")
$PSBoundParameters['Destination'] = $Destination
# Normalize: nuget requires destination NOT end with a slash
$Destination = (Convert-Path $Destination).TrimEnd("\")
if ($Version -and $AllowPrerelease) {
nuget install $Name -OutputDirectory $Destination -Version $Version -Prerelease
} elseif ($AllowPrerelease) {
nuget install $Name -OutputDirectory $Destination -Prerelease
} elseif ($Version) {
nuget install $Name -OutputDirectory $Destination -Version $Version
} else {
nuget install $Name -OutputDirectory $Destination
}
$PackagePath = if (Test-Path "$Destination\$Name") {
Convert-Path "$Destination\$Name"
} elseif (Test-Path "$Destination\$Name*") {
Convert-Path "$Destination\$Name*" |
Sort-Object { [SemanticVersion]($_ -replace ".*?\.([\d\.]+)$", '$1') } -Descending |
Select-Object -First 1
} else {
$Package | Out-Default
Write-Error "Could not find package after install of Package!"
}
Write-Verbose "Installed $Name to $PackagePath"
} else {
Write-Verbose "Found $Name at $PackagePath"
}
# Nuget packages hide their assemblies in folders with version numbers...
$Versions = @()
if ($PSVersionTable.PSVersion -ge "7.4") {
$Versions += @("net8.0")
}
if ($PSVersionTable.PSVersion -ge "7.3") {
$Versions += @("net7.0")
}
if ($PSVersionTable.PSVersion -ge "7.2") {
$Versions += @("net6.0")
}
if ($PSVersionTable.PSVersion -ge "7.1") {
$Versions += @("net5.0")
}
if ($PSVersionTable.PSVersion -ge "6.0") {
$Versions += @("netstandard2.1", "netstandard2.0", "netstandard1.6", "netstandard1.5", "netstandard1.4", "netstandard1.3", "netstandard1.2", "netstandard1.1", "netstandard1.0")
}
if ($PSVersionTable.PSVersion -ge "4.0") {
$Versions += @("net482","net481","net48","net472","net471","net47","net463","net462","net461","net46", "net452", "net451", "net45", "net40", "net35", "net20")
} elseif ($PSVersionTable.PSVersion -ge "3.0") {
$Versions = "net40", "net35", "net20", "net45", "net451", "net452", "net46"
} else {
$Versions = "net35", "net20"
}
# build full path with \ on the end
$LibraryPath = ($Versions -replace "^", "$PackagePath*\lib\") + "$PackagePath*\lib\" + "$PackagePath*" |
# find the first one that exists
Convert-Path -ErrorAction SilentlyContinue | Select-Object -First 1
$Number = $LibraryPath -replace '.*?([\d\.]+)$', '$1' -replace '(?<=\d)(?=\d)$', '.'
if (Test-Path "$PackagePath\$Name.nuspec") {
Write-Verbose "Found nuspec file at $PackagePath\$Name.nuspec"
$Document = [xml](Get-Content "$PackagePath\$Name.nuspec")
} elseif (Test-Path "$PackagePath\$Name*.nupkg") {
$Nupkg = Convert-Path "$PackagePath\$Name*.nupkg"
Write-Verbose "Reading nupkg at $Nupkg"
try {
$Package = [System.IO.Packaging.Package]::Open( $Nupkg, "Open", "Read" )
$Part = $Package.GetPart( $Package.GetRelationshipsByType( "http://schemas.microsoft.com/packaging/2010/07/manifest" ).TargetUri )
try {
$Stream = $Part.GetStream()
$Reader = [System.IO.StreamReader]$Stream
$Document = [xml]$Reader.ReadToEnd()
} catch [Exception] {
$PSCmdlet.WriteError( [System.Management.Automation.ErrorRecord]::new($_.Exception, "Unexpected Exception", "InvalidResult", $_) )
} finally {
if ($Reader) {
$Reader.Close()
$Reader.Dispose()
}
if ($Stream) {
$Stream.Close()
$Stream.Dispose()
}
}
if ($Package) {
$Package.Close()
$Package.Dispose()
}
} catch [Exception] {
$PSCmdlet.WriteError( [System.Management.Automation.ErrorRecord]::new($_.Exception, "Cannot Open Path", "OpenError", $Path) )
}
}
if ($Document) {
Write-Debug $Document.OuterXml
if ($Dependencies = $Document.package.metadata.dependencies) {
Write-Verbose "Importing Dependencies for $number"
foreach ($dependency in @($Dependencies.Group).Where{ $_.targetFramework.EndsWith($number) }.dependency.id) {
Import-NugetLibrary -Destination:$Destination -Name:$dependency
}
}
if ($References = $Document.package.metadata.references) {
Write-Verbose "Importing References for $number"
$group = @($references.Group).Where{ $_.targetFramework.EndsWith($number) }
if ($group) {
$Files = $group.dependency.id
} else {
Write-Warning "Couldn't match $number, try all of them"
# If we can't figure out the right group, just get all the references:
$Files = @($references.SelectNodes("//*[name(.) = 'reference']").File | Select-Object -Unique)
}
$Assemblies = Get-Item ($Files -replace "^", "$LibraryPath\")
}
}
if (!$Assemblies) {
$Assemblies = Get-ChildItem $LibraryPath -Filter *.dll
}
if ($Assemblies) {
# Just for the purpose of the verbose output
Push-Location $Destination
# since we don't know the order, we'll just loop a few times
for ($e = 0; $e -lt $Assemblies.Count; $e++) {
$success = $true
foreach ($assm in $Assemblies) {
Write-Verbose "Import Library $(Resolve-Path $Assm.FullName -Relative)"
Add-Type -Path $Assm.FullName -ErrorAction SilentlyContinue -ErrorVariable failure
if ($failure) {
$success = $false
} else {
Write-Host "LOADING: " -Fore Cyan -NoNewline
Write-Host $LibraryPath\ -Fore Yellow -NoNewline
Write-Host $Assm.Name -Fore White
}
}
# if we loaded everything ok, we're done
if ($success) {
break
}
}
Pop-Location
}
if (!$success) {
throw $failure
}
return
@Jaykul
Copy link
Author

Jaykul commented Oct 9, 2019

The -PackageSaveMode prevented nuget from saving the whole .nupkg file

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment