Restore-NuGetPackage.ps1
<#PSScriptInfo
.VERSION 0.1.3 .GUID 9925e87b-552a-45c0-89e9-73673dd588af .AUTHOR Slava Sharashkin .COMPANYNAME .COPYRIGHT .TAGS NuGet .LICENSEURI https://raw.githubusercontent.com/slavashar/Restore-NuGet/master/LICENSE .PROJECTURI https://github.com/slavashar/Restore-NuGet .ICONURI .EXTERNALMODULEDEPENDENCIES .REQUIREDSCRIPTS .EXTERNALSCRIPTDEPENDENCIES .RELEASENOTES #> <# .SYNOPSIS Retores NuGet package .DESCRIPTION The script restores specific version of a NuGet package and dependences. Currently only strongly typed version are supported. .PARAMETER PackageId A specific package id to restore .PARAMETER Version A specific version of the package to restore .PARAMETER Source Comma separeted list of sources .PARAMETER OutputDirectory Destination location of the restored packages .PARAMETER NoCache Indicates that no cache should be used #> Param( [Parameter(Mandatory=$True)] [ValidateNotNull()] [String]$Id, [Parameter(Mandatory=$True)] [ValidateNotNull()] [String]$Version, [String]$Source = "https://www.nuget.org/api/v2/", [String]$OutputDirectory = (Get-Location), [switch]$NoCache) Add-Type -Assembly "WindowsBase" if (!(Test-Path $OutputDirectory)) { $outputDir = New-Item $OutputDirectory -ItemType directory } else { $outputDir = Get-Item $OutputDirectory } $services = New-Object System.Collections.Generic.HashSet[object] $Source.Split(';') | Foreach { if ($_.StartsWith("http")) { [void]$services.Add((New-Object Uri -ArgumentList $_)) } else { [void]$services.Add((Get-Item $_)) } } function ExtractPackage($stream, $packageId, $packageVersion) { $directory = New-Item (Join-Path $outputDir "$packageId.$packageVersion") -ItemType directory $nupkgStartPosition = $stream.Position; $archive = [System.IO.Packaging.Package]::Open($stream) foreach ($part in $archive.GetParts()) { if ($part.ContentType -eq "application/vnd.openxmlformats-package.relationships+xml") { continue } if ($part.ContentType -eq "application/vnd.openxmlformats-package.core-properties+xml") { continue } if ($part.Uri.OriginalString -eq "/$packageId.nuspec") { $reader = New-Object System.IO.StreamReader -ArgumentList $part.GetStream() $spec = [xml] $reader.ReadToEnd() continue } $partPath = Join-Path $directory ([Uri]::UnescapeDataString($part.Uri.OriginalString)) $file = New-Item $partPath -ItemType file -Force $writer = $file.OpenWrite() [void]$part.GetStream().CopyTo($writer) [void]$writer.Close() } [void]$archive.Close() [void]$stream.Seek($nupkgStartPosition, [System.IO.SeekOrigin]::Begin); $partPath = Join-Path $directory "$packageId.$packageVersion.nupkg" $file = New-Item $partPath -ItemType file -Force $writer = $file.OpenWrite() [void]$stream.CopyTo($writer) [void]$writer.Close() return $spec } function GetSpec($nupkg) { $archive = [System.IO.Packaging.Package]::Open($nupkg) $packageId = $archive.PackageProperties.Identifier $specPart = $archive.GetPart((New-Object Uri -ArgumentList @( "/$packageId.nuspec", [UriKind]::Relative ))); $reader = New-Object System.IO.StreamReader -ArgumentList $specPart.GetStream() $spec = [xml] $reader.ReadToEnd() [void]$archive.Close() return $spec } function private:restorePackage($packageId, $packageVersion) { $directory = Join-Path $outputDir "$packageId.$packageVersion" $cachePath = Join-Path $env:LOCALAPPDATA "NuGet\Cache" $cachePackagePath = Join-Path $cachePath "$packageId.$packageVersion.nupkg" if (Test-Path $directory) { $spec = GetSpec ((Join-Path $directory "$packageId.$packageVersion.nupkg")) Write-Host $packageId $packageVersion already installed } elseif ((-not $NoCache) -and (Test-Path $cachePackagePath)) { $stream = [System.IO.File]::OpenRead($cachePackagePath) $spec = ExtractPackage -stream $stream -packageId $packageId -packageVersion $packageVersion $stream.Close() Write-Host Successfully installed $packageId $packageVersion from cache } else { $packageLocation = $null foreach ($service in $services) { if ($service -is [Uri]) { try { $packageResponce = Invoke-RestMethod (New-Object Uri -ArgumentList @( $service, "Packages(Id='$packageId',Version='$packageVersion')" )) } catch { continue } $packageLocation = $packageResponce.entry.content.src break } else { $tmp = Join-Path $service "$packageId.$packageVersion.nupkg" if (Test-Path $tmp) { $packageLocation = $tmp break } } } if ($packageLocation -eq $null) { throw "Unable to find version $packageVersion of package $packageId" } if ($packageLocation -is [string] -and $packageLocation.StartsWith("http")) { $packageContent = (New-Object Net.WebClient).DownloadData($packageLocation) } elseif ($packageLocation -is [string]) { $packageContent = [System.IO.File]::ReadAllBytes($packageLocation) } else { throw "Unable to retrieve the package" } if ((-not $NoCache)) { if (!(Test-Path $cachePath)) { New-Item $cachePath -ItemType directory | Out-Null } [System.IO.File]::WriteAllBytes($cachePackagePath, $packageContent) } try { $stream = New-Object System.IO.MemoryStream -ArgumentList @(, $packageContent) $spec = ExtractPackage -stream $stream -packageId $packageId -packageVersion $packageVersion } finally { $stream.Close() } Write-Host Successfully installed $packageId $packageVersion from source } return $spec } $installedPackages = @{} $requiredPackages = @{} $requiredPackages.Add($Id, $Version) while ($requiredPackages.Count -gt 0) { $packageId = $requiredPackages.Keys | select -First 1 $packageVersion = $requiredPackages[$packageId] Write-Host Restoring $packageId $packageVersion $spec = restorePackage -packageId $packageId -packageVersion $packageVersion $requiredPackages.Remove($packageId) $pkg = New-Object System.Object $pkg | Add-Member -MemberType NoteProperty -Name "Id" -Value $packageId $pkg | Add-Member -MemberType NoteProperty -Name "Version" -Value $packageVersion $pkg | Add-Member -MemberType NoteProperty -Name "Location" -Value (Join-Path $outputDir "$packageId.$packageVersion") $installedPackages.Add($packageId, $pkg) foreach ($dependency in ($spec.package.metadata.dependencies | foreach { $_.dependency })) { $dependencyPackageId = $dependency.id $dependencyVersion = $dependency.version if ($installedPackages.ContainsKey($dependencyPackageId)) { #TODO check the version } elseif ($requiredPackages.ContainsKey($dependencyPackageId)){ #TODO check the version } else { $requiredPackages.Add($dependencyPackageId, $dependencyVersion) } } } return $installedPackages.Values |