Devi lavorare con il formato Base64? Allora questo sito è perfetto per te! Usa il nostro praticissimo strumento online per codificare o decodificare i tuoi dati.

Codifica Base64 in PowerShell: una guida completa

Hai una stringa, un file, un certificato o un token, e il lato opposto del cavo lo vuole come una lunga fila di lettere e cifre: stampabile, incollabile in una email, in un URL o in un file di configurazione, senza un singolo byte binario che rompa il trasporto. È il Base64. È una traduzione, non una compressione e non un lucchetto: tre byte di input diventano quattro caratteri di output, quindi il testo che spedisci finisce circa il 33% più grande di quello da cui è partito, usando un alfabeto di 64 caratteri più il segno di uguale come riempimento finale.

La home page di questo sito copre l'alfabeto, il calcolo dei bit e le varianti nel dettaglio. Questo articolo copre la direzione di codifica dal lato PowerShell: l'unico metodo .NET che userai, il passo mancante che fa inciampare tutti al primo script, le convenzioni di avvolgimento di riga che cambiano da protocollo a protocollo, l'alfabeto sicuro per URL, e la manciata di lavori reali in cui la codifica in PowerShell ricompensa il meticoloso e punisce il disattento.

Il metodo e il passo mancante

PowerShell non include un cmdlet Base64 tutto suo. Il lavoro lo fa un metodo che fa parte del framework .NET dal .NET Framework 1.1 del 2003, tre anni prima che PowerShell stesso uscisse:

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

È tutta l'API: un array di byte in ingresso, una stringa in uscita, in ogni PowerShell su ogni sistema operativo, perché è semplicemente .NET. Il passo mancante è la prima riga dell'esempio, ed è lì che i principianti perdono la loro prima ora. Il metodo non accetta la tua stringa. Accetta byte, e la domanda "quali byte significa la mia stringa" è una domanda di codifica che solo tu puoi rispondere. Ecco il contratto dei sovraccarichi che puoi effettivamente chiamare da PowerShell:

Quello che passi Quello che ottieni
byte[] Una riga lunga di Base64 standard, con riempimento = dove la lunghezza lo richiede
byte[] più InsertLineBreaks Lo stesso dato, spezzato a 76 caratteri con CRLF tra le righe
byte[], offset, count Solo la fetta richiesta dell'array, codificata
Una stringa come "Hello" Un'eccezione di conversione. PowerShell non può trasformare una stringa in un array di byte da solo
$null Un ArgumentNullException, impacchettato per te in un MethodInvocationException

Noterai cosa non c'è in quella tabella: non c'è un sovraccarico che dica "codifica questo testo". Codificare testo in PowerShell è sempre un processo in due passi. Decidi la codifica, produci i byte, e solo allora il metodo Base64 entra in conversazione. Tieni quelle due decisioni visibilmente separate nello script, perché la seconda è invisibile e la prima è lì che vivono i bug.

Codificare testo: scegli prima la codifica

La scelta sicura di default per tutto ciò che attraversa l'internet moderna è UTF-8. API web, JSON, JWT, tutto ciò che un browser o un server ha scritto nell'ultimo decennio si aspetta byte UTF-8 sotto il Base64, e il schema in due passi è l'abitudine che vuoi costruire:

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

Quando ricorri a una codifica diversa, di solito stai servendo un sistema legacy, e la tabella qui sotto è la guida pratica:

Codifica Usala quando Se scegli quella sbagliata
UTF8 API web, JSON, JWT, tutto il mondo moderno. La scelta di default Il decodificatore dall'altra parte vede testo illeggibile al posto del tuo testo
Unicode (UTF-16LE) Il consumatore è un componente Windows o .NET che codifica stringhe .NET, o -EncodedCommand Il tuo carico utile è il doppio della lunghezza che il consumatore si aspetta, e pieno di sorprese
ASCII Protocolli classici a 7 bit come le credenziali HTTP Basic Tutto ciò che supera il valore 127 viene sostituito prima ancora che la codifica avvenga
Latin1 Sistemi europei legacy che precedono UTF-8 Un byte per carattere, e ogni carattere non Latin-1 diventa un punto interrogativo

