To decode Base64 on the command line in Linux, pipe the text into base64 -d: echo 'SGVsbG8sIHdvcmxkIQ==' | base64 -d prints Hello, world!. In PowerShell, call [Convert]::FromBase64String() to get bytes and turn them into text with [Text.Encoding]::UTF8.GetString(). On Windows without PowerShell, certutil -decode works on files.
echo 'SGVsbG8sIHdvcmxkIQ==' | base64 -d
[Text.Encoding]::UTF8.GetString([Convert]::FromBase64String('SGVsbG8sIHdvcmxkIQ=='))
Both print Hello, world!. I tested everything below with GNU coreutils base64 8.32 and Windows PowerShell 5.1, and kept the exact error messages so you can match what you see.
How to decode Base64 on the Linux command line
On Linux, the base64 tool from GNU coreutils decodes with -d (or --decode). The base64(1) man page describes it simply: "decode data". Without -d, the same command encodes.
It takes input three ways:
- Pipe:
echo 'SGVsbG8=' | base64 -d - Here-string (bash, zsh):
base64 -d <<< 'SGVsbG8=' - File name as an argument:
base64 -d encoded.txt
If the result is binary, such as an image, redirect it to a file:
base64 -d image.b64 > image.png
Line breaks in the input are fine. The man page says that when decoding, the input may contain newlines as well as the Base64 alphabet. That matters because encoders often wrap output, and GNU base64 itself wraps at 76 columns by default unless you pass -w 0.
openssl base64 -d is an alternative on systems that have OpenSSL but not coreutils. In my test with OpenSSL 3.5.6, echo 'SGVsbG8=' | openssl base64 -d printed Hello.
Why base64 -d says "invalid input"
base64: invalid input means GNU base64 hit a character it can't decode or a block that isn't complete. The awkward part is that it prints everything it decoded before the bad spot, then the error, and exits with status 1.
Here's what that looked like with a space in the middle:
echo 'SGVs bG8=' | base64 -d
# Helbase64: invalid input
In a script, that partial output can land in a file that looks almost right. Check the exit status ($? or set -e), not whether output appeared.
Missing padding gives a similar result. echo 'SGVsbG8sIHdvcmxkIQ' | base64 -d printed Hello, world! followed by base64: invalid input, again with exit status 1. The data was fine; the trailing == was gone.
Skipping junk with --ignore-garbage
The -i (--ignore-garbage) flag tells base64 to skip non-alphabet characters while decoding. With it, echo 'SGVs bG8=' | base64 -di printed Hello and exited 0.
My take: don't reach for -i until you've looked at the input and know the junk is harmless, like spaces from a copy-paste. It throws away anything outside the alphabet, which hides the reason a value is wrong.
How to decode Base64 in PowerShell
PowerShell has no built-in decode cmdlet, so you call the .NET method [Convert]::FromBase64String(). Microsoft's Convert.FromBase64String docs say it returns an array of 8-bit unsigned integers, which is a byte array. To get text, pick an encoding and call GetString():
$bytes = [Convert]::FromBase64String('SGVsbG8sIHdvcmxkIQ==')
[Text.Encoding]::UTF8.GetString($bytes)
For a binary file, skip GetString() and write the bytes directly:
[IO.File]::WriteAllBytes("$PWD\image.png", [Convert]::FromBase64String($b64))
Use a full path, as above. In my test, decoding iVBORw0KGgo= this way wrote an 8-byte file holding a PNG header.
UTF8 or Unicode: pick the one that matches the source
The encoding you pass to GetString() has to match how the original text was encoded. Most Base64 from web APIs, config files and Linux tools is UTF-8. PowerShell's own -EncodedCommand is different: the about_PowerShell_exe docs say that string must be UTF-16LE, which .NET calls Unicode.
Get it wrong and you don't get an error. You get nonsense. Decoding SGVsbG8sIHdvcmxkIQ== with [Text.Encoding]::Unicode printed a row of CJK-looking characters. Going the other way, SABlAGwAbABvAA== only reads as Hello with Unicode. If you see every other character as a gap or a box, switch encodings.
"Invalid length for a Base-64 char array or string"
This PowerShell error means the input length, ignoring whitespace, isn't a multiple of 4. The .NET docs list that as one of the FormatException cases, along with a non-Base64 character or more than two padding characters. Mine read:
Exception calling "FromBase64String" with "1" argument(s): "Invalid length for a Base-64 char array or string."
Unlike GNU base64, FromBase64String() ignores tabs, newlines, carriage returns and spaces, so wrapped input isn't the problem here. Missing = padding usually is.
Decoding URL-safe Base64 and JWTs in a shell
URL-safe Base64 replaces + and / with - and _, and often drops the padding, which both tools reject. RFC 4648 allows skipping the padding when the length is known some other way, and JWTs do exactly that. The fix is the same in both shells: swap the two characters back and pad to a multiple of 4.
In bash:
s=$(printf '%s' "$token_part" | tr '_-' '/+')
while [ $(( ${#s} % 4 )) -ne 0 ]; do s="$s="; done
echo "$s" | base64 -d
In PowerShell:
$s = $part.Replace('-', '+').Replace('_', '/')
$s = $s.PadRight($s.Length + (4 - $s.Length % 4) % 4, '=')
[Text.Encoding]::UTF8.GetString([Convert]::FromBase64String($s))
Both decoded the JWT-style payload eyJzdWIiOiIxMjM0NTY3ODkwIn0 to {"sub":"1234567890"}. A decoded payload like that is plain JSON; what JSON format is explains the structure if you need to read it further. If you end up doing this in a script, decoding Base64 in Python covers the same padding and URL-safe cases with less shell quoting.
Decoding Base64 with certutil in Command Prompt
On Windows without PowerShell, certutil -decode decodes a Base64 file to another file. The certutil reference gives the syntax as certutil [options] -decode InFile OutFile.
certutil -f -decode in.b64 out.txt
The -f option overwrites out.txt if it already exists. On my machine, this printed Input Length = 22, Output Length = 13 and CertUtil: -decode command completed successfully. The catch: certutil only reads files, so a string has to be saved to a file first. For a quick string, the PowerShell one-liner is less work.
Which command to use
The right command depends on your shell and whether the output is text or a file:
| Situation | Command |
|---|---|
| Linux shell, text | echo '...' | base64 -d |
| Linux, binary file | base64 -d in.b64 > out.bin |
| PowerShell, UTF-8 text | [Text.Encoding]::UTF8.GetString([Convert]::FromBase64String('...')) |
PowerShell, -EncodedCommand payload |
Same, with [Text.Encoding]::Unicode |
| Command Prompt, file | certutil -f -decode in.b64 out.bin |
| JWT or URL-safe value | Swap -_ to +/ and pad with = first |
When you just want to read one value and don't need a script, the Base64 decoder on this site handles UTF-8 text, URL-safe input, Data URIs and PEM blocks in the browser.
FAQ
What is the Linux command to decode Base64?
Use base64 -d (or base64 --decode). Pipe the text in with echo, or pass a file name, and redirect the output to a file if the result is binary.
How do I decode Base64 in PowerShell?
Call [Convert]::FromBase64String() to get bytes, then [Text.Encoding]::UTF8.GetString() to turn them into text. Use [Text.Encoding]::Unicode instead for -EncodedCommand payloads, which are UTF-16LE.
Why does base64 -d say invalid input?
The input has a character outside the Base64 alphabet, such as a space or a URL-safe - or _, or the trailing = padding is missing. Clean the input, or use -i to skip non-alphabet characters.
Can I decode Base64 in Command Prompt without PowerShell?
Yes. certutil -decode InFile OutFile decodes a Base64 file on Windows. It works on files, so save the string to a file first.