Encode and decode a string
Convert the string to bytes with an explicit encoding, then call [Convert]:
$enc = [Convert]::ToBase64String([Text.Encoding]::UTF8.GetBytes("héllo wörld"))
$enc # aMOpbGxvIHfDtnJsZA==
[Text.Encoding]::UTF8.GetString([Convert]::FromBase64String($enc)) # héllo wörld
The encoding decides the output. [Text.Encoding]::Unicode is UTF-16LE, so the same two letters give a different result:
[Convert]::ToBase64String([Text.Encoding]::UTF8.GetBytes("hi")) # aGk=
[Convert]::ToBase64String([Text.Encoding]::Unicode.GetBytes("hi")) # aABpAA==
Use UTF-8 for anything you send to web APIs, config files or other languages. Use Unicode only for -EncodedCommand. If a decoded string shows a gap between every letter, it was UTF-16; the Base64 to UTF-16 tool decodes those.
For a Basic Auth header in a REST call:
$token = [Convert]::ToBase64String([Text.Encoding]::UTF8.GetBytes("user:pass"))
$headers = @{ Authorization = "Basic $token" }
$headers.Authorization # Basic dXNlcjpwYXNz
Invoke-RestMethod -Uri $url -Headers $headers
PowerShell 6+ can also build the header itself with Invoke-RestMethod -Authentication Basic -Credential $cred, which keeps the password out of a plain string.
-EncodedCommand
powershell.exe and pwsh accept a Base64 script through -EncodedCommand (short forms -enc, -e). It exists to pass scripts with quotes and special characters through cmd.exe, schedulers and remote tools without escaping problems. The text must be UTF-16LE:
$cmd = 'Write-Output "hi from base64"'
$b = [Convert]::ToBase64String([Text.Encoding]::Unicode.GetBytes($cmd))
$b
# VwByAGkAdABlAC0ATwB1AHQAcAB1AHQAIAAiAGgAaQAgAGYAcgBvAG0AIABiAGEAcwBlADYANAAiAA==
pwsh -NoProfile -EncodedCommand $b # hi from base64
Because attackers also use -enc to hide scripts from casual inspection, security tools flag it. To read one without executing it:
[Text.Encoding]::Unicode.GetString([Convert]::FromBase64String($b))
# Write-Output "hi from base64"
The PowerShell encoded command tool does both directions in the browser and never runs the script.
URL-safe Base64
There is no built-in URL-safe mode in [Convert]. Replace the characters and padding yourself:
$u = [Convert]::ToBase64String([Text.Encoding]::UTF8.GetBytes("<<???>>"))
$u.TrimEnd('=').Replace('+', '-').Replace('/', '_') # PDw_Pz8-Pg
$s = "PDw_Pz8-Pg".Replace('-', '+').Replace('_', '/')
$s = $s.PadRight($s.Length + (4 - $s.Length % 4) % 4, '=')
[Text.Encoding]::UTF8.GetString([Convert]::FromBase64String($s)) # <<???>>
PowerShell 7.5 runs on .NET 9, so [System.Buffers.Text.Base64Url]::EncodeToString($bytes) is available there as well; on 7.4 and Windows PowerShell 5.1 stick to the replacements above. See Base64 vs Base64URL for where each variant is used.
Encode and decode a file
[Convert]::ToBase64String([IO.File]::ReadAllBytes("$PWD/hello.txt")) # aGVsbG8K
[IO.File]::WriteAllBytes("$PWD/copy.txt", [Convert]::FromBase64String("aGVsbG8K"))
The $PWD/ prefix is needed because .NET methods resolve relative paths against the process working directory, and Set-Location does not change it. Starting pwsh in /tmp, running Set-Location /w and then [IO.File]::ReadAllBytes("hello.txt") throws FileNotFoundException even though the file is right there.
The cmdlet route reads bytes too, but the parameter changed between versions:
# PowerShell 7+
[Convert]::ToBase64String((Get-Content hello.txt -AsByteStream -Raw))
# Windows PowerShell 5.1
[Convert]::ToBase64String((Get-Content hello.txt -Encoding Byte -Raw))
Without -Raw, Get-Content returns one object per byte, which is very slow for big files.
Large files
ReadAllBytes loads the whole file. For hundreds of megabytes, stream it through .NET’s ToBase64Transform:
$in = [IO.File]::OpenRead((Resolve-Path big.bin))
$out = [IO.File]::Create("$PWD/big.b64")
$b64 = [Security.Cryptography.CryptoStream]::new(
$out, [Security.Cryptography.ToBase64Transform]::new(), 'Write')
$in.CopyTo($b64)
$b64.Dispose(); $in.Dispose()
Dispose the CryptoStream before using the output, or the final block and padding are missing. Our 300 KB test file produced the same string as ToBase64String. Decoding works the same way with FromBase64Transform in 'Read' mode; the Base64 in C# page has that version.
On Windows, certutil -encode in.bin out.txt and certutil -decode also work, but -encode wraps the output in -----BEGIN CERTIFICATE----- lines, so strip those before using it elsewhere.
MIME line breaks
Pass InsertLineBreaks to get 76-character lines with CRLF:
[Convert]::ToBase64String([Text.Encoding]::UTF8.GetBytes("x" * 60), 'InsertLineBreaks')
# eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4
# eHh4
Errors and validation
Invalid input raises a .NET System.FormatException, which PowerShell wraps in MethodInvocationException:
[Convert]::FromBase64String("aGk")
# Exception calling "FromBase64String" with "1" argument(s): "The input is not a
# valid Base-64 string as it contains a non-base 64 character, more than two
# padding characters, or an illegal character among the padding characters."
aGk fails because the padding is missing. The same message appears for URL-safe characters, data: prefixes and quotes copied along with the string. A simple test function:
function Test-Base64([string]$s) {
try { $null = [Convert]::FromBase64String($s); $true } catch { $false }
}
Test-Base64 "aGk=" # True
Test-Base64 "aGk" # False
When a string from a log or email refuses to decode, Repair Base64 strips quotes and line breaks and fixes padding. The Base64 errors guide explains the causes.
Version notes
[Convert]::ToBase64String/FromBase64String: every PowerShell version, including Windows PowerShell 5.1.Get-Content -AsByteStream: PowerShell 6+.-Encoding Bytewas removed there.Base64Urlclass: PowerShell 7.5+ (built on .NET 9).
FAQ
What encoding does -EncodedCommand expect?
UTF-16LE, which .NET calls [Text.Encoding]::Unicode. A command encoded from UTF-8 bytes decodes to garbage and fails with a parse error.
How do I decode a suspicious -enc command safely?
Decode it without running it: [Text.Encoding]::Unicode.GetString([Convert]::FromBase64String($b)), or paste it into the PowerShell encoded command decoder, which only displays the script.
Is there a Base64 cmdlet like ConvertTo-Base64?
Not in PowerShell itself. Some modules add one, but [Convert]::ToBase64String and [Convert]::FromBase64String work everywhere without installing anything.
Why does [IO.File]::ReadAllBytes say the file is not found?
.NET resolves relative paths against the process working directory, which Set-Location does not change. Pass (Resolve-Path file.bin) or "$PWD/file.bin" instead.