ComPrS.psm1
### --- PUBLIC FUNCTIONS --- ### #Region - Compress-String.ps1 function Compress-String { <# .SYNOPSIS Accepts string input, compresses it using the DEFLATE algorithm, and returns the bytes encoded in base64 .DESCRIPTION Provides little benefit against short strings but could be useful for large string values, multi-line files, or script blocks. .PARAMETER String String input for compressing. If multiple strings are passed through the pipeline they will be included in the compression together and output as a single base64 string. If piping file content from Get-Content make sure to use the -Raw parameter with Get-Content to avoid sending empty strings. .PARAMETER Algorithm Optionally specify a compression algorithm. Choices are DEFLATE or Brotli however Brotli is only available on PS Version 6.1 or newer. .PARAMETER NoPreserve By default when given an array of strings Compress-String will attempt to preserve formatting by joining each string together before compressing it. This will bring over new line characters and blank lines so that when later expanded it will look the same. If you'd prefer not to do that supply the -NoPreserve switch and each string will be streamed in to the compression writer. #> [Cmdletbinding()] Param ( [Parameter(ValueFromPipeline)] [String[]]$String, [ValidateSet('Deflate','Brotli')] [String]$Algorithm = $(Set-CompressionAlgorithm), [Switch]$NoPreserve ) begin { if ($PSVersionTable.PSVersion -lt [Version]'6.1' -and $Algorithm -eq 'Brotli') { Write-Warning "PSVersion is <6.1. Brotli compression not available. Reverting to Deflate" $Algorithm = 'Deflate' } Write-Verbose "Algorithm: $Algorithm" $MemoryStream = [System.IO.MemoryStream]::new() $CompressionStream = switch ($Algorithm) { 'Deflate' { [System.IO.Compression.DeflateStream]::new($MemoryStream, [System.IO.Compression.CompressionMode]::Compress) } 'Brotli' { [System.IO.Compression.BrotliStream]::new($MemoryStream, [System.IO.Compression.BrotliCompressionOptions]@{Quality=11}) } } $StreamWriter = [System.IO.StreamWriter]::new($CompressionStream) $StringLength = 0 if ($MyInvocation.ExpectingInput) { $PipeLineStrings = [System.Collections.ArrayList]::new() } } process { if ($NoPreserve) { foreach ($InputString in $String) { try { $StreamWriter.Write($InputString) $StringLength += $InputString.Length } catch { Write-Error $_ } } } else { if ($MyInvocation.ExpectingInput) { [Void]$PipeLineStrings.Add($String) } else { try { $InputString = $String | Out-String $StreamWriter.Write($InputString) $StringLength += $InputString.Length } catch { Write-Error $_ } } } } end { if ($MyInvocation.ExpectingInput) { try { $InputString = $PipelineStrings | Out-String $StreamWriter.Write($InputString) $StringLength += $InputString.Length } catch { Write-Error $_ } } try { $StreamWriter.Close() $Base64String = [System.Convert]::ToBase64String($MemoryStream.ToArray()) $Base64String } catch { Write-Error $_ } $MemoryStream.Dispose() Write-Verbose "Total string input length: $StringLength" Write-Verbose "Total string output length: $($Base64String.Length)" } } #Region - ConvertTo-HereString.ps1 function ConvertTo-HereString { <# .SYNOPSIS Convert a long single string in to a multi line here-string. .DESCRIPTION When working with Compress-String the output can be very long depending on what you're compressing. If you'd like to store this compressed string in a script it might look nicer if it ran vertically instead of just horizontally. This function will turn a single tring in to a multi line here-string of a given width. .PARAMETER String The long string to convert in to a here string. .PARAMETER Width optionally specify the character width for the here string. Defaults to 160. #> [Cmdletbinding()] param ( [String]$String, [Int64]$Width = 160 ) $Regex = [Regex]"(.{$Width})" $StringChunks = $String -split $Regex | Where-Object {$_} Write-Verbose "Original string length: $($String.Length)" Write-Verbose "Here-string lines: $($StringChunks.count)" $StringChunks | Out-String } #Region - Expand-String.ps1 function Expand-String { <# .SYNOPSIS Accepts string input, expands it using the DEFLATE algorithm, and returns the bytes converted to string .DESCRIPTION For expanding the base64 encoded output from the Compress-String function. .PARAMETER String String input for expanding. .PARAMETER Algorithm Optionally specify a compression algorithm. Choices are DEFLATE or Brotli however Brotli is only available on PS Version 6.1 or newer. #> Param ( [Parameter(Mandatory)] [String]$String, [ValidateSet('Deflate','Brotli')] [String]$Algorithm = $(Set-CompressionAlgorithm) ) if ($PSVersionTable.PSVersion -lt [Version]'6.1' -and $Algorithm -eq 'Brotli') { Write-Warning "PSVersion is <6.1. Brotli compression not available. Reverting to Deflate" $Algorithm = 'Deflate' } try { $Bytes = [System.Convert]::FromBase64String($String) $MemoryStream = [System.IO.MemoryStream]::new() $MemoryStream.Write($Bytes, 0, $Bytes.Length) [Void]$MemoryStream.Seek(0, 0) $DecompressionStream = switch ($Algorithm) { 'Deflate' { [System.IO.Compression.DeflateStream]::new($MemoryStream, [System.IO.Compression.CompressionMode]::Decompress) } 'Brotli' { [System.IO.Compression.BrotliStream]::new($MemoryStream, [System.IO.Compression.CompressionMode]::Decompress) } } $StreamReader = [System.IO.StreamReader]::new($DecompressionStream) $StreamReader.ReadToEnd() } catch { Write-Error $_ } $MemoryStream.Dispose() $DecompressionStream.Dispose() $StreamReader.Dispose() } ### --- PRIVATE FUNCTIONS --- ### #Region - Set-CompressionAlgorithm.ps1 function Set-CompressionAlgorithm { param () # detect which version of Powershell, and therefore .NET, to set a default compression algorithm if ($PSVersionTable.PSVersion -lt [Version]'6.1') { return "Deflate" } else { return "Brotli" } } |