Você tem que lidar com o formato Base64? Então esse site é perfeito para você! Use o nosso ferramenta online super útil para codificar ou decodificar os seus dados.

Codificação Base64 em PowerShell: um guia completo

Você tem uma string, um arquivo, um certificado ou um token, e o outro lado do fio quer isso como uma longa sequência de letras e dígitos: imprimível, colável num e-mail, numa URL ou num arquivo de configuração, sem um único byte binário para quebrar o transporte. Isso é Base64. É uma tradução, não uma compressão e nem um cadeado: três bytes de entrada viram quatro caracteres de saída, então o texto que você envia fica cerca de 33% maior que o que o originou, usando um alfabeto de 64 caracteres mais o sinal de igual como padding no final.

A página inicial deste site cobre o alfabeto, as contas de bits e as variantes em detalhe. Este artigo cobre a direção de codificação do lado do PowerShell: o único método .NET que você vai chamar, o passo que falta e que derruba todo mundo no primeiro script, as convenções de embrulho de linha que diferem por protocolo, o alfabeto seguro para URL, e os uns poucos trabalhos reais onde codificar no PowerShell recompensa o cuidadoso e pune o descuidado.

O método e o passo que falta

O PowerShell não vem com nenhum cmdlet próprio de Base64. O trabalho é feito por um método que faz parte do framework .NET desde o .NET Framework 1.1 em 2003, três anos antes do próprio PowerShell ser lançado:

$bytes = [System.Text.Encoding]::UTF8.GetBytes("Hello")
[System.Convert]::ToBase64String($bytes)
# SGVsbG8=

Essa é a API inteira: um array de bytes entra, uma string sai, em todo PowerShell em qualquer sistema operacional, porque ele é simplesmente .NET. O passo que falta é a primeira linha do exemplo, e é onde iniciantes perdem a sua primeira hora. O método não aceita a sua string. Ele aceita bytes, e a pergunta "quais bytes a minha string significa" é uma pergunta de codificação que só você pode responder. Aqui está o contrato dos overloads que você realmente pode chamar do PowerShell:

O que você passa O que você recebe
byte[] Uma linha longa de Base64 padrão, com padding de = onde o comprimento exigir
byte[] mais InsertLineBreaks Os mesmos dados, quebrados a cada 76 caracteres com CRLF entre as linhas
byte[], offset, count Apenas o pedaço do array que foi pedido, codificado
Uma string como "Hello" Uma exceção de conversão. O PowerShell não consegue transformar uma string em um array de bytes sozinho
$null Um ArgumentNullException, embrulhado para você num MethodInvocationException

Repare no que não está nessa tabela: não existe um overload que diga "codifique este texto". Codificar texto no PowerShell é sempre um processo de duas etapas. Você decide a codificação, você produz os bytes, e só então o método Base64 entra na conversa. Mantenha essas duas decisões visivelmente separadas no script, porque a segunda é invisível e a primeira é onde os bugs moram.

Codificando texto: escolha a codificação primeiro

O padrão seguro para qualquer coisa que cruze a internet moderna é UTF-8. Web APIs, JSON, JWTs, tudo que um navegador ou um servidor escreveu na última década vai esperar bytes UTF-8 por baixo do Base64, e o padrão de duas etapas é o hábito que você quer criar:

$text = "Hello, PowerShell!"
$bytes = [System.Text.Encoding]::UTF8.GetBytes($text)
$encoded = [System.Convert]::ToBase64String($bytes)
# SGVsbG8sIFBvd2VyU2hlbGwh

Quando você recorre a uma codificação diferente, geralmente está atendendo a um sistema legacy, e a tabela abaixo é o guia prático:

Codificação Use quando Se você escolher a errada
UTF8 Web APIs, JSON, JWTs, tudo o que é moderno. A escolha padrão O decodificador do outro lado vê mojibake no lugar do seu texto
Unicode (UTF-16LE) O consumidor é um componente Windows ou .NET que codifica strings .NET, ou -EncodedCommand Seu payload fica o dobro do tamanho que o consumidor espera, e cheio de surpresas
ASCII Protocolos clássicos de 7 bits, como credenciais HTTP Basic Qualquer coisa acima do valor 127 é substituída antes de a codificação acontecer
Latin1 Sistemas europeus legacy anteriores ao UTF-8 Um byte por caractere, e todo caractere que não é Latin-1 vira um ponto de interrogação

