2

How do I change the below so i can use the Gzip data with [System.Convert]::ToBase64String() instead of an outfile then send THAT output(the b64) to an outfile

**I Received these answers from help on a previous post from an awesome member. It was marked as an answer but my goals were misunderstood.

Right now this does INFILE>Compress>OUTFILE, I want to do INFILE>Compress>Convert>OUTBase64

$infile = Get-Item path\to\myfiletocompress.ext
$instream = $infile.OpenRead()
$outstream = (New-Item path\to\mygzfile.gz).OpenWrite()
$gzip = [System.IO.Compression.GZipStream]::new(
    $outstream,
    [System.IO.Compression.CompressionLevel]::Optimal)
$instream.CopyTo($gzip)

$gzip.Dispose()
$outstream.Dispose()
$instream.Dispose()

And with this the reverse, I want to use Base64 for the input from a Var, and have that get converted from base64 first then get decompressed into an outfile.

This is currently INFILE>Decompress>OUTFILE I would like to INBase64>Convert>Decompress>OUTFILE

$infile = Get-Item path\to\mygzfile.gz
$instream = $infile.OpenRead()
$outstream = (New-Item path\to\myexpandedgzfile.ext -Force).OpenWrite()
$gzip = [System.IO.Compression.GZipStream]::new(
    $instream,
    [System.IO.Compression.CompressionMode]::Decompress)
$gzip.CopyTo($outstream)

$gzip.Dispose()
$outstream.Dispose()
$instream.Dispose()

The way I'm doing it now is with no compression, using IO.File ReadAllBytes, WriteAllBytes.

File>B64

[Convert]::ToBase64String([IO.File]::ReadAllBytes('anyfile.ext')) | Out-File 'anyfile.txt"

B64>File

[IO.File]::WriteAllBytes('anyfile.ext', [Convert]::FromBase64String('anyfile.txt'))

I tested the results of using gzip files instead of originals when encoding to B64 and the B64 encoded files were smaller than the originals, so this would be worth it.


EDIT: Using the below code with a temp file I can get a working result:

$filename = 'reflect_setup_free_x64.exe'
$infile = Get-Item $filename
$instream = $infile.OpenRead()
$outstream = (New-Item "$filename.gz").OpenWrite()
$gzip = [System.IO.Compression.GZipStream]::new(
    $outstream,
    [System.IO.Compression.CompressionLevel]::Optimal)
$instream.CopyTo($gzip)

$gzip.Dispose()
$outstream.Dispose()
$instream.Dispose()
[Convert]::ToBase64String([IO.File]::ReadAllBytes("$filename.gz")) | SC "$filename-encoded.txt" -NoNewline

But using the updated code in the solution gives me a larger file by min ~20%, something is wrong with it. Fails on decompression as well:

$content = Get-Content 'reflect_setup_free_x64.exe' -Raw
$outstream = [System.IO.MemoryStream]::new()
$gzip = [System.IO.Compression.GZipStream]::new(
    $outstream,
    [System.IO.Compression.CompressionLevel]::Optimal)
$bytes = [System.Text.Encoding]::UTF8.GetBytes($content)
$gzip.Write($bytes, 0, $bytes.Length)
$gzip.Dispose()

# This is the b64 gzip string
[System.Convert]::ToBase64String($outstream.ToArray()) | SC 'reflectencoded.txt'
$outstream.Dispose()

And lasty I'm stuck on the reverse command to recreate the file from b64 ->->. This works with a temp file can you show me how to add the stream to this as well? Normally I can pick apart the answers and context to proceed on my own, but i do not understand this yet..

$filename ='reflect_setup_free_x64.exe'
$encoded = GC "$filename-encoded.txt"
[IO.File]::WriteAllBytes("$filename.gz", [Convert]::FromBase64String($encoded))
$infile = Get-Item "$filename.gz"
$instream = $infile.OpenRead()
$outstream = (New-Item "$filename" -Force).OpenWrite()
$gzip = [System.IO.Compression.GZipStream]::new(
    $instream,
    [System.IO.Compression.CompressionMode]::Decompress)
$gzip.CopyTo($outstream)

$gzip.Dispose()
$outstream.Dispose()
$instream.Dispose()

LAST EDIT - For the reverse process the below was used:

$filename ='reflect_setup_free_x64.exe'
$encoded = GC "$filename-encoded.txt"
$instream = [System.IO.MemoryStream]::new(
[Convert]::FromBase64String($encoded)
)
$outstream = (New-Item "$filename" -Force).OpenWrite()
$gzip = [System.IO.Compression.GZipStream]::new(
    $instream,
    [System.IO.Compression.CompressionMode]::Decompress)
