public/Compress-GZipArchive.ps1

using namespace System.IO
using namespace System.IO.Compression
using namespace System.Text
using namespace System.Management.Automation
function Compress-GzipArchive {
    <#
    .SYNOPSIS
    Creates a Gzip compressed file from specified File Paths or input Bytes.
 
    .Parameter Path
    Specifies the path or paths to the files that you want to add to the Gzip archive file.
    To specify multiple paths, and include files in multiple locations, use commas to separate the paths.
    This Parameter accepts wildcard characters. Wildcard characters allow you to add all files in a directory to your archive file.
 
    .PARAMETER LiteralPath
    Specifies the path or paths to the files that you want to add to the Gzip archive file.
    Unlike the Path Parameter, the value of LiteralPath is used exactly as it's typed.
    No characters are interpreted as wildcards
 
    .PARAMETER InputBytes
    Takes the bytes from pipeline and adds to the Gzip archive file.
    This parameter is meant to be used in combination with `ConvertTo-GzipString -Raw`.
 
    .PARAMETER DestinationPath
    The destination path to the Gzip file.
    If the file name in DestinationPath doesn't have a `.gzip` file name extension, the function appends the `.gzip` file name extension.
 
    .PARAMETER CompressionLevel
    Define the compression level that should be used.
    See https://learn.microsoft.com/en-us/dotnet/api/system.io.compression.compressionlevel for details.
 
    .PARAMETER Update
    Appends to the existing Gzip file.
 
    .PARAMETER Force
    Replaces an existing Gzip file with a new one. All contents will be lost.
 
    .PARAMETER PassThru
    Outputs the object representing the compressed file. The function produces no output by default.
 
    .LINK
    https://github.com/santisq/PSCompression
    #>


    [CmdletBinding(DefaultParameterSetName='Path')]
    [Alias('gziptofile')]
    param(
        [Parameter(ParameterSetName = 'PathWithUpdate', Mandatory, Position = 0, ValueFromPipeline)]
        [Parameter(ParameterSetName = 'PathWithForce', Mandatory, Position = 0, ValueFromPipeline)]
        [Parameter(ParameterSetName = 'Path', Mandatory, Position = 0, ValueFromPipeline)]
        [string[]] $Path,

        [Parameter(ParameterSetName = 'LiteralPathWithUpdate', Mandatory, ValueFromPipelineByPropertyName)]
        [Parameter(ParameterSetName = 'LiteralPathWithForce', Mandatory, ValueFromPipelineByPropertyName)]
        [Parameter(ParameterSetName = 'LiteralPath', Mandatory, ValueFromPipelineByPropertyName)]
        [Alias('PSPath')]
        [string[]] $LiteralPath,

        [Parameter(ParameterSetName = 'RawBytesWithUpdate', Mandatory, ValueFromPipeline)]
        [Parameter(ParameterSetName = 'RawBytesWithForce', Mandatory, ValueFromPipeline)]
        [Parameter(ParameterSetName = 'RawBytes', Mandatory, ValueFromPipeline)]
        [byte[]] $InputBytes,

        [Parameter(Position = 1, Mandatory)]
        [string] $DestinationPath,

        [Parameter()]
        [CompressionLevel] $CompressionLevel = 'Optimal',

        [Parameter(ParameterSetName = 'RawBytesWithUpdate', Mandatory)]
        [Parameter(ParameterSetName = 'PathWithUpdate', Mandatory)]
        [Parameter(ParameterSetName = 'LiteralPathWithUpdate', Mandatory)]
        [switch] $Update,

        [Parameter(ParameterSetName = 'RawBytesWithForce', Mandatory)]
        [Parameter(ParameterSetName = 'PathWithForce', Mandatory)]
        [Parameter(ParameterSetName = 'LiteralPathWithForce', Mandatory)]
        [switch] $Force,

        [Parameter()]
        [switch] $PassThru
    )

    begin {
        if($Force.IsPresent) {
            $fsMode = [FileMode]::Create
        }
        elseif($Update.IsPresent) {
            $fsMode = [FileMode]::Append
        }
        else {
            $fsMode = [FileMode]::CreateNew
        }
        $ExpectingInput = $null
    }
    process {
        try {
            if($withPath = -not $PSBoundParameters.ContainsKey('InputBytes')) {
                $isLiteral = $PSBoundParameters.ContainsKey('LiteralPath')
                $paths     = $Path
                if($isLiteral) {
                    $paths = $LiteralPath
                }
                $items = $ExecutionContext.InvokeProvider.Item.Get($paths, $true, $isLiteral)

                if(-not $items) {
                    foreach($path in $paths) {
                        $PSCmdlet.WriteError([ErrorRecord]::new(
                            [ItemNotFoundException] "Cannot find path '$path' because it does not exist.",
                            'PathNotFound',
                            [ErrorCategory]::ObjectNotFound,
                            $DestinationPath
                        ))
                    }
                }
            }

            if(-not $expectingInput) {
                $expectingInput  = $true
                $DestinationPath = $PSCmdlet.GetUnresolvedProviderPathFromPSPath($DestinationPath)
                if([Path]::GetExtension($DestinationPath) -ne '.gzip') {
                    $DestinationPath = $DestinationPath + '.gzip'
                }
                $null      = [Directory]::CreateDirectory([Path]::GetDirectoryName($DestinationPath))
                $outStream = [File]::Open($DestinationPath, $fsMode)
                $gzip      = [GZipStream]::new($outStream, [CompressionMode]::Compress, $CompressionLevel)

                if(-not $withPath) {
                    $inStream = [MemoryStream]::new($InputBytes)
                }
            }

            foreach($item in $items) {
                try {
                    $inStream = $item.OpenRead()
                    $inStream.CopyTo($gzip)
                }
                catch {
                    $PSCmdlet.WriteError($_)
                }
                finally {
                    if($inStream -is [IDisposable]) {
                        $inStream.Dispose()
                    }
                }
            }
        }
        catch {
            $gzip, $outStream, $inStream | ForEach-Object Dispose
            $PSCmdlet.ThrowTerminatingError($_)
        }
    }
    end {
        try {
            if(-not $withPath) {
                $inStream.Flush()
                $inStream.CopyTo($outStream)
            }
        }
        catch {
            $PSCmdlet.ThrowTerminatingError($_)
        }
        finally {
            $gzip, $outStream, $inStream | ForEach-Object Dispose

            if($PassThru.IsPresent) {
                $outStream.Name -as [FileInfo]
            }
        }
    }
}