Um truque útil de depuração funciona nas duas direções: o padding e o comprimento do Base64 te contam quantos bytes foram codificados, e a aparência do texto decodificado te diz de qual mundo de dois bytes ou de um byte ele veio. Um payload suspeitamente par no tamanho e cheio de caracteres normais alternando com caracteres com aparência de espaço é geralmente UTF-16 vestindo uma fantasia UTF-8, ou o contrário.

A surpresa do UTF-16

O PowerShell armazena strings como UTF-16 internamente, e esse fato vaza para o trabalho com Base64 num lugar específico e muito comum: você escreve o Base64 para um consumidor que é ele mesmo um componente .NET ou do Windows, e codifica com Unicode porque é disso que as strings .NET são feitas. É um instinto certo para alguns consumidores e um erro que dobra o tamanho para todos os demais. Os mesmos quatro caracteres visíveis, duas codificações:

$same = "Café"
[System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes($same))
# Q2Fmw6k=  cinco bytes
[System.Convert]::ToBase64String([System.Text.Encoding]::Unicode.GetBytes($same))
# QwBhAGYA6QA=  oito bytes

O mesmo texto, o dobro do tamanho, e as duas strings não são intercambiáveis: um consumidor que espera uma e recebe a outra não vai falhar com estrondo; ele vai só ler lixo. A regra que impede isso de te morder é tratar a codificação como parte do protocolo, não como um detalhe local. Se o sistema receptor é um navegador, uma REST API ou um servidor moderno, é UTF-8, a menos que a documentação diga o contrário. Se é o próprio host do PowerShell via -EncodedCommand, ou uma string .NET num pipeline só do Windows, é UTF-16LE. Quando o protocolo não diz, pergunte do outro lado com o que ele vai chamar GetString, porque essa é a pergunta que realmente decide.

Números, bytes e tudo o mais

O método é declarado para receber um array de bytes, mas a conversão de tipo do PowerShell é generosa sobre o que conta como um, e conhecer as arestas te salva de surpresas:

[System.Convert]::ToBase64String([byte[]](1, 2, 3, 250, 251))
# AQID+vs=
[System.Convert]::ToBase64String([char[]]"Café")
# Q2Fm6Q==  um byte por caractere, o valor do caractere como número
[System.Convert]::ToBase64String([int[]](72, 101, 108, 108, 111))
# SGVsbG8=
[System.Convert]::ToBase64String(123)
# ew==  um número único é aceito onde um array inteiro seria esperado

Duas arestas naquele bloco merecem atenção. Arrays de caracteres convertem um byte por caractere usando o valor numérico do caractere, o que para texto latino é exatamente o que os sistemas legacy que usam esse truque esperam, e para qualquer coisa além disso produz silenciosamente os bytes errados. Um inteiro maior que 255 é a aresta que falha com estrondo: a conversão de byte do PowerShell se recusa a valores fora de 0-255 com uma exceção, então 256 para o script no cast em vez de corromper seus dados em silêncio. Se a sua fonte são números, faça o cast explícito: [byte[]](1, 2, 3) diz exatamente o que significa.

Passar uma string para o método e você recebe o mesmo tratamento com estrondo por um motivo diferente: não há como saber quais bytes uma string significa, então o motor de conversão do PowerShell desiste. Passar $null e o .NET lança exceção antes de fazer qualquer coisa. Os dois são comportamento correto, e os dois são o motivo pelo qual o padrão de duas etapas da primeira seção é o único padrão que vale a pena ter.

Embrulho de linhas: 76, 64 e nenhuma

Por padrão o codificador produz uma linha longa, não importa quantos dados você dê. Para um arquivo de alguns kilobytes, tudo bem. Para dados que serão lidos por um humano, colados num e-mail, ou comparados num diff de controle de versão, um muro de oito milhões de caracteres é um problema prático, e a convenção é embrulhar. O PowerShell e os protocolos que ele atende conhecem três larguras, e elas não são intercambiáveis:

