Sunday, February 5, 2023

PowerShell: Create a GZip (*.gz)

PowerShell natively does not contain a CmdLet for creating a GZip file. There are third-party modules/CmdLets that create GZip. It is a straightforward process to access the CLI using PowerShell to create a GZip.

In support of creating a Gzip the following PowerShell functions were implemented:

  • New-GZipArchive: function that creates the actual GZip file
  • Close-Stream: helper function that handles closing/disposing the streams used.

The code is as follows:

function Close-Stream {
    param
    (
        [Parameter(Mandatory=$false)]        
        [System.IO.Stream] $stream
    )

    if ($null -ne $stream) {
        $stream.Close()
        $stream.Dispose()
    }
}

function New-GZipArchive {
    param
    (
        [Parameter(Mandatory=$true)]        
        [string] $sourceFilePath,
        [Parameter(Mandatory=$true)]
        [string] $destinationFilePath,
        [switch] $overwrite
    )

    [System.IO.FileStream] $sourceFileStream = $null
    [System.IO.FileStream] $destinationFileStream = $null
    [System.IO.Compression.GZipStream] $gzipStream

    try {
        if ($overwrite)
        {
            if (Test-Path `
                    -Path $destinationFilePath `
                    -PathType Leaf `
                    -ErrorAction:Stop) {
                Remove-Item `
                    -Path $destinationFilePath`
                    -ErrorAction:Stop
            }
        }

        [byte[]] $buffer = [System.Byte[]]::new([Math]::Pow(2, 20))

        $sourceFileStream = [System.IO.FileStream]::new(
                                $sourceFilePath,
                                [System.IO.FileMode]::Open,
                                [System.IO.FileAccess]::Read,
                                [System.IO.FileShare]::Read)
        $destinationFileStream = [System.IO.FileStream]::new(
                                    $destinationFilePath,
                                    [System.IO.FileMode]::CreateNew,
                                    [System.IO.FileAccess]::Write,
                                    [System.IO.FileShare]::None)
        $gzipStream = [System.IO.Compression.GZipStream]::new(
                $destinationFileStream,
                [System.IO.Compression.CompressionMode]::Compress)

        do {
            [int] $bytesRead = $sourceFileStream.Read(
                                     $buffer,
                                     0,
                                     $buffer.Length)

            $gzipStream.Write($buffer, 0, $bytesRead)
        } while($bytesRead -ne 0)
    }
    
    finally {
        Close-Stream $sourceFileStream
        Close-Stream $gzipStream
        Close-Stream $destinationFileStream
    }
}