Rants and ravings from a techy brit.
(Now hosted on DigitalOcean!)
Dark Mode?


Posted 2 years ago.

Quite a lot of the time, I either want to encode my data in Base64, or decode some data that I've already received. In this short blog post, I shall show you the basics of encoding and decoding Base64, along with two functions which you can add to the top of any .ps1 file (or your $PROFILE) and encode/decode any data on the fly with ConvertTo-Base64 and ConvertFrom-Base64.

Let's get down to it with a simple example of how to encode some text. We first need to use the System.Convert .NET class. As all System .NET classes are implicit in the namespace, I shall omit the "System." part of my .NET calls, for brevity.

To encode some text, we first need to call [Convert]::ToBase64String(). This function takes a character array, however. Luckily, we can use the built in [char] type accelerator to cast a string to an array of characters. Observe the following:

nat@home > $Object = "hello, world"
nat@home > $Object
# hello, world
nat@home > $Object.GetType().Name
# String
nat@home > [char]$Object
# InvalidArgument: Cannot convert value "String" to type "System.Char".
# Error: "String must be exactly one character long."
nat@home > [char[]]$Object
# h
# e
# l
# ...
nat@home > ([char[]]$Object).GetType().Name`
# Char[]

Char[], or "Character Array", is simply a different representation of data. Instead of a string being any number of characters, each char can only be 1 character long (hence the name). Because of this, adding them together in an array (via the [] notation) allows us to effectively convert a String as needed.

From here, it's as simple as plugging the two calls together to form one line:

nat@home > $Base64Encoded = [Convert]::ToBase64String([char[]]$Object)
nat@home > $Base64Encoded
# aGVsbG8sIHdvcmxk

Now that we've encoded some data, we should look at trying to decode it back into regular text. Luckily, we've met all of the main players already. Let's try decoding the data with [Convert]::FromBase64String(). This function takes a String instead of a Character array, so at least it's abit easier to work with. Let's give it a shot:

nat@home > $Output = [Convert]::FromBase64String($Base64Encoded)
nat@home > $Output
# 104
# 101
# 108
# ...
nat@home > $Output.Length
# 12
nat@home > $Object.Length
# 12

Oh, that doesn't look quite right. There's the correct amount of items there, but they're all numbers rather than letters. This is because the function has output an array of characters. We can decode any character pretty easily by casting it like so:

nat@home > [char]110 + [char]97 + [char]116
# nat

So, all that's left is to hook those two up in a similar manner to before, but this time switch them around:

nat@home > $Output = [char[]][Convert]::FromBase64String($Base64Encoded)
nat@home > $Output
# h
# e
# l
# ...

Damn, that still doesn't look right. Here is where I like to leverage some of Powershell's awesome operators, such as -join, to concatenate the array together:

nat@home > $Output = [char[]][Convert]::FromBase64String($Base64Encoded) -join ""
nat@home > $Output
# hello, world
nat@home > $Output.GetType().Name
# String

Here, we're using the -join operator to concatenate the letters together, however as we are providing it with a blank string as a parameter, it is joining the characters with nothing in between them, effectively creating a String for us.

As promised, here are the functions that you can use in your own scripts:

function ConvertTo-Base64 { param([Parameter(Mandatory, ValueFromPipeline)]$InputObject) [Convert]::ToBase64String([char[]]$InputObject) }
function ConvertFrom-Base64 { param([Parameter(Mandatory, ValueFromPipeline)]$InputObject) [char[]][Convert]::FromBase64String($InputObject) -join "" }

Both of these functions can be used on either side of the pipeline. See below for some examples:

nat@home > $Object = ""
nat@home > $B64Cmdlet = ConvertTo-Base64 $Object
nat@home > $B64Cmdlet
# YmxvZy5uYXRmYW4uaW8=
nat@home > $B64Pipeline = $Object | ConvertTo-Base64
nat@home > $B64Pipeline
# YmxvZy5uYXRmYW4uaW8=
nat@home > $UB64Cmdlet = ConvertFrom-Base64 $B64Pipeline
nat@home > $UB64Cmdlet
nat@home > $UB64Pipeline = $B64Cmdlet | ConvertFrom-Base64
nat@home > $UB64Pipeline

As you can see from the above, they can be used interchangably!

I hope this helped you with your Powershell journey.

Take care,