PwSh.Fw.Archive.psm1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
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 {
                eerror "File '$File' not found in archive '$($archive.Name)'"
                eerror "Try to Get-ArchiveContent to see what's inside."
                eerror "Remember, -File must be the full path to file from the archive point of view."
                $rc = $false
            }
        } catch {
            eerror $_
            $rc = $false
        } finally {
            #free object
            $zip.Dispose()
        }

        if ($PassThru) {
            if ($rc) { return "$DestinationPath/$($entry.Name)" } else { return $rc }
        } else {
            return $rc
        }
    }

    End {
        Write-LeaveFunction
    }
}