PwSh.Fw.Archive.psm1
|
Add-Type -Assembly System.IO.Compression.FileSystem <# .SYNOPSIS List the files contained in an archive .DESCRIPTION Long description .PARAMETER Path Full path to the archive file .PARAMETER PassThru If specified, Get-ArchiveContent will return whole archive file object. If not specified, Get-ArchiveContent will return file list .EXAMPLE archive.zip | Get-ArchiveContent .NOTES Inspired by @url https://stackoverflow.com/questions/43715949/powershell-extract-specific-files-folders-from-a-zipped-archive #> function Get-ArchiveContent { [CmdletBinding()] [OutputType([String])] Param ( [Parameter(Mandatory = $true, ValueFromPipeLine = $true)][string]$Path, [switch]$PassThru ) Begin { Write-EnterFunction } Process { if (!(Test-FileExist $Path)) { Write-Fatal "Archive '$Path' not found." } # $archive = Get-Item -Path $Path #extract list entries for dir myzipdir/c/ into myzipdir.zip $zip = [IO.Compression.ZipFile]::OpenRead($Path) $entries = $zip.Entries #free object $zip.Dispose() if ($PassThru) { return $entries } else { return $entries.fullname } } End { Write-LeaveFunction } } <# .SYNOPSIS Expand a single from an archive .DESCRIPTION Extract only one specified file from an archive. .PARAMETER Path Path to the archive file .PARAMETER DestinationPath Destination path where to extract files .PARAMETER Files Exact filename to extract. The path must be relative to the root of the archive. Wildcard are not allowed .PARAMETER Force If specified, erase existing files .PARAMETER PassThru If specified, return filesystem object of files extracted. If not specified, return a list of path/files extracted .EXAMPLE "archive.zip" | Expand-SingleFileFromArchive -File "README.md" .EXAMPLE "archive.zip" | Expand-SingleFileFromArchive -File "src/path/to/file.c" This example extract the file 'file.c' from the "archive.zip" file, located in the "src/path/to" folder inside the archive. .NOTES Inspired by @url https://stackoverflow.com/questions/43715949/powershell-extract-specific-files-folders-from-a-zipped-archive #> function Expand-SingleFileFromArchive { [CmdletBinding()] [OutputType([Boolean], [System.IO.FileInfo])] Param ( [Parameter(Mandatory = $true, ValueFromPipeLine = $true)][string]$Path, [Parameter(Mandatory = $false, ValueFromPipeLine = $false)][string]$DestinationPath, [Parameter(Mandatory = $true, ValueFromPipeLine = $false)][string]$File, [switch]$Force, [switch]$PassThru ) Begin { Write-EnterFunction } Process { $rc = $false if (!(Test-FileExist $Path)) { Write-Fatal "Archive '$Path' not found." } $archive = Get-Item -Path $Path if ([string]::IsNullOrEmpty($DestinationPath)) { $DestinationPath = "$($archive.Directory)/$($archive.BaseName)" } #create dir for result of extraction $FileName = Split-Path $File -Leaf if ($Force) { if (Test-FileExist "$DestinationPath/$FileName") { Remove-Item -Path "$DestinationPath/$FileName" -Confirm:$false -Force:$Force } $null = New-Item -ItemType Directory -Path "$DestinationPath" -Force:$Force -ErrorAction SilentlyContinue } #extract list entries for dir myzipdir/c/ into myzipdir.zip try { $zip = [IO.Compression.ZipFile]::OpenRead($Path) $entry = $zip.GetEntry($File) if ($null -ne $entry) { #extraction [IO.Compression.ZipFileExtensions]::ExtractToFile( $entry, "$DestinationPath/$($entry.Name)", $Force) $rc = $? } else { Write-Error "File '$File' not found in archive '$($archive.Name)'" Write-Error "Try to Get-ArchiveContent to see what's inside." Write-Error "Remember, -File must be the full path to file from the archive point of view." $rc = $false } } catch { Write-Error $_ $rc = $false } finally { #free object $zip.Dispose() } if ($PassThru) { if ($rc) { return "$DestinationPath/$($entry.Name)" } else { return $rc } } else { return $rc } } End { Write-LeaveFunction } } <# .SYNOPSIS Expand a CAB archive .DESCRIPTION Extract all files from a Microsoft Cabinet (.cab) archive. This function relies on platform tools, because no GPL-compatible managed implementation exists: - Windows: built-in Expand cmdlet (Microsoft.PowerShell.Archive) - Linux/macOS: cabextract, invoked via PwSh.Fw.Core Execute-Command .PARAMETER Path Full path to the .cab archive file .PARAMETER DestinationPath Destination folder where to extract files. If not specified, files are extracted to a folder next to the archive, named after the archive (without extension). .PARAMETER Force If specified, erase existing files before extraction. Note: on Linux/macOS, cabextract overwrites existing files anyway. .PARAMETER PassThru If specified, return the list of extracted file paths. If not specified, return $true on success, $false on failure. .EXAMPLE "archive.cab" | Expand-CabFile .EXAMPLE "archive.cab" | Expand-CabFile -DestinationPath /tmp/out -Force .NOTES CAB support is delegated to platform tools (Expand on Windows, cabextract elsewhere) since managed CAB libraries are not GPL-compatible (WixToolset is MS-RL / fee-EULA licensed). #> function Expand-CabFile { [CmdletBinding()] [OutputType([Boolean], [String])] Param ( [Parameter(Mandatory = $true, ValueFromPipeLine = $true)][string]$Path, [Parameter(Mandatory = $false, ValueFromPipeLine = $false)][string]$DestinationPath, [switch]$Force, [switch]$PassThru ) Begin { Write-EnterFunction } Process { $rc = $false if (!(Test-FileExist $Path)) { Write-Fatal "Archive '$Path' not found." } $archive = Get-Item -Path $Path if ([string]::IsNullOrEmpty($DestinationPath)) { $DestinationPath = "$($archive.Directory)/$($archive.BaseName)" } if ($IsWindows) { # built-in cmdlet from Microsoft.PowerShell.Archive if ($Force) { # Expand has no overwrite option: clean destination first Get-ChildItem -Path $DestinationPath -Recurse -Force -ErrorAction SilentlyContinue | Remove-Item -Recurse -Force -ErrorAction SilentlyContinue } $null = New-Item -ItemType Directory -Path $DestinationPath -Force -ErrorAction SilentlyContinue try { Expand $Path -F:* $DestinationPath -ErrorAction Stop $rc = $true } catch { Write-Error $_ $rc = $false } } else { if (!(Get-Command cabextract -ErrorAction SilentlyContinue)) { Write-Fatal "CAB extractor 'cabextract' not found. Install it (e.g. 'apt install cabextract' or 'brew install cabextract')." } $null = New-Item -ItemType Directory -Path $DestinationPath -Force -ErrorAction SilentlyContinue $toolArgs = "-q -d '$DestinationPath'" if ($Force) { $toolArgs += " -f" } $toolArgs += " '$Path'" $rc = Execute-Command -exe "cabextract" -args $toolArgs -AsBool if (!$rc) { Write-Error "cabextract failed on archive '$Path'." } } if ($PassThru) { if ($rc) { return (Get-ChildItem -Path $DestinationPath -Recurse -File -Force).FullName } else { return $rc } } else { return $rc } } End { Write-LeaveFunction } } |