Largura Quem espera Final de linha
76 caracteres MIME, e-mail e a maioria dos transportes de texto. O padrão de InsertLineBreaks CRLF
64 caracteres Arquivos PEM: certificados, chaves privadas e o resto da família -----BEGIN LF por convenção
Nenhuma APIs, tokens, arquivos de configuração, qualquer coisa onde o payload é processado por máquina Nenhuma linha

O embrulho embutido é uma mudança de um parâmetro, e é o que você quer para payloads estilo e-mail:

$text = "The quick brown fox jumps over the lazy dog. Base64 output arrives wrapped at different widths depending on who is reading it."
$wrapped = [System.Convert]::ToBase64String(
  [System.Text.Encoding]::UTF8.GetBytes($text),
  [Base64FormattingOptions]::InsertLineBreaks)
# 76 caracteres por linha, CRLF entre elas, exatamente como o MIME espera

O PEM é a exceção ao embutido, porque o OpenSSL e todo o ecossistema -----BEGIN embrulham a cada 64 caracteres, e nenhuma flag do .NET produz essa largura. O loop é curto e é a receita padrão:

$der = [System.IO.File]::ReadAllBytes("./certificate.der")
$b64 = [System.Convert]::ToBase64String($der)
$lines = for ($i = 0; $i -lt $b64.Length; $i += 64) {
  $b64.Substring($i, [Math]::Min(64, $b64.Length - $i))
}
$pem = @("-----BEGIN CERTIFICATE-----") + @($lines) + @("-----END CERTIFICATE-----")
Set-Content -Path "./certificate.pem" -Value ($pem -join "`n")

O motivo de a largura importar é que os grupos de quatro caracteres do Base64 não respeitam quebras de linha, então um decodificador pode ignorar as quebras por completo ou pode impô-las. O decodificador que este site usa as ignora, mas consumidores estritos, e existem muitos deles nos mundos de certificados e e-mail, tratam uma quebra inesperada como caractere estrangeiro e rejeitam o payload. Quando você escolhe uma largura, está fazendo um contrato com o consumidor, e vale um comentário no script dizendo com quem você está contratando.

base64url: dois caracteres e uma decisão de padding

O + e o / do Base64 padrão só são legais dentro de uma URL depois de percent-encoding, e o padding de iguais se lê como um separador de campos. Então o RFC 4648 definiu um alfabeto seguro para URL e nome de arquivo: os mesmos 64 caracteres, com a exceção de que o + vira hífen e o / vira sublinhado, e o padding geralmente é descartado porque o comprimento dos dados o torna desnecessário. Cada token de API e JWT que você já manuseou é escrito nesta variante, que o padrão insiste em chamar de base64url e não só base64.

O codificador padrão do PowerShell produz o alfabeto padrão, então a conversão para base64url é duas trocas de caracteres e uma decisão de padding:

$bytes = [System.Text.Encoding]::UTF8.GetBytes("Париж encoded 大阪")
$standard = [System.Convert]::ToBase64String($bytes)
$standard
# 0J/QsNGA0LjQtiBlbmNvZGVkIOWkp+mYqg==  o alfabeto padrão, padding incluído
$url = $standard.Replace("+", "-").Replace("/", "_").TrimEnd("=")
$url
# 0J_QsNGA0LjQtiBlbmNvZGVkIOWkp-mYqg  a forma segura para URL, padding removido