Un trucco utile di debug funziona in entrambe le direzioni: il riempimento e la lunghezza del Base64 ti dicono quanti byte sono stati codificati, e l'aspetto del testo decodificato ti dice da quale mondo a due byte o a un byte proviene. Un carico utile con una dimensione sospettosamente pari, pieno di caratteri che alternano valori normali e valori dall'aspetto di spazi vuoti, di solito è UTF-16 vestito da UTF-8, o il contrario.

La sorpresa UTF-16

PowerShell memorizza le stringhe internamente come UTF-16, e questo fatto si infiltra nel lavoro con Base64 in un punto specifico, molto comune: scrivi il Base64 per un consumatore che è a sua volta un componente .NET o Windows, e codifichi con Unicode perché è così che sono fatte le stringhe .NET. Per alcuni consumatori è un istinto corretto, per tutti gli altri è un errore che raddoppia le dimensioni. Gli stessi quattro caratteri visibili, due codifiche:

$same = "Café"
[System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes($same))
# Q2Fmw6k=  cinque byte
[System.Convert]::ToBase64String([System.Text.Encoding]::Unicode.GetBytes($same))
# QwBhAGYA6QA=  otto byte

Stesso testo, doppia dimensione, e le due stringhe non sono interscambiabili: un consumatore che se ne aspetta una e riceve l'altra non fallirà rumorosamente; leggerà semplicemente spazzatura. La regola che ti tiene al sicuro da questo è trattare la codifica come parte del protocollo, non come un dettaglio locale. Se il sistema ricevente è un browser, una API REST o un server moderno, è UTF-8 a meno che la documentazione non dica altrimenti. Se è lo stesso host di PowerShell tramite -EncodedCommand, o una stringa .NET in una pipeline solo Windows, è UTF-16LE. Quando il protocollo non lo dice, chiedi all'altra parte con cosa chiamerà GetString, perché è quella la domanda che decide davvero.

Numeri, byte e tutto il resto

Il metodo è dichiarato per accettare un array di byte, ma la conversione di tipi di PowerShell è generosa su cosa conta come uno, e conoscere i bordi ti salva da sorprese:

[System.Convert]::ToBase64String([byte[]](1, 2, 3, 250, 251))
# AQID+vs=
[System.Convert]::ToBase64String([char[]]"Café")
# Q2Fm6Q==  un byte per carattere, il valore del carattere come numero
[System.Convert]::ToBase64String([int[]](72, 101, 108, 108, 111))
# SGVsbG8=
[System.Convert]::ToBase64String(123)
# ew==  un numero singolo è accettato dove ci si aspetta un array intero

Due bordi in quel blocco meritano attenzione. Gli array di caratteri convertono un byte per carattere usando il valore numerico del carattere, il che per il testo latino è esattamente ciò che i sistemi legacy che usano questo trucco si aspettano, e per tutto ciò che va oltre produce in silenzio i byte sbagliati. Un intero maggiore di 255 è invece il bordo che fallisce rumorosamente: la conversione in byte di PowerShell rifiuta i valori fuori da 0-255 con un'eccezione, quindi 256 ferma lo script al cast invece di corrompere silenziosamente i tuoi dati. Se la tua fonte è fatta di numeri, rendi il cast esplicito: [byte[]](1, 2, 3) dice esattamente cosa intende.

Passa al metodo una stringa e ottieni lo stesso trattamento rumoroso per una ragione diversa: non c'è modo di sapere quali byte significhi una stringa, quindi il motore di conversione di PowerShell si arrende. Passagli $null e .NET genera un'eccezione prima di fare qualsiasi cosa. Entrambi sono comportamenti corretti, e sono la ragione per cui lo schema in due passi della prima sezione è l'unico schema che vale la pena avere.

Avvolgimento di riga: 76, 64 e nessuna

Di default il codificatore produce una riga lunga, qualunque sia la quantità di dati che gli dai. Per un file di qualche kilobyte va bene. Per dati che verranno letti da un essere umano, incollati in una email o confrontati in un diff di source control, un muro di otto milioni di caratteri è un problema pratico, e la convenzione è avvolgere. PowerShell e i protocolli che serve conoscono tre larghezze, e non sono interscambiabili:

Larghezza Chi se l'aspetta Fine riga
76 caratteri MIME, posta e la maggior parte dei trasporti di testo. Il default di InsertLineBreaks CRLF
64 caratteri File PEM: certificati, chiavi private e il resto della famiglia -----BEGIN Convenzionalmente LF
Nessuna API, token, file di configurazione, tutto ciò dove il carico utile è elaborato da una macchina Nessuna riga, e basta

L'avvolgimento integrato è un cambio di un solo parametro, ed è quello che vuoi per i carichi utili in stile posta:

$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 caratteri per riga, CRLF tra di loro, esattamente come MIME si aspetta

PEM è l'eccezione all'integrato, perché OpenSSL e l'intero ecosistema -----BEGIN avvolgono a 64 caratteri, e nessun flag .NET produce quella larghezza. Il ciclo è corto ed è la ricetta standard:

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

La ragione per cui la larghezza conta è che i gruppi di quattro caratteri del Base64 non rispettano gli a capo, quindi un decodificatore può ignorare del tutto gli a capo o può farli rispettare. Il decodificatore che usa questo sito li ignora, ma i consumatori rigorosi, e nel mondo dei certificati e della posta ce ne sono tanti, trattano un a capo inatteso come un carattere estraneo e rifiutano il carico utile. Quando scegli una larghezza, stai facendo un contratto con il consumatore, e vale la pena una nota nello script che nomini con chi stai facendo il contratto.

base64url: due caratteri e una decisione sul riempimento

Il più e la barra del Base64 standard sono legali all'interno di un URL solo dopo la codifica percent, e il riempimento con gli equals si legge come un separatore di campi. Così la RFC 4648 ha definito un alfabeto sicuro per URL e nomi di file: gli stessi 64 caratteri, tranne che il più diventa trattino e la barra diventa sottolineatura, e il riempimento viene di solito tolto perché la lunghezza dei dati lo rende inutile. Ogni token API e JWT che hai mai maneggiato è scritto in questa variante, che lo standard tiene a chiamare base64url e non semplicemente base64.

Il codificatore standard di PowerShell produce l'alfabeto standard, quindi la conversione a base64url è due scambi di caratteri e una decisione sul riempimento:

$bytes = [System.Text.Encoding]::UTF8.GetBytes("Париж encoded 大阪")
$standard = [System.Convert]::ToBase64String($bytes)
$standard
# 0J/QsNGA0LjQtiBlbmNvZGVkIOWkp+mYqg==  l'alfabeto standard, riempimento incluso
$url = $standard.Replace("+", "-").Replace("/", "_").TrimEnd("=")
$url
# 0J_QsNGA0LjQtiBlbmNvZGVkIOWkp-mYqg  la forma sicura per URL, riempimento rimosso

La rimozione del riempimento è sicura nel mondo base64url, perché il consumatore ricalcola quale sarebbe stato il riempimento dalla lunghezza della stringa. Non è così dappertutto, però, quindi rendi la decisione esplicita: togli il riempimento per token, segmenti JWT e incorporamento negli URL, tienilo per tutto ciò che alimenta un consumatore rigoroso dell'alfabeto standard, e annota quale hai scelto. Il runtime .NET include davvero una classe dedicata per questo alfabeto, System.Buffers.Text.Base64Url (aggiunta nel .NET 9), con metodi costruiti intorno a parametri ReadOnlySpan<T>. Il PowerShell attuale (7.4 e versioni successive, una volta che gira su una versione di .NET che include la classe) può in realtà chiamarli direttamente - [System.Buffers.Text.Base64Url]::EncodeToString($bytes) funziona oggi, perché il risolutore di metodi converte adesso implicitamente un argomento array in uno span - ma lo scambio di due caratteri resta quello a cui ricorrere ogni volta che lo script deve girare su Windows PowerShell 5.1, una release più vecchia di PowerShell 7.x, o un host su un runtime pre-.NET-9, e funziona in ognuna di quelle versioni.

Coniare un JWT

Il JSON Web Token è l'uso reale di punta del base64url, ed è anche un buon test completo della pipeline di codifica, perché un JWT è tre segmenti codificati uniti da punti: l'intestazione, il carico utile e la firma. I primi due sono JSON compatto in base64url, e il terzo è l'output binario di un hash sul testo esatto dei primi due. Ecco un token HS256 completo costruito in PowerShell, dall'inizio alla fine:

$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
#  su PowerShell 7.4; l'ordine interno delle chiavi dei segmenti - e quindi la firma - può variare da versione a versione

Dai un'occhiata al segmento di firma: una fila dell'alfabeto base64url, quello dove il più apparirebbe come trattino e la barra come sottolineatura. Tre cose di quell'esempio ti salveranno da incidenti di produzione. Primo, la firma è calcolata sul testo JSON esatto, incluso l'ordine delle chiavi e gli spazi, quindi il JSON che firmi e il JSON contro cui verifichi devono essere identici byte per byte. Il ConvertTo-Json di PowerShell decide l'ordine delle chiavi per te, e non è qualcosa che controlli, quindi non riordinare a mano i segmenti di un token o riformattarli tra la firma e il controllo. Secondo, -Compress non è estetico: un token la cui intestazione o il cui carico utile contiene un solo spazio è un token che non verificherà mai contro un'implementazione conforme, perché la forma standard è compatta. Terzo, il timestamp iat è i secondi dall'epoca Unix, e un carico utile costruito da Get-Date senza convertire sarà fuori range di anni. La direzione di decodifica, la sbirciata in un token coniato da qualcun altro, è coperta nell'articolo correlato sul sito sorella.

File e il flusso di byte

I file sono il carico utile più comune di tutti, e la pipeline è corta. Leggi il file come byte, codifica, scrivi testo. Le due righe che contano sono la lettura, che deve essere una lettura di byte, e la scrittura, che di solito non deve aggiungere un a capo finale:

$bytes = [System.IO.File]::ReadAllBytes("./photo.png")
$encoded = [System.Convert]::ToBase64String($bytes)
Set-Content -Path "./photo.b64" -Value $encoded -NoNewline
$encoded.Length
# la dimensione del testo che stai per spedire

Due note pratiche. La prima è aritmetica: il Base64 rende tutto più grande, e per un file da 10 megabyte il testo che spedisci è circa 13,4 megabyte. Se il trasporto ha un limite di dimensione, o se questo testo finirà in un corpo di email o in un URL, fai i conti prima di codificare, non dopo l'errore. La seconda è l'a capo finale: Set-Content ne aggiunge uno di default, e anche se il decodificatore usato da questo sito e la maggior parte dei decodificatori moderni lo ignora, alcuni consumatori rigorosi non lo fanno. -NoNewline non ti costa niente e toglie il dubbio.

PowerShell 6 e versioni successive offrono una seconda lettura che resta nel linguaggio: Get-Content -AsByteStream -Raw restituisce il file come un unico array di byte in una chiamata, un'alternativa ordinata alla ReadAllBytes di .NET che si comporta in modo identico per questo scopo. Su Windows PowerShell 5.1, che non ha -AsByteStream, la lettura .NET è l'unica opzione, ed è quella che si comporta allo stesso modo in ogni versione della shell.

Certificati: da PEM e PFX al testo

I certificati sono i cittadini di codifica più pesanti delle operazioni quotidiane, perché i deploy amano portarli come testo. Un certificato PEM è un corpo Base64 avvolto tra righe di armatura, e la ricetta dalla sezione sull'avvolgimento è l'intero export:

$cert = [System.Security.Cryptography.X509Certificates.X509Certificate2]::new([System.IO.File]::ReadAllBytes("./certificate.der"))
$cert.Subject
# CN=example.org
$b64 = [System.Convert]::ToBase64String($cert.RawData)
# una riga lunga della forma binaria del certificato

Il formato PFX è l'altro cavallo da lavoro: un singolo file binario che tiene il certificato insieme alla sua chiave privata, ed è per questo che è il formato che più spesso trovi a girovagare come testo Base64 dentro script di distribuzione e archivi di configurazione. Codificarne uno è la semplice pipeline di file della sezione precedente, e la direzione di lettura in PowerShell 7 è una questione di un solo cmdlet:

$pfxBytes = [System.IO.File]::ReadAllBytes("./certificate.pfx")
$pfxB64 = [System.Convert]::ToBase64String($pfxBytes)
# la forma testuale del bundle, pronta per un file di configurazione
Get-PfxCertificate -FilePath "./certificate.pfx" -Password (ConvertTo-SecureString "secret" -AsPlainText -Force)
# il certificato vivo, nessuna decodifica manuale necessaria

Una frase di sicurezza, detta in modo semplice perché il Base64 invita all'assunzione opposta: un PFX in Base64 è una chiave privata in testo. La codifica cambia la forma del segreto e nulla della sua segretezza, quindi un PFX Base64 incollato in una finestra di chat, in un ticket o in un commit è una chiave privata incollata in una finestra di chat, in un ticket o in un commit. Tratta la forma testuale con esattamente la cura che riceve la forma binaria, e preferisci l'archivio dei certificati o un gestore di segreti a entrambi.

Basic Auth, data URI e le vecchie abitudini

Il Base64 è più vecchio del documento standard che gli ha dato il nome. La famiglia MIME di RFC del 1996 lo ha messo nelle email, e l'autenticazione HTTP Basic lo ha messo in ogni scambio di intestazioni del web primordiale, dove il client ancora oggi codifica la coppia di credenziali come un'unica stringa Base64:

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

L'alfabeto standard è quello giusto qui, più e barra inclusi, perché un'intestazione non è un URL e non ha bisogno dell'alfabeto sicuro. Lo stesso meccanismo appare nei data URI, il modo in cui un documento incorpora il proprio binario in linea, e la forma è un prefisso letterale più il Base64 standard dei byte:

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

Entrambe le abitudini vale la pena conoscerle meno come cose che costruirai e più come cose che incontrerai: quando un'intestazione o un link contiene una lunga fila Base64, questi due formati sono i primi da controllare, e entrambi sono a una semplice decodifica da quello che dicono. Ed è questo il punto del formato, e la ragione per cui esiste il lato decodifica di questo sito.

Comandi codificati e la cassetta degli attrezzi di Windows

PowerShell porta una ragione integrata per codificare dalla versione 1.0: il parametro -EncodedCommand dell'host stesso. Dai a pwsh una stringa Base64, lui decodifica i byte come UTF-16LE, e il risultato viene eseguito come comando. Lo scopo documentato sono i comandi che lottano con la virgolettatura della shell esterna, e il lato codifica è due righe:

$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

Leggi la riga di codifica con attenzione, perché è quella che tutti sbagliano: il carico utile deve essere UTF-16LE, ed è la codifica Unicode, non UTF-8. Codifica con quella sbagliata e l'host decodifica comunque i tuoi byte come UTF-16LE ed esegue un comando fatto di testo illeggibile, producendo un errore che è il ritratto perfetto dell'errore. L'articolo sulla decodifica copre quel fallimento per intero, e la correzione su questo lato è una parola sola: Unicode.

Fuori dal linguaggio, gli strumenti nativi portano ciascuno la propria silenziosa decisione di codifica. Su Windows, certutil -encode infile outfile.b64 produce un file Base64 standard con le righe di armatura che PEM si aspetta, -f sovrascrive un output esistente, e il flag da ricordare è -unicodetext, che fa scrivere a certutil il file di output in Unicode (secondo la documentazione di Microsoft: "Scrivi il file di output in Unicode") - uno switch che nasconde una decisione di codifica. Su Linux l'utilità classica è base64 -w 0 file, dove -w 0 è la parte portante: senza di esso GNU base64 avvolge a 76 caratteri e ti consegna un file in stile MIME quando ne volevi una. Su macOS la versione BSD non ha bisogno di un flag del genere, perché di default emette una riga ininterrotta.

Codificare quando l'output è enorme

Per le dimensioni di ogni giorno, la pipeline leggi-tutto-codifica-tutto è quella veloce e semplice, ed è quella giusta finché il file non è troppo grande per stare comodamente in memoria o i dati non arrivano pezzo per pezzo da un download o da un socket. Allora lo strumento documentato è la coppia a flusso: System.Security.Cryptography.ToBase64Transform avvolto in un CryptoStream, dove scrivi byte grezzi in entrata e in uscita arriva il testo Base64, dove a ogni istante è vivo solo un piccolo buffer:

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

Una differenza rispetto al metodo a colpo unico vale la pena scriverla giù: il flusso produce una riga continua, senza alcun avvolgimento, qualunque sia la dimensione dell'input. Un decodificatore che ignora gli spazi bianchi non se ne cura, ma se la destinazione finale è un file PEM, esegui il ciclo a 64 colonne della sezione sull'avvolgimento sul risultato dopo. E in C# la forma standard è lo stesso schema ToBase64Transform + CryptoStream che vedi nell'articolo C#; PowerShell lo pilota direttamente, come sopra.

Dove i carichi utili codificati vanno storti

  • Codificare la stringa, non i byte. ToBase64String("Hello") genera un'eccezione di conversione, il che è il metodo che ti dice che la prima decisione, la codifica, non è stata presa. Rendila visibile nello script e l'errore sparisce.
  • UTF-16 dove era stato promesso UTF-8. Il carico utile è il doppio della lunghezza attesa e il consumatore legge spazzatura. La codifica fa parte del protocollo, e per quasi ogni cavo dell'internet moderna il protocollo dice UTF-8.
  • La lettura su 5.1. Windows PowerShell 5.1 legge un file di testo senza BOM con la pagina di codice ANSI della macchina prima che il tuo script lo veda, quindi un file sorgente UTF-8 può corrompersi prima del passo di codifica. Su 5.1, leggi il testo con una lettura UTF-8 esplicita e controlla i primi caratteri del risultato.
  • La larghezza di avvolgimento sbagliata. MIME vuole 76, PEM vuole 64, le API non ne vogliono nessuna, e un consumatore rigoroso tratta un a capo inatteso come un carattere estraneo. Scegli la larghezza dal consumatore e dillo in una nota.
  • Riempimento dal lato sbagliato dello scambio. Togliere i segni di uguale è corretto per i token base64url e sbagliato per un consumatore che si aspetta il riempimento standard. Lo scambio di alfabeto e la decisione sul riempimento sono due scelte, non una.
  • Riformattare quello che hai firmato. Una firma JWT copre il testo JSON esatto, incluso l'ordine delle chiavi e gli spazi. Riordina le claims o aggiungi uno spazio e il token smette di verificare, senza alcun messaggio di errore vicino alla causa.
  • Valori oltre 255. Convertire un intero in un byte genera un'eccezione invece di avvolgere, quindi 256 ferma lo script al cast. Se i tuoi dati sorgente sono numeri, fai il cast esplicito e lascia che un errore sia un errore che vedi.
  • Credere al costume. Il Base64 non è crittografia e non è compressione: è una traduzione che fa crescere i dati di un terzo. Un segreto in Base64 è un segreto in testo semplice, e un file in Base64 è un file che ha bisogno del 33% in più di spazio.

Regole per codificatori di cui fidarti

  • Produci i byte con deliberazione. La prima riga di qualsiasi script di codifica dovrebbe essere un GetBytes esplicito o una lettura di byte, mai una speranza che PowerShell convertirà una stringa nei byte giusti.
  • Dà un nome all'alfabeto e alla larghezza in una nota accanto al codice che fa la scelta: standard o base64url, avvolto a 76, 64 o non per niente. Il consumatore è una persona che legge lo script tra sei mesi, e quella persona sei tu.
  • Scrivi il file di testo con -NoNewline a meno che il consumatore non si aspetti specificamente un a capo finale, e scegli la fine riga (LF o CRLF) nel modo che la documentazione del consumatore si aspetta.
  • Testa l'andata e ritorno mentre costruisci: codifica, decodifica, confronta i byte. Una Compare-Object di trenta secondi sui due array di byte cattura errori di codifica, errori di avvolgimento e errori di ordine dei byte tutti in una volta, mentre la causa è ancora fresca.
  • Registra le dimensioni, non i carichi utili. Il conteggio dei byte prima e il conteggio dei caratteri dopo dovrebbero stare a un rapporto di circa 1,33, e quando non lo sono, la discrepanza di dimensione ti dice dove guardare senza che il log contenga mai i dati.

Come PowerShell ha ereditato il suo codificatore

La più corta storia vera della codifica Base64 in PowerShell è che PowerShell non ne ha mai scritto uno. Il metodo che chiami, Convert.ToBase64String, è uscito con .NET Framework 1.1 nel 2003, e ogni PowerShell dalla versione 1.0 di novembre 2006 ha semplicemente esposto il .NET su cui gira. Il progetto si chiamava Monad mentre veniva costruito, mostrato per la prima volta in pubblico alla Professional Developers Conference di ottobre 2003, e al momento del rilascio il codificatore .NET che avvolge era già vecchio di tre anni e portava traffico web.

Il formato è stato standardizzato lo stesso anno in cui la shell è uscita. La RFC 4648, pubblicata in ottobre 2006, ha fissato l'alfabeto, le regole di riempimento, la severità della decodifica e la variante base64url, e descrive ancora esattamente il comportamento che la coppia .NET implementa. Le RFC MIME che l'hanno preceduta, nel 1996, avevano già messo l'avvolgimento a 76 caratteri nelle email, ed è per questo che quella larghezza è il default di InsertLineBreaks fino a oggi. Quando PowerShell è diventato open source e multipiattaforma in agosto 2016 come PowerShell Core, il codificatore è arrivato su Linux e macOS senza modifiche, perché non c'era niente da cambiare.

Quello che è cambiato in seguito è successo in .NET, e per lo più fuori dalla portata di PowerShell. Il runtime ha acquisito aiutanti Base64 più veloci, basati su span, nelle versioni recenti, inclusa la classe Base64Url e i metodi di decodifica con prefisso Try. Gli span sono tipi simili a byref, e le versioni più vecchie di PowerShell non potevano legarsi a loro in modo genuino, ma il risolutore di metodi del PowerShell attuale esegue adesso una conversione implicita da array a span, quindi queste scorciatoie sono chiamabili da uno script su un host abbastanza recente. La risposta della comunità per tutto ciò che è più vecchio è il modulo Microsoft.PowerShell.TextUtility della PowerShell Gallery, il cui ConvertTo-Base64 avvolge lo stesso metodo .NET e aggiunge un parametro -Text con default UTF-8 e uno switch -InsertBreakLines per l'avvolgimento a 76 colonne. Installalo con Install-Module -Name Microsoft.PowerShell.TextUtility se preferisci la forma cmdlet, e nota che il modulo è archiviato e non viene più mantenuto attivamente, un'altra ragione per cui il metodo integrato resta la raccomandazione per gli script nuovi.

I numeri e i nomi da tenere

  • Ogni tre byte di input diventano quattro caratteri di output, quindi i dati codificati finiscono circa il 33% più grandi dell'originale, e il riempimento non è mai più di due segni di uguale.
  • L'output di default è una riga ininterrotta. InsertLineBreaks avvolge a 76 caratteri con CRLF, la convenzione MIME del 1996. PEM vuole 64, e nessun flag integrato produce quella larghezza.
  • Il base64url è il Base64 standard con più e barra scambiati con trattino e sottolineatura, riempimento di solito tolto, ed è l'alfabeto di ogni JWT e token API.
  • "Café" è cinque byte in UTF-8 e otto in UTF-16LE. Lo stesso testo visibile, doppia dimensione, e le due codifiche non sono interscambiabili attraverso il cavo.
  • -EncodedCommand esiste dal primo rilascio di PowerShell, e il suo carico utile deve essere UTF-16LE, non UTF-8. La parola singola che corregge l'errore più comune su questo lato è Unicode.
  • certutil -encode può nascondere una decisione di codifica dentro -unicodetext, e GNU base64 ha bisogno di -w 0 per darti una riga invece dell'avvolgimento a 76 colonne.
  • Gli aiutanti Base64 basati su span di .NET, incluso Base64Url, un tempo erano irraggiungibili da PowerShell, perché gli span sono tipi simili a byref a cui il vecchio risolutore di metodi non sapeva legarsi. Il PowerShell attuale (7.4+, su un runtime .NET abbastanza nuovo da includere la classe) risolve un argomento array contro un parametro span senza lamentarsi, quindi la chiamata diretta funziona oggi - ma lo scambio di due caratteri resta la ricetta unica che funziona in ogni versione, vecchia e nuova allo stesso modo.
  • Un singolo byte, 123, si codifica come ew==: l'esempio più piccolo possibile della regola per cui la lunghezza dell'output ti dice la lunghezza dell'input.

Girare la freccia

Tutto in questo articolo riguarda il prendere i dati che hai e trasformarli in una stringa Base64. L'operazione speculare, prendere una stringa e riavere i tuoi dati, ha il suo cast di problemi: un decodificatore che ignora quattro tipi di spazi bianchi, un messaggio di errore che copre tre crimini, un JWT in cui sbirciare, un certificato da svelare, e un -EncodedCommand da spiegare. Quella direzione riceve la sua trattazione completa, con le sue trappole e la sua storia, nell'articolo correlato sul sito sorella, la decodifica Base64 in PowerShell, collegato qui sotto.

Ultimo aggiornamento: 2026-09-08

Articolo correlato: Decodifica Base64 in PowerShell: una guida completa