$gzip.CopyTo($outstream)

$gzip.Dispose()
$outstream.Dispose()
$instream.Dispose()

1 Answers1

3

You need to use a MemoryStream instead of a FileStream.

  • For a plain text file or hardcoded string:
# `$content` could also be a hardcoded string here
$content = Get-Content path\to\file.txt -Raw
$outstream = [System.IO.MemoryStream]::new()
$gzip = [System.IO.Compression.GZipStream]::new(
    $outstream,
    [System.IO.Compression.CompressionLevel]::Optimal)
$bytes = [System.Text.Encoding]::UTF8.GetBytes($content)
$gzip.Write($bytes, 0, $bytes.Length)

$gzip.Dispose()
$outstream.Dispose()

# This is the b64 gzip string
[System.Convert]::ToBase64String($outstream.ToArray())
  • For a binary:
$filename = 'reflect_setup_free_x64.exe'
$infile = Get-Item $filename
$instream = $infile.OpenRead()
$outstream = [System.IO.MemoryStream]::new()
$gzip = [System.IO.Compression.GZipStream]::new(
    $outstream,
    [System.IO.Compression.CompressionLevel]::Optimal)
$instream.CopyTo($gzip)

$gzip.Dispose()
$outstream.Dispose()
$instream.Dispose()

[Convert]::ToBase64String($outstream.ToArray()) |
    Set-Content "$filename-encoded.txt" -NoNewline

You need to ensure that you will be using the same encoding to read this file back, as explained in previous answer, storing a gzip b64 string in a file (specially if it is a binary) doesn't make sense, [Convert]::ToBase64String(..) should be out of this equation. Gzip b64 is mainly used for transport of data not for storage.

Santiago Squarzon
  • 41,465
  • 5
  • 14
  • 37
  • 1
    @PlayLORD-SysOp if you have doubts about how this is handled you can check the github repo I posted in my previous answer. Right now it's written in c# but if you check previous releases it was all in PowerShell and it covers any imaginable possibility for gzip compression and expansion – Santiago Squarzon Jul 16 '23 at 02:55
  • Updated the bottom of OP, something isnt working right the output is larger than if I do the steps one at a time and it wont decompress.. – PlayLORD-SysOp Jul 16 '23 at 05:03
  • 1
    @PlayLORD-SysOp thats because you're trying to use an encoding to read a binary. see edit – Santiago Squarzon Jul 16 '23 at 05:15
  • Is there a good reason not to just use binary for everything? The binary file (any filetype) option was what I needed but didnt ask for correctly on both posts, maybe my examples made it confusing. THANK YOU VERY MUCH THIS WAS THE PERFECT ANSWER – PlayLORD-SysOp Jul 16 '23 at 13:05
  • Also I added one final question to the OP (It is really the original question) I do not understand this yet. Just showing me how to change the (newly edited) last bit of code on the bottom of the OP to use a stream instead of temp file when doing the b64>binaryfile export process... Is it $instream = [System.IO.MemoryStream]::new() ?I'm kind of brute forcing my testing with lack of knowledge. I usually have success with my testing methods but not with this, The import method you showed me works great ;P – PlayLORD-SysOp Jul 16 '23 at 13:33
  • 1
    @PlayLORD-SysOp for reading a gzip b64 string you have the example from my previous answer the one that uses the `StreamReader`. For reading a binay that was encoded and compressed you can't obv since a binary is just that bytes – Santiago Squarzon Jul 16 '23 at 14:25
  • So there is no way to do the reverse? I can input from exe>compress in memory>save to b64 text.. But its not possible to go B64text>decompressinmemory>output binary or any file? – PlayLORD-SysOp Jul 16 '23 at 14:28
  • bottom of OP is updated. I cant believe I figured out the last part, its so confusing... ;P Thanks for your help! – PlayLORD-SysOp Jul 16 '23 at 14:46
  • 1
    @PlayLORD-SysOp yes, you can put it back into a new file or read its bytes for sure, in that example from the previous answer for a binary you wouldn't be using a `StreamReader`, `$outmem` would hold the bytes of the file, if you want to put it back into a file you can `$outmem.CopyTo($fileStream)` and then `$fileStream.Dipose()` – Santiago Squarzon Jul 16 '23 at 14:47
  • 1
    @PlayLORD-SysOp yup, exactly as you have it in your last edit for the binary works. if it was a plain text then you can change it to use `StreamReader` to read the content – Santiago Squarzon Jul 16 '23 at 14:48