Remover o padding é seguro no mundo base64url porque o consumidor recalcula o que o padding seria a partir do comprimento da string. Isso não é verdade em todo lugar, então tome a decisão explicitamente: descarte o padding para tokens, segmentos de JWT e embutimento em URL, mantenha-o para qualquer coisa que alimente um consumidor estrito do alfabeto padrão, e anote qual você escolheu. O runtime do .NET realmente fornece uma classe dedicada para este alfabeto, System.Buffers.Text.Base64Url (adicionada no .NET 9), com métodos construídos em torno de parâmetros ReadOnlySpan<T>. O PowerShell atual (7.4 e posteriores, uma vez que roda numa versão do .NET que fornece a classe) pode, na verdade, chamá-los diretamente - [System.Buffers.Text.Base64Url]::EncodeToString($bytes) funciona hoje, porque o method binder agora converte um argumento de array para span implicitamente - mas a troca dos dois caracteres continua sendo a que você deve usar sempre que o script precisa rodar no Windows PowerShell 5.1, numa versão antiga do PowerShell 7.x, ou num host com um runtime pré-.NET-9, e ela funciona em cada uma dessas versões.

Cunhando um JWT

Um JSON Web Token é o uso real de destaque do base64url, e também é um bom teste completo do pipeline de codificação, porque um JWT é três segmentos codificados unidos por pontos: o header, o payload e a assinatura. Os dois primeiros são JSON compacto em base64url, e o terceiro é a saída binária de um hash sobre o texto exato dos dois primeiros. Aqui está um token HS256 completo construído no PowerShell, do início ao fim:

$header = @{ alg = "HS256"; typ = "JWT" } | ConvertTo-Json -Compress
$payload = @{ sub = "1234567890"; name = "John Doe"; iat = 1516239022 } | ConvertTo-Json -Compress
function UrlEncode64([byte[]]$bytes) {
  $standard = [System.Convert]::ToBase64String($bytes).TrimEnd("=")
  return $standard.Replace("+", "-").Replace("/", "_")
}
$left = (UrlEncode64 ([System.Text.Encoding]::UTF8.GetBytes($header))) + "." + (UrlEncode64 ([System.Text.Encoding]::UTF8.GetBytes($payload)))
$hmac = [System.Security.Cryptography.HMACSHA256]::new([System.Text.Encoding]::UTF8.GetBytes("secret"))
$signature = UrlEncode64 ($hmac.ComputeHash([System.Text.Encoding]::UTF8.GetBytes($left)))
$jwt = $left + "." + $signature
# eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE1MTYyMzkwMjIsInN1YiI6IjEyMzQ1Njc4OTAiLCJuYW1lIjoiSm9obiBEb2UifQ.6MWZy9doHbfyomJd4soTRUQft7PmRM2EyxxT3SLoiyE
#  no PowerShell 7.4; a ordem interna das chaves dos segmentos - e portanto a assinatura - pode variar por versão

Olhe para o segmento de assinatura: uma sequência do alfabeto base64url, aquele onde o + apareceria como hífen e o / como sublinhado. Três coisas sobre aquele exemplo vão te salvar de incidentes de produção. Primeira, a assinatura é calculada sobre o texto JSON exato, incluindo a ordem das chaves e os espaços, então o JSON que você assina e o JSON contra o qual você verifica precisam ser iguais byte a byte. O ConvertTo-Json do PowerShell decide a ordem das chaves por você, e é algo que você não controla, então não reordene manualmente os segmentos de um token nem reformate-os entre assinar e verificar. Segunda, -Compress não é cosmético: um token cujo header ou payload contém um único espaço é um token que nunca vai verificar contra uma implementação compatível, porque a forma padrão é compacta. Terceira, o timestamp iat é segundos desde a epoch Unix, e um payload construído a partir do Get-Date sem converter vai ficar anos fora da faixa. A direção de decodificação, espiar um token cunhado por outra pessoa, é coberta no artigo relacionado no site irmão.

Arquivos e o stream de bytes

Arquivos são o payload mais comum de todos, e o pipeline é curto. Leia o arquivo como bytes, codifique, escreva texto. As duas linhas que importam são a leitura, que precisa ser uma leitura de bytes, e a escrita, que geralmente não deve adicionar um newline no final:

$bytes = [System.IO.File]::ReadAllBytes("./photo.png")
$encoded = [System.Convert]::ToBase64String($bytes)
Set-Content -Path "./photo.b64" -Value $encoded -NoNewline
$encoded.Length
# o tamanho do texto que você está prestes a enviar

Dois avisos práticos. O primeiro é aritmética: o Base64 aumenta tudo, e para um arquivo de 10 megabytes o texto que você envia fica em uns 13,4 megabytes. Se o transporte tiver um limite de tamanho, ou se este texto for para o corpo de um e-mail ou para uma URL, faça as contas antes de codificar, não depois do erro. O segundo é o newline no final: Set-Content adiciona um por padrão, e embora o decodificador usado por este site e a maioria dos decodificadores modernos o ignorem, alguns consumidores estritos não. -NoNewline não te custa nada e remove a dúvida.

O PowerShell 6 e os mais novos oferecem uma segunda leitura que fica na linguagem: Get-Content -AsByteStream -Raw retorna o arquivo como um único array de bytes numa chamada, o que é uma alternativa arrumada ao ReadAllBytes do .NET e se comporta de forma idêntica para este fim. No Windows PowerShell 5.1, que não tem -AsByteStream, a leitura do .NET é a única opção, e é a que se comporta do mesmo jeito em toda versão do shell.

Certificados: do PEM e do PFX para texto

Certificados são os cidadãos de codificação mais pesados das operações do dia a dia, porque deploys adoram carregá-los como texto. Um certificado PEM é um corpo Base64 embrulhado entre linhas de armadura, e a receita da seção de embrulho é o export inteiro:

$cert = [System.Security.Cryptography.X509Certificates.X509Certificate2]::new([System.IO.File]::ReadAllBytes("./certificate.der"))
$cert.Subject
# CN=example.org
$b64 = [System.Convert]::ToBase64String($cert.RawData)
# uma linha longa da forma binária do certificado

O formato PFX é o outro cavalo de batalha: um único arquivo binário guardando o certificado junto com a sua chave privada, e é por isso que ele é o formato que você mais encontra por aí vagando como texto Base64 dentro de scripts de deploy e lojas de configuração. Codificar um é o pipeline simples de arquivo da seção anterior, e a direção de leitura no PowerShell 7 é questão de um cmdlet:

$pfxBytes = [System.IO.File]::ReadAllBytes("./certificate.pfx")
$pfxB64 = [System.Convert]::ToBase64String($pfxBytes)
# a forma de texto do pacote, pronta para um arquivo de configuração
Get-PfxCertificate -FilePath "./certificate.pfx" -Password (ConvertTo-SecureString "secret" -AsPlainText -Force)
# o certificado vivo, sem decodificação manual

Uma frase de segurança, dita sem rodeios porque o Base64 convida à suposição contrária: um PFX em Base64 é uma chave privada em texto. A codificação muda a forma do segredo e nada sobre o seu sigilo, então um PFX Base64 colado numa janela de chat, num chamado ou num commit é uma chave privada colada numa janela de chat, num chamado ou num commit. Trate a forma de texto com exatamente o mesmo cuidado que a forma binária recebe, e prefira a loja de certificados ou um gerenciador de segredos a qualquer uma das duas.

Basic Auth, data URIs e os hábitos antigos

Base64 é mais velho que o documento de padrão que o batizou. A família de RFCs do MIME de 1996 o colocou no e-mail, e a autenticação HTTP Basic o colocou em toda troca de headers na web dos primeiros tempos, onde o cliente ainda codifica o par de credenciais como uma única string Base64:

$credential = [System.Text.Encoding]::UTF8.GetBytes("alice:s3cret!")
[System.Convert]::ToBase64String($credential)
# YWxpY2U6czNjcmV0IQ==
# enviado como: Authorization: Basic YWxpY2U6czNjcmV0IQ==

O alfabeto padrão é o certo aqui, com + e / inclusos, porque um header não é uma URL e não precisa do alfabeto seguro. O mesmo mecanismo aparece nos data URIs, a maneira pela qual um documento embute o próprio binário inline, e a forma é um prefixo literal mais o Base64 padrão dos bytes:

$dataUri = "data:application/octet-stream;base64," + [System.Convert]::ToBase64String([byte[]](1, 2, 3, 250, 251))
# data:application/octet-stream;base64,AQID+vs=

Os dois hábitos valem a pena conhecer menos como coisas que você vai construir e mais como coisas que você vai encontrar: quando um header ou um link contém uma longa sequência Base64, esses dois formatos são os primeiros a checar, e os dois estão a uma decodificação simples do que dizem. O que é o ponto do formato, e o motivo pelo qual o lado de decodificação deste site existe.

Comandos codificados e a caixa de ferramentas do Windows

O PowerShell carrega um motivo embutido para codificar desde a versão 1.0: o parâmetro -EncodedCommand do próprio host. Você entrega ao pwsh uma string Base64, ele decodifica os bytes como UTF-16LE, e o resultado roda como um comando. O propósito documentado são comandos que brigam com as aspas do shell externo, e o lado da codificação são duas linhas:

$command = "Write-Host 'Hello from the encoded side'"
$encoded = [System.Convert]::ToBase64String([System.Text.Encoding]::Unicode.GetBytes($command))
# VwByAGkAdABlAC0ASABvAHMAdAAgACcASABlAGwAbABvACAAZgByAG8AbQAgAHQAaABlACAAZQBuAGMAbwBkAGUAZAAgAHMAaQBkAGUAJwA=
pwsh -NoProfile -EncodedCommand $encoded
# Hello from the encoded side

Leia a linha de codificação com atenção, porque é a que todo mundo erra: o payload deve ser UTF-16LE, que é a codificação Unicode, não UTF-8. Codifique com a errada e o host decodifica seus bytes como UTF-16LE mesmo assim e executa um comando feito de mojibake, produzindo um erro que é um retrato perfeito do erro. O artigo de decodificação cobre aquela falha em detalhes, e a correção deste lado é uma única palavra: Unicode.

Fora da linguagem, as ferramentas nativas carregam cada uma a sua própria decisão silenciosa de codificação. No Windows, certutil -encode infile outfile.b64 produz um arquivo Base64 padrão com as linhas de armadura que o PEM espera, -f sobrescreve uma saída existente, e a flag que vale a pena lembrar é -unicodetext, que faz o certutil escrever o arquivo de saída em Unicode (segundo a documentação da Microsoft: "Escreve o arquivo de saída em Unicode") - um único switch que esconde uma decisão de codificação. No Linux a utilidade clássica é base64 -w 0 file, onde o -w 0 é a parte que sustenta tudo: sem ele o base64 do GNU embrulha a cada 76 caracteres e te entrega um arquivo estilo MIME quando você queria uma linha. No macOS a variante BSD não precisa de flag nenhuma, porque emite uma linha ininterrupta por padrão.

Codificando quando a saída é enorme

Para tamanhos do dia a dia, o pipeline de ler tudo e codificar tudo é o rápido e o simples, e é o certo até o arquivo ficar grande demais para guardar na memória com conforto, ou os dados chegarem aos pedaços de um download ou de um socket. Então a ferramenta documentada é o par em streaming: System.Security.Cryptography.ToBase64Transform embrulhado num CryptoStream, onde você escreve bytes crus e sai texto Base64, com apenas um pequeno buffer vivo em qualquer momento:

$source = [System.IO.File]::OpenRead("./photo.png")
$destination = [System.IO.File]::Create("./photo.b64")
$transform = [System.Security.Cryptography.ToBase64Transform]::new()
$stream = [System.Security.Cryptography.CryptoStream]::new($destination, $transform, [System.Security.Cryptography.CryptoStreamMode]::Write)
$buffer = New-Object byte[] 65536
while (($read = $source.Read($buffer, 0, $buffer.Length)) -gt 0) {
  $stream.Write($buffer, 0, $read)
}
$stream.Dispose()
$source.Dispose()
$destination.Dispose()

Uma diferença do método de uma vez única vale anotar: o stream produz uma linha contínua sem nenhum embrulho, não importa o quão grande seja a entrada. Um decodificador que ignora espaço em branco não se importa, mas se o destino final é um arquivo PEM, rode o loop de 64 colunas da seção de embrulho sobre o resultado depois. E em C# a forma padrão é o mesmo padrão ToBase64Transform + CryptoStream que você vê no artigo de C#; o PowerShell o dirige diretamente, como acima.

Onde os payloads codificados dão errado

  • Codificando a string, não os bytes. ToBase64String("Hello") lança uma exceção de conversão, que é o método te dizendo que a primeira decisão, a codificação, não foi tomada. Deixe ela visível no script e o erro desaparece.
  • UTF-16 onde UTF-8 foi prometido. O payload fica o dobro do tamanho esperado e o consumidor lê lixo. A codificação é parte do protocolo, e para quase todo fio da internet moderna o protocolo diz UTF-8.
  • A leitura do 5.1. O Windows PowerShell 5.1 lê um arquivo de texto sem BOM com a code page ANSI da máquina antes do seu script vê-lo, então um arquivo de origem UTF-8 pode ser corrompido antes do passo de codificação. No 5.1, leia texto com uma leitura UTF-8 explícita e cheque os primeiros caracteres do resultado.
  • A largura de embrulho errada. O MIME quer 76, o PEM quer 64, as APIs querem nenhuma, e um consumidor estrito trata uma quebra de linha inesperada como caractere estrangeiro. Escolha a largura a partir do consumidor e diga isso num comentário.
  • Padding do lado errado da troca. Descartar os sinais de igual é correto para tokens base64url e errado para um consumidor que espera padding padrão. A troca de alfabeto e a decisão de padding são duas escolhas, não uma.
  • Reformatando o que você assinou. A assinatura de um JWT cobre o texto JSON exato, incluindo ordem das chaves e espaços. Reordene as claims ou adicione um espaço e o token para de verificar, sem nenhuma mensagem de erro perto da causa.
  • Valores além de 255. Converter um inteiro em byte lança exceção em vez de estourar, então 256 para o script no cast. Se os seus dados de origem são números, faça o cast explicitamente e deixe um erro ser um erro que você vê.
  • Acreditando na fantasia. Base64 não é criptografia e nem compressão: é uma tradução que aumenta os dados em um terço. Um segredo em Base64 é um segredo em texto puro, e um arquivo em Base64 é um arquivo que precisa de 33% mais espaço.

Regras para codificadores em quem você pode confiar

  • Produza os bytes com intenção. A primeira linha de qualquer script de codificação deve ser um GetBytes explícito ou uma leitura de bytes, nunca a esperança de que o PowerShell converta uma string nos bytes certos.
  • Dê nome ao alfabeto e à largura num comentário ao lado do código que faz a escolha: padrão ou base64url, embrulhado em 76, 64 ou não. O consumidor é a pessoa que lê o script daqui a seis meses, e essa pessoa é você.
  • Escreva o arquivo de texto com -NoNewline, a menos que o consumidor espere especificamente uma quebra no final, e escolha o final de linha (LF ou CRLF) do jeito que a documentação do consumidor espera.
  • Teste a ida e volta enquanto constrói: codifique, decodifique, compare os bytes. Um Compare-Object de trinta segundos sobre os dois arrays de bytes pega erros de codificação, erros de embrulho e erros de ordem de bytes todos de uma vez, enquanto a causa ainda está fresca.
  • Logue tamanhos, não payloads. A contagem de bytes antes e a contagem de caracteres depois devem ficar numa proporção de uns 1,33, e quando não ficarem, a diferença de tamanho te diz onde olhar, sem o log nunca conter os dados.

Como o PowerShell herdou o seu codificador

A história mais curta e verdadeira da codificação Base64 no PowerShell é que o PowerShell nunca escreveu um. O método que você chama, Convert.ToBase64String, foi lançado com o .NET Framework 1.1 em 2003, e todo PowerShell desde a versão 1.0, em novembro de 2006, simplesmente expôs o .NET em que roda. O projeto se chamava Monad enquanto era construído, foi mostrado publicamente pela primeira vez na Professional Developers Conference em outubro de 2003, e na hora do lançamento o codificador .NET que ele embrulha já tinha três anos e carregava tráfego web.

O formato foi padronizado no mesmo ano em que o shell saiu. O RFC 4648, publicado em outubro de 2006, fixou o alfabeto, as regras de padding, a estriteza da decodificação e a variante base64url, e ele ainda descreve exatamente o comportamento que o par do .NET implementa. Os RFCs do MIME que vieram antes, em 1996, já tinham colocado o embrulho de 76 caracteres no e-mail, e é por isso que essa largura é o padrão de InsertLineBreaks até hoje. Quando o PowerShell ficou open-source e multiplataforma em agosto de 2016 como PowerShell Core, o codificador veio junto para o Linux e o macOS sem mudanças, porque não havia nada para mudar.

O que mudou depois aconteceu no .NET, e em grande parte fora do alcance do PowerShell. O runtime ganhou helpers Base64 mais rápidos, baseados em span, nas versões recentes, incluindo a classe Base64Url e os métodos de decodificação com prefixo Try. Spans são tipos do tipo byref, e as versões antigas do PowerShell genuinamente não conseguiam ligar neles de jeito nenhum, mas o method binder do PowerShell atual agora faz uma conversão implícita de array para span, então esses atalhos podem ser chamados de um script num host recente o suficiente. A resposta da comunidade para tudo que é mais antigo é o módulo Microsoft.PowerShell.TextUtility do PowerShell Gallery, cujo ConvertTo-Base64 embrulha o mesmo método .NET e adiciona um parâmetro -Text com padrão UTF-8 e um switch -InsertBreakLines para o embrulho de 76 colunas. Instale com Install-Module -Name Microsoft.PowerShell.TextUtility se você prefere a forma cmdlet, e note que o módulo está arquivado e não é mais mantido ativamente, o que é mais um motivo para o método embutido continuar sendo a recomendação para scripts novos.

Os números e nomes para guardar

  • A cada três bytes de entrada, saem quatro caracteres de saída, então os dados codificados ficam cerca de 33% maiores que o original, e o padding nunca passa de dois sinais de igual.
  • A saída padrão é uma linha ininterrupta. InsertLineBreaks embrulha a cada 76 caracteres com CRLF, a convenção MIME de 1996. O PEM quer 64, e nenhuma flag embutida produz essa largura.
  • base64url é Base64 padrão com + e / trocados por hífen e sublinhado, padding geralmente descartado, e é o alfabeto de todo JWT e token de API.
  • "Café" é cinco bytes em UTF-8 e oito em UTF-16LE. O mesmo texto visível, o dobro do tamanho, e as duas codificações não são intercambiáveis pelo fio.
  • -EncodedCommand existe desde o primeiro lançamento do PowerShell, e o seu payload deve ser UTF-16LE, não UTF-8. A palavra única que corrige o erro mais comum deste lado é Unicode.
  • certutil -encode pode esconder uma decisão de codificação dentro de -unicodetext, e o base64 do GNU precisa de -w 0 para te dar uma linha em vez do embrulho de 76 colunas.
  • Os helpers Base64 baseados em span do .NET, incluindo Base64Url, já foram inalcançáveis do PowerShell porque spans são tipos do tipo byref que o method binder antigo não conseguia ligar. O PowerShell atual (7.4+, num runtime .NET novo o suficiente para fornecer a classe) resolve um argumento de array contra um parâmetro span sem reclamação, então a chamada direta funciona hoje - mas a troca dos dois caracteres continua sendo a receita que funciona em toda versão, antiga e nova.
  • Um único byte, 123, codifica como ew==: o menor exemplo possível da regra de que o comprimento da saída te conta o comprimento da entrada.

Invertendo a seta

Tudo neste artigo é sobre pegar dados que você tem e transformar em uma string Base64. A operação espelho, pegar uma string e trazer seus dados de volta, tem o seu próprio elenco de problemas: um decodificador que ignora quatro tipos de espaço em branco, uma mensagem de erro cobrindo três crimes, um JWT para espiar, um certificado para desembalar, e um -EncodedCommand para explicar. Essa direção ganha o seu próprio tratamento completo, com as suas próprias armadilhas e a sua própria história, no artigo relacionado no site irmão, Decodificação Base64 em PowerShell, vinculado abaixo.

Última atualização: 2026-09-08

Artigo relacionado: Decodificação Base64 em PowerShell: um guia completo