Encoding binary files to include in scripts

Encoding binary files to include in scripts

A common question when building scripts in an RMM like Atera is, "how do I get files that my script needs to the endpoint?" For the most part, I've stored the binary files I need on an Azure file store, Dropbox folder, etc. Any plain text files, though, I embed into the script and have the script write the content out to the file. Well, why not do the same thing with the binary files?

If you're not familiar with base64, it is an encoding scheme designed for use cases, exactly like this. Base64 can encode binary data into ASCII data and then decode it back to binary. So let's look at how we can use Base64 to write a script that will configure BgInfo on endpoints.

To start, we need to create and save a BgInfo configuration using the BgInfo exe. Once you've done that, you can encode that config file into base64 with the following command:

# Read all of the bytes from the config file.
$FileContent = [IO.File]::ReadAllBytes("Full\Path\To\Default.bgi")
# Encode the data to a base64 string
$Base64String = [Convert]::ToBase64String($FileContent)
# Copy the base64 string to the clipboard
$Base64String | clip.exe

Now with the config on your clipboard, create a PowerShell script pasting the string into a variable:

$Base64Config = "CwAAAEJhY2tncm91bmQABAAAAAQAAAAAAAAACQAAAFBvc....."

Next, do the same process with the BgInfo exe:

# Read all of the bytes from the exe.
$FileContent = [IO.File]::ReadAllBytes("Full\Path\To\BgInfo.exe")
# Encode the data to a base64 string
$Base64String = [Convert]::ToBase64String($FileContent)
# Copy the base64 string to the clipboard
$Base64String | clip.exe

And add that to your script:

$Base64Exe = "TVqQAAMAAAAEAA..."

When you paste that in, your editor might weird out. Mostly because you just pasted in a single line containing ~5Mb of text. When I pasted into VSCode, I couldn't even jump to the end of the line anymore.

Now that we have the 2 binary files encoded into our script, we'll need to decode them back into binary and save the files somewhere. The process is almost the same as the encoding process, except ReadAllBytes becomes WriteAllBytes and ToBase64String becomes FromBase64String

$Config = [Convert]::FromBase64String($base64Config)
[IO.File]::WriteAllBytes("$env:TEMP/Default.bgi", $Config)

$BgInfo = [Convert]::FromBase64String($base64Exe)
[IO.File]::WriteAllBytes("$env:TEMP/BgInfo.exe", $BgInfo)

And finally, we can run BgInfo from the temp directory:

& $env:TEMP/BgInfo.exe $env:TEMP/Default.bgi /nolicprompt /timer:0

Putting it all together

Now that we have all the parts, here is the final script:

$Base64Config = "..."
$Base64Exe = "..."

[IO.File]::WriteAllBytes("$env:TEMP/bginfo.bgi", [Convert]::FromBase64String($base64Config))
[IO.File]::WriteAllBytes("$env:TEMP/bginfo.exe", [Convert]::FromBase64String($base64Exe))

& $env:TEMP/bginfo.exe $env:TEMP/bginfo.bgi /nolicprompt /timer:0

Departing Note

If you're using Atera, the script limit is 20MB for users on the Pro Plan and unlimited on other plans. Be aware of this when encoding exe files since the base64 string will be at least the same size as the executable itself.