functions/Expand-ArchiveItem.ps1

Function Expand-ArchiveItem {
    <#
    .SYNOPSIS
    Extracts one or more items from the archive
     
    .DESCRIPTION
    Extract specific file or folder from the existing archive
     
    .PARAMETER Path
    Archive path
     
    .PARAMETER DestinationPath
    Destination folder to put the item into
     
    .PARAMETER Item
    Archived item: file or folder
     
    .PARAMETER PassThru
    If specified, returns the unpacked item object
 
    .PARAMETER Force
    Overwrites existing file(s)
 
    .PARAMETER Relative
    Extract with relative paths based on the specified item path
 
    .PARAMETER IgnoreFolders
    Extract all files to the same folder regardless of the paths inside the archive
     
    .EXAMPLE
    Expand-ArchiveItem -Path c:\temp\myarchive.zip -DestinationPath c:\MyFolder -Item MyFile.txt, Myfile2.txt
     
    .NOTES
    General notes
    #>

    [CmdletBinding(SupportsShouldProcess = $true)]
    Param(
        [Parameter(Mandatory = $true,
            ValueFromPipeline = $true,
            Position = 1)]
        [string]$Path,
        [Parameter(Mandatory = $true,
            Position = 2)]
        [string]$DestinationPath,
        [Parameter(Mandatory = $true,
            Position = 3)]
        [string[]]$Item,
        [switch]$PassThru,
        [switch]$Force,
        [switch]$Relative,
        [switch]$IgnoreFolders
    )
    begin {
    }
    process {
        $archive = Get-ArchiveItem -Path $Path 
        foreach ($currentItem in $Item) {
            #check if it's a folder
            if ($archive | Where-Object { $_.Folder -eq $currentItem -or $_.Folder -like (Join-Path $currentItem *) }) {
                $currentZipEntries = $archive | Where-Object Path -like (Join-Path $currentItem *)
            }
            else {
                $currentZipEntries = $archive | Where-Object Path -like $currentItem
            }
            if ($Relative) {
                $rootFolder = Split-Path $currentItem -Parent
            }
            if (!$currentZipEntries) {
                Write-Warning -Message "Item $currentItem was not found in $Path"
            }
            foreach ($currentZipItem in $currentZipEntries) {
                # get archive item
                if ($IgnoreFolders) {
                    $itemPath = Split-Path $currentZipItem.Path -Leaf
                }
                elseif ($Relative) {
                    $itemPath = $currentZipItem.Path -replace ("^" + [Regex]::Escape($rootFolder)), ''
                }
                else {
                    $itemPath = $currentZipItem.Path
                }
                # check if item exists
                if (Test-Path $DestinationPath) {
                    $destItem = Get-Item $DestinationPath
                    if ($destItem.PSIsContainer) {
                        $destFolder = $destItem.FullName
                        $itemDestPath = Join-Path $destItem.FullName $itemPath
                    }
                    else {
                        $itemDestPath = $DestinationPath
                    }
                }
                else {
                    $itemDestPath = Join-Path $DestinationPath $itemPath
                }
                
                if ($Force -eq $false -and (Test-Path $itemDestPath)) {
                    Write-Warning -Message "Destination item $itemDestPath already exists. No action performed. Use -Force to overwrite."
                    continue
                }
                
                # create parent directory
                $parent = Split-Path $itemDestPath -Parent
                if (!(Test-Path $parent)) {
                    if ($pscmdlet.ShouldProcess($parent, "Creating parent directory")) {
                        $null = New-Item -Path $parent -ItemType Directory -Force
                    }
                }

                if ($pscmdlet.ShouldProcess($currentZipItem.Path, "Extract archive item to $itemDestPath")) {
                    [ZipHelper]::SaveArchiveItem($Path, $currentZipItem.Path, $itemDestPath)
                }

                # return item object
                if ($PassThru) {
                    Get-Item $itemDestPath
                }
            }
        }
    }
    end {

    }
}