Enviar um arquivo
  1. base64hub
  2. Base64 no código
  3. PowerShell
Código

Base64 em PowerShell

O PowerShell não tem cmdlet de Base64; ele chama diretamente a classe [Convert] do .NET. O pulo do gato é escolher a codificação de texto certa. As saídas abaixo vêm do PowerShell 7.4 no Linux.

Codificar e decodificar uma string

Converta a string em bytes com uma codificação explícita e depois chame o [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

A codificação decide a saída. [Text.Encoding]::Unicode é UTF-16LE, então as mesmas duas letras dão outro resultado:

[Convert]::ToBase64String([Text.Encoding]::UTF8.GetBytes("hi"))      # aGk=
[Convert]::ToBase64String([Text.Encoding]::Unicode.GetBytes("hi"))   # aABpAA==

Use UTF-8 para tudo o que você envia para APIs web, arquivos de configuração ou outras linguagens. Use Unicode só para o -EncodedCommand. Se uma string decodificada mostra um espaço entre cada letra, ela era UTF-16; a ferramenta Base64 para UTF-16 decodifica essas strings.

Para um header Basic Auth numa chamada REST:

$token = [Convert]::ToBase64String([Text.Encoding]::UTF8.GetBytes("user:pass"))
$headers = @{ Authorization = "Basic $token" }
$headers.Authorization                                   # Basic dXNlcjpwYXNz
Invoke-RestMethod -Uri $url -Headers $headers

O PowerShell 6+ também consegue montar o header sozinho com Invoke-RestMethod -Authentication Basic -Credential $cred, o que mantém a senha fora de uma string simples.

-EncodedCommand

O powershell.exe e o pwsh aceitam um script em Base64 pelo -EncodedCommand (formas curtas -enc, -e). Ele existe para passar scripts com aspas e caracteres especiais pelo cmd.exe, por agendadores e por ferramentas remotas sem problemas de escape. O texto precisa ser 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

Como atacantes também usam o -enc para esconder scripts de uma olhada rápida, as ferramentas de segurança o sinalizam. Para ler um sem executá-lo:

[Text.Encoding]::Unicode.GetString([Convert]::FromBase64String($b))
# Write-Output "hi from base64"

A ferramenta comando codificado do PowerShell faz as duas direções no navegador e nunca executa o script.

Base64 URL-safe

O [Convert] não tem modo URL-safe embutido. Troque os caracteres e o preenchimento você mesmo:

$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))    # <<???>>

O PowerShell 7.5 roda sobre o .NET 9, então o [System.Buffers.Text.Base64Url]::EncodeToString($bytes) também está disponível nele; no 7.4 e no Windows PowerShell 5.1, fique com as trocas acima. Veja Base64 vs Base64URL para saber onde cada variante é usada.

Codificar e decodificar um arquivo

[Convert]::ToBase64String([IO.File]::ReadAllBytes("$PWD/hello.txt"))   # aGVsbG8K

[IO.File]::WriteAllBytes("$PWD/copy.txt", [Convert]::FromBase64String("aGVsbG8K"))

O prefixo $PWD/ é necessário porque os métodos do .NET resolvem caminhos relativos a partir do diretório de trabalho do processo, e o Set-Location não o altera. Iniciar o pwsh em /tmp, rodar Set-Location /w e depois [IO.File]::ReadAllBytes("hello.txt") lança FileNotFoundException, mesmo com o arquivo bem ali.

O caminho pelos cmdlets também lê bytes, mas o parâmetro mudou entre as versões:

# PowerShell 7+
[Convert]::ToBase64String((Get-Content hello.txt -AsByteStream -Raw))

# Windows PowerShell 5.1
[Convert]::ToBase64String((Get-Content hello.txt -Encoding Byte -Raw))

Sem -Raw, o Get-Content retorna um objeto por byte, o que é muito lento para arquivos grandes.

Arquivos grandes

O ReadAllBytes carrega o arquivo inteiro. Para centenas de megabytes, passe-o em fluxo pelo ToBase64Transform do .NET:

$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()

Chame o Dispose do CryptoStream antes de usar a saída, senão o último bloco e o preenchimento ficam faltando. Nosso arquivo de teste de 300 KB gerou a mesma string que o ToBase64String. A decodificação funciona do mesmo jeito com FromBase64Transform no modo 'Read'; a página Base64 em C# traz essa versão.

No Windows, certutil -encode in.bin out.txt e certutil -decode também funcionam, mas o -encode envolve a saída em linhas -----BEGIN CERTIFICATE-----, então remova-as antes de usar o resultado em outro lugar.

Quebras de linha MIME

Passe InsertLineBreaks para obter linhas de 76 caracteres com CRLF:

[Convert]::ToBase64String([Text.Encoding]::UTF8.GetBytes("x" * 60), 'InsertLineBreaks')
# eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4
# eHh4

Erros e validação

Entrada inválida gera uma System.FormatException do .NET, que o PowerShell envolve numa 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 falha porque falta o preenchimento. A mesma mensagem aparece para caracteres URL-safe, prefixos data: e aspas copiadas junto com a string. Uma função de teste simples:

function Test-Base64([string]$s) {
    try { $null = [Convert]::FromBase64String($s); $true } catch { $false }
}
Test-Base64 "aGk="    # True
Test-Base64 "aGk"     # False

Quando uma string tirada de um log ou de um e-mail se recusa a decodificar, o Reparar Base64 remove aspas e quebras de linha e corrige o preenchimento. O guia de erros de Base64 explica as causas.

Notas de versão

  • [Convert]::ToBase64String / FromBase64String: todas as versões do PowerShell, inclusive o Windows PowerShell 5.1.
  • Get-Content -AsByteStream: PowerShell 6+. O -Encoding Byte foi removido nessa versão.
  • Classe Base64Url: PowerShell 7.5+ (sobre o .NET 9).

Perguntas frequentes

Que codificação o -EncodedCommand espera?

UTF-16LE, que o .NET chama de [Text.Encoding]::Unicode. Um comando codificado a partir de bytes UTF-8 decodifica para lixo e falha com erro de parsing.

Como decodificar com segurança um comando -enc suspeito?

Decodifique sem executar: [Text.Encoding]::Unicode.GetString([Convert]::FromBase64String($b)), ou cole no decodificador de comandos codificados do PowerShell, que só exibe o script.

Existe um cmdlet de Base64, como ConvertTo-Base64?

Não no próprio PowerShell. Alguns módulos acrescentam um, mas [Convert]::ToBase64String e [Convert]::FromBase64String funcionam em qualquer lugar sem instalar nada.

Por que o [IO.File]::ReadAllBytes diz que o arquivo não existe?

O .NET resolve caminhos relativos a partir do diretório de trabalho do processo, que o Set-Location não altera. Passe (Resolve-Path file.bin) ou "$PWD/file.bin".

Continue lendo