Last active
May 13, 2022 09:21
-
-
Save JPRuskin/91eeef066642f1d3f1000f38bea059f5 to your computer and use it in GitHub Desktop.
Some unfinished functions to handle CRUD in zip (/nupkg) archives.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function Find-FileInArchive { | |
<# | |
.Synopsis | |
Finds files matching a pattern in an archive. | |
.Example | |
Find-FileInArchive -Path "C:\Archive.zip" -like "tools/files/*-x86.exe" | |
.Example | |
Find-FileInArchive -Path $Nupkg -match "tools/files/dotnetcore-sdk-(?<Version>\d+\.\d+\.\d+)-win-x86\.exe(\.ignore)?" | |
.Notes | |
Please be aware that this matches against the full name of the file, not just the file name. | |
Though given that, you can easily write something to match the file name. | |
#> | |
[CmdletBinding(DefaultParameterSetName="match")] | |
param( | |
# Path to the archive | |
[Parameter(Mandatory)] | |
[string]$Path, | |
# Pattern to match with basic globbing | |
[Parameter(Mandatory, ValueFromPipeline, ParameterSetName="match")] | |
[string]$match, | |
# Pattern to match with regex | |
[Parameter(Mandatory, ParameterSetName="like")] | |
[string]$like | |
) | |
begin { | |
while (-not $Zip -and $AccessRetries++ -lt 3) { | |
try { | |
$Stream = [IO.FileStream]::new($Path, [IO.FileMode]::Open) | |
$Zip = [IO.Compression.ZipArchive]::new($Stream, [IO.Compression.ZipArchiveMode]::Read) | |
} catch [System.IO.IOException] { | |
if ($AccessRetries -ge 3) { | |
Write-Error -Message "Accessing '$Path' failed after $AccessRetries attempts." -TargetObject $Path | |
} else { | |
Write-Information "Could not access '$Path', retrying..." | |
Start-Sleep -Milliseconds 500 | |
} | |
} | |
} | |
} | |
process { | |
if ($Zip) { | |
$WhereBlock = [ScriptBlock]::Create("`$_.FullName -$($PSCmdlet.ParameterSetName) '$(Get-Variable -Name $PSCmdlet.ParameterSetName -ValueOnly)'") | |
$Zip.Entries | Where-Object -FilterScript $WhereBlock | |
} | |
} | |
end { | |
if ($Zip) { | |
$Zip.Dispose() | |
} | |
if ($Stream) { | |
$Stream.Close() | |
$Stream.Dispose() | |
} | |
} | |
} | |
function Remove-FileInArchive { | |
<# | |
.Synopsis | |
Removes files from a zip formatted archive | |
.Description | |
In order to reduce the size of an archive, you may want to remove files from it. | |
This function will remove the files you specify from the archive you specify. | |
.Example | |
Remove-FileInArchive -Path $Nupkg -Name dotnet-sdk-3.1.410-win-x86.exe dotnet-sdk-3.1.410-win-x86.exe.ignore | |
.Example | |
Remove-FileInArchive -Zip $Zip -FullName "tools/chocolateyInstall.ps1" | |
#> | |
[CmdletBinding(SupportsShouldProcess)] | |
param( | |
# Path to the archive | |
[Parameter(Mandatory, ParameterSetName = "PathFullName")] | |
[Parameter(Mandatory, ParameterSetName = "PathName")] | |
[string]$Path, | |
# Zip object for the archive | |
[Parameter(Mandatory, ParameterSetName = "ZipFullName")] | |
[Parameter(Mandatory, ParameterSetName = "ZipName")] | |
[IO.Compression.ZipArchive]$Zip, | |
# Name of the file(s) to remove in the archive | |
[Parameter(Mandatory, ValueFromPipeline, ValueFromRemainingArguments, ParameterSetName="PathFullName")] | |
[Parameter(Mandatory, ValueFromPipeline, ValueFromRemainingArguments, ParameterSetName="ZipFullName")] | |
[string[]]$FullName, | |
# Name of the file(s) to remove in the archive | |
[Parameter(Mandatory, ValueFromPipeline, ValueFromRemainingArguments, ParameterSetName="PathName")] | |
[Parameter(Mandatory, ValueFromPipeline, ValueFromRemainingArguments, ParameterSetName="ZipName")] | |
[string[]]$Name | |
) | |
begin { | |
if (-not $PSCmdlet.ParameterSetName.StartsWith("Zip")) { | |
$Stream = [IO.FileStream]::new($Path, [IO.FileMode]::Open) | |
$Zip = [IO.Compression.ZipArchive]::new($Stream, [IO.Compression.ZipArchiveMode]::Update) | |
} | |
} | |
process { | |
foreach ($File in Get-Variable -Name $PSCmdlet.ParameterSetName.TrimStart('PathZip') -ValueOnly) { | |
($Zip.Entries | Where-Object {$_."$($PSCmdlet.ParameterSetName.TrimStart('PathZip'))" -eq $File}) | ForEach-Object { | |
if ($PSCmdlet.ShouldProcess($_.FullName, "Remove")) { | |
$_.Delete() | |
} | |
} | |
} | |
} | |
end { | |
if (-not $PSCmdlet.ParameterSetName.StartsWith("Zip")) { | |
$Zip.Dispose() | |
$Stream.Close() | |
$Stream.Dispose() | |
} | |
} | |
} | |
function Get-FileContentInArchive { | |
<# | |
.Synopsis | |
Returns the content of a file from within an archive | |
.Example | |
Get-FileContentInArchive -Path $ZipPath -Name "chocolateyInstall.ps1" | |
.Example | |
Get-FileContentInArchive -Zip $Zip -FullName "tools\chocolateyInstall.ps1" | |
#> | |
[CmdletBinding(DefaultParameterSetName="PathFullName")] | |
[OutputType([string])] | |
param( | |
# Path to the archive | |
[Parameter(Mandatory, ParameterSetName = "PathFullName")] | |
[Parameter(Mandatory, ParameterSetName = "PathName")] | |
[string]$Path, | |
# Zip object for the archive | |
[Parameter(Mandatory, ParameterSetName = "ZipFullName")] | |
[Parameter(Mandatory, ParameterSetName = "ZipName")] | |
[IO.Compression.ZipArchive]$Zip, | |
# Name of the file(s) to remove from the archive | |
[Parameter(Mandatory, ParameterSetName = "PathFullName")] | |
[Parameter(Mandatory, ParameterSetName = "ZipFullName")] | |
[string]$FullName, | |
# Name of the file(s) to remove from the archive | |
[Parameter(Mandatory, ParameterSetName = "PathName")] | |
[Parameter(Mandatory, ParameterSetName = "ZipName")] | |
[string]$Name | |
) | |
begin { | |
if (-not $PSCmdlet.ParameterSetName.StartsWith("Zip")) { | |
$Stream = [IO.FileStream]::new($Path, [IO.FileMode]::Open) | |
$Zip = [IO.Compression.ZipArchive]::new($Stream, [IO.Compression.ZipArchiveMode]::Read) | |
} | |
} | |
process { | |
if (-not $FullName) { | |
$MatchingEntries = $Zip.Entries | Where-Object {$_.Name -eq $Name} | |
if ($MatchingEntries.Count -ne 1) { | |
Write-Error "File '$Name' not found in archive" -ErrorAction Stop | |
} | |
$FullName = $MatchingEntries[0].FullName | |
} | |
[System.IO.StreamReader]::new( | |
$Zip.GetEntry($FullName).Open() | |
).ReadToEnd() | |
} | |
end { | |
if (-not $PSCmdlet.ParameterSetName.StartsWith("Zip")) { | |
$Zip.Dispose() | |
$Stream.Close() | |
$Stream.Dispose() | |
} | |
} | |
} | |
function Update-FileInArchive { | |
<# | |
.Synopsis | |
Updates a text file in an archive | |
.Description | |
In order to remove references to given files from install scripts, you may want to update a file within an archive (without repacking it). | |
This function will update the content of files in the archive you specify. | |
.Example | |
Update-FileInArchive -Path $Nupkg -FullName "tools/chocolateyInstall.ps1" -Value $UpdatedScript | |
.Example | |
Update-FileInArchive -Zip $Zip -Name "chocolateyInstall.ps1" -Value $UpdatedScript | |
#> | |
[CmdletBinding(DefaultParameterSetName="PathFullName", SupportsShouldProcess)] | |
param( | |
# Path to the archive | |
[Parameter(Mandatory, ParameterSetName = "PathFullName")] | |
[Parameter(Mandatory, ParameterSetName = "PathName")] | |
[string]$Path, | |
# Zip object for the archive | |
[Parameter(Mandatory, ParameterSetName = "ZipFullName")] | |
[Parameter(Mandatory, ParameterSetName = "ZipName")] | |
[IO.Compression.ZipArchive]$Zip, | |
# Name of the file to update in the archive | |
[Parameter(Mandatory, ParameterSetName = "PathFullName")] | |
[Parameter(Mandatory, ParameterSetName = "ZipFullName")] | |
[string]$FullName, | |
# Name of the file to update in the archive | |
[Parameter(Mandatory, ParameterSetName = "PathName")] | |
[Parameter(Mandatory, ParameterSetName = "ZipName")] | |
[string]$Name, | |
# Value to set the file to | |
[Parameter(Mandatory)] | |
[string]$Value | |
) | |
begin { | |
if (-not $PSCmdlet.ParameterSetName.StartsWith("Zip")) { | |
$Stream = [IO.FileStream]::new($Path, [IO.FileMode]::Open) | |
$Zip = [IO.Compression.ZipArchive]::new($Stream, [IO.Compression.ZipArchiveMode]::Update) | |
} | |
} | |
process { | |
if (-not $FullName) { | |
$MatchingEntries = $Zip.Entries | Where-Object {$_.Name -eq $Name} | |
if ($MatchingEntries.Count -ne 1) { | |
Write-Error "File '$Name' not found in archive" -ErrorAction Stop | |
} | |
$FullName = $MatchingEntries[0].FullName | |
} | |
if ($PSCmdlet.ShouldProcess("Update", $_.FullName)) { | |
# Either remove file, create entry | |
Remove-FileInArchive -Zip $Zip -FullName $FullName | |
$Zip.CreateEntry() | |
# Or update existing entry and length | |
} | |
} | |
end { | |
if (-not $PSCmdlet.ParameterSetName.StartsWith("Zip")) { | |
$Zip.Dispose() | |
$Stream.Close() | |
$Stream.Dispose() | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment