Public/Get-NuGetPackageContent.ps1
|
function Get-NuGetPackageContent { <# .SYNOPSIS Lists entries in a NuGet package or reads an internal file. .DESCRIPTION Opens a local .nupkg as a ZIP archive using .NET, without extracting files or requiring external tools. By default, returns metadata objects that remain usable after the archive is closed. With EntryPath, returns the complete file as one string, preserving line endings. Text defaults to UTF-8 with BOM detection; invalid UTF-8 produces an error. Use AsByteStream for binary files. .PARAMETER Path One or more literal file system paths to local packages. Accepts paths or FileInfo objects from the pipeline. Wildcards are not expanded. .PARAMETER EntryPath Exact, case-sensitive internal file path, using ZIP forward slashes. Wildcards are not expanded. Directory entries cannot be read as files. .PARAMETER AsByteStream Returns the selected file as a single byte array instead of decoding text. .OUTPUTS System.Management.Automation.PSCustomObject Listing properties: PackagePath, FullName, Name, Length, CompressedLength, LastWriteTime, and IsDirectory. System.String Complete text of the selected file. System.Byte[] Raw bytes of the selected file when AsByteStream is specified. .EXAMPLE Get-NuGetPackageContent -Path .\Example.1.0.0.nupkg .EXAMPLE Get-NuGetPackageContent .\Example.1.0.0.nupkg -EntryPath 'Example.nuspec' .EXAMPLE $bytes = Get-NuGetPackageContent .\Example.1.0.0.nupkg -EntryPath 'lib/netstandard2.0/Example.dll' -AsByteStream #> [CmdletBinding(DefaultParameterSetName = 'List')] param( [Parameter(Mandatory, Position = 0, ValueFromPipeline, ValueFromPipelineByPropertyName)] [Alias('FullName')] [ValidateNotNullOrEmpty()] [string[]]$Path, [Parameter(Mandatory, Position = 1, ParameterSetName = 'Read')] [ValidateNotNullOrEmpty()] [string]$EntryPath, [Parameter(ParameterSetName = 'Read')] [switch]$AsByteStream ) begin { Add-Type -AssemblyName System.IO.Compression.FileSystem -ErrorAction Stop } process { foreach ($package in $Path) { $archive = $null $stream = $null $reader = $null $buffer = $null try { $file = Get-Item -LiteralPath $package -Force -ErrorAction Stop if ($file -isnot [System.IO.FileInfo]) { throw "'$package' is not a file system file." } $archive = [System.IO.Compression.ZipFile]::OpenRead($file.FullName) if ($PSCmdlet.ParameterSetName -eq 'List') { foreach ($entry in $archive.Entries) { [pscustomobject]@{ PackagePath = $file.FullName FullName = $entry.FullName Name = $entry.Name Length = $entry.Length CompressedLength = $entry.CompressedLength LastWriteTime = $entry.LastWriteTime IsDirectory = $entry.FullName.EndsWith('/') } } } else { $entry = $archive.GetEntry($EntryPath) if ($null -eq $entry) { throw "Entry '$EntryPath' was not found." } if ($entry.FullName.EndsWith('/')) { throw "Entry '$EntryPath' is a directory, not a file." } $stream = $entry.Open() if ($AsByteStream) { $buffer = [System.IO.MemoryStream]::new() $stream.CopyTo($buffer) Write-Output -NoEnumerate ($buffer.ToArray()) } else { $encoding = [System.Text.UTF8Encoding]::new($false, $true) $reader = [System.IO.StreamReader]::new($stream, $encoding, $true) $reader.ReadToEnd() } } } catch { $message = "Failed to read NuGet package '$package': $($_.Exception.Message)" $exception = [System.IO.IOException]::new($message, $_.Exception) $PSCmdlet.WriteError([System.Management.Automation.ErrorRecord]::new( $exception, 'NuGetPackageReadFailed', [System.Management.Automation.ErrorCategory]::ReadError, $package)) } finally { if ($null -ne $reader) { $reader.Dispose() } elseif ($null -ne $stream) { $stream.Dispose() } if ($null -ne $buffer) { $buffer.Dispose() } if ($null -ne $archive) { $archive.Dispose() } } } } } |