Private/Expand-GzipArchive.ps1
|
function Expand-GzipArchive { [CmdletBinding(SupportsShouldProcess = $false)] param ( [Parameter(Mandatory = $true, Position = 0)] [ValidateNotNullOrEmpty()] [ValidateScript( { if (Test-Path -Path $_ -PathType "Leaf") { $true } else { throw "Cannot find path $_." } })] [System.String] $Path, [Parameter(Mandatory = $false, Position = 1)] [ValidateNotNullOrEmpty()] [ValidateScript( { $ResolvedDestination = $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($_) $DestinationDirectory = [System.IO.Path]::GetDirectoryName($ResolvedDestination) if ([System.IO.Directory]::Exists($DestinationDirectory)) { $true } else { throw "Cannot find destination directory $DestinationDirectory." } })] [System.String] $DestinationPath = ($Path -replace "\.gz$", ""), [Parameter()] [ValidateRange(1, [System.Int32]::MaxValue)] [System.Int32] $BufferSize = 1024 ) if (-not $PSBoundParameters.ContainsKey("DestinationPath") -and $Path -notmatch "\.gz$") { throw "DestinationPath must be specified when Path does not end in .gz." } $SourceFullPath = (Resolve-Path -LiteralPath $Path -ErrorAction Stop).ProviderPath $DestinationFullPath = $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($DestinationPath) $PathComparison = [System.StringComparison]::Ordinal if (Test-IsWindows) { $PathComparison = [System.StringComparison]::OrdinalIgnoreCase } if ([System.String]::Equals($SourceFullPath, $DestinationFullPath, $PathComparison)) { throw "The destination path must be different from the source path." } $DestinationDirectory = [System.IO.Path]::GetDirectoryName($DestinationFullPath) $TemporaryPath = [System.IO.Path]::Combine( $DestinationDirectory, ".$([System.IO.Path]::GetFileName($DestinationFullPath)).$([System.Guid]::NewGuid().ToString('N')).tmp" ) $InputStream = $null $OutputStream = $null $GzipStream = $null $Succeeded = $false try { try { Write-Verbose -Message "$($MyInvocation.MyCommand): Create input file stream." $InputStream = [System.IO.File]::Open( $SourceFullPath, [System.IO.FileMode]::Open, [System.IO.FileAccess]::Read, [System.IO.FileShare]::Read ) Write-Verbose -Message "$($MyInvocation.MyCommand): Create temporary output file stream." $OutputStream = [System.IO.File]::Open( $TemporaryPath, [System.IO.FileMode]::CreateNew, [System.IO.FileAccess]::Write, [System.IO.FileShare]::None ) Write-Verbose -Message "$($MyInvocation.MyCommand): Create Gzip stream." $GzipStream = New-Object -TypeName "System.IO.Compression.GzipStream" $InputStream, ` ([System.IO.Compression.CompressionMode]::Decompress) Write-Verbose -Message "$($MyInvocation.MyCommand): Attempt expand: $DestinationPath." $Buffer = New-Object -TypeName System.Byte[] -ArgumentList $BufferSize while ($true) { $Read = $GzipStream.Read($Buffer, 0, $BufferSize) if ($Read -le 0) { break } $OutputStream.Write($Buffer, 0, $Read) } } finally { try { if ($null -ne $GzipStream) { $GzipStream.Dispose() } } finally { try { if ($null -ne $OutputStream) { $OutputStream.Dispose() } } finally { if ($null -ne $InputStream) { $InputStream.Dispose() } } } } if ([System.IO.File]::Exists($DestinationFullPath)) { $BackupPath = "$TemporaryPath.bak" [System.IO.File]::Replace($TemporaryPath, $DestinationFullPath, $BackupPath) [System.IO.File]::Delete($BackupPath) } else { [System.IO.File]::Move($TemporaryPath, $DestinationFullPath) } $Succeeded = $true Write-Verbose -Message "$($MyInvocation.MyCommand): Successfully expanded: $DestinationPath." Write-Output -InputObject $DestinationPath } finally { if (-not $Succeeded -and [System.IO.File]::Exists($TemporaryPath)) { Remove-Item -LiteralPath $TemporaryPath -Force -ErrorAction Stop } } } |