Haben Sie mit dem Base64-Format zu tun? Dann ist diese Website genau das Richtige für Sie! Nutzen Sie unser superpraktisches Online-Tool, um Ihre Daten zu kodieren oder zu dekodieren.

Base64-Dekodierung in PowerShell: Ein vollständiger Leitfaden

Irgendwo in einer Logzeile, in einer Konfigurationsdatei oder in einer Fehlermeldung laufen Sie darauf auf: eine lange Kette aus Buchstaben und Ziffern mit dem gelegentlichen Plus oder Schrägstrich und ein oder zwei Gleichheitszeichen, die verdächtig am Ende parken. Es sieht nach Rauschen aus. Ist es aber nicht. Es ist Base64, und Sie wissen bereits, was Sie wollen: das, was es verbirgt.

Base64 ist eine Übersetzung, keine Kompression und kein Schloss. Es schreibt jede Folge von Bytes in druckbaren Text um, vier Zeichen pro drei Eingabe-Bytes (kodiertes Material wird dadurch etwa 33 Prozent größer als das Original), mit einem Alphabet von 64 Zeichen plus dem Gleichheitszeichen als Padding am Ende. Die Startseite dieser Site geht das Alphabet, die Bit-Mathematik und die Varianten vollständig durch, also verbringt dieser Artikel seine Zeit dort, wo PowerShell den Unterschied macht: die eine .NET-Methode, die Sie aufrufen werden, die Regeln, die sie durchsetzt, und rund ein Dutzend Ecken der realen Arbeit, an denen das Dekodieren in PowerShell interessant wird.

Die Methode und ihr Vertrag

PowerShell bringt kein eigenes Base64-Cmdlet mit. Die Arbeit erledigt eine Methode einer .NET-Klasse, die seit .NET Framework 1.1 im Jahr 2003 Teil des Frameworks ist, drei Jahre, bevor PowerShell selbst erschien:

$bytes = [System.Convert]::FromBase64String("SGVsbG8sIFdvcmxkIQ==")
[System.Text.Encoding]::UTF8.GetString($bytes)
# Hello, World!

Das ist die gesamte API: ein String rein, ein Byte-Array raus. Es funktioniert in jedem PowerShell auf jedem Betriebssystem, in Windows PowerShell 5.1 und in PowerShell 7 auf Windows, Linux und macOS, denn es ist schlicht .NET. Der Vertrag ist kurz genug zum Auswendiglernen, also hier als Tabelle:

Eingabe Was Sie zurückbekommen
$null Ein leeres Array, kein Fehler. PowerShell wandelt $null still und leise in einen leeren String um, bevor der Aufruf startet
Ein leerer String Ein leeres Array, kein Fehler
Ein gültiger Payload Ein byte[], niemals ein String, auch wenn die Daten Text sind
Ein ungültiger Payload Eine FormatException, für Sie verpackt in einer MethodInvocationException

Eine Warnung, bevor Sie irgendeine Fehlerbehandlung schreiben: Diese FormatException hat genau eine Meldung, die drei verschiedene Vergehen abdeckt. Ein Zeichen außerhalb des Alphabets, mehr als zwei Padding-Zeichen oder ein Zeichen, das kein Leerraum ist und sich im Padding versteckt, erzeugen alle exakt denselben Satz. Wenn Sie die sehen, sagt die Meldung Ihnen nicht, welches Vergehen Sie begangen haben, also gehen Sie zurück und lesen Sie Ihren Input:

try {
  [System.Convert]::FromBase64String("SGV!G8s=")
}
catch {
  $real = $_.Exception.InnerException
  $real.GetType().Name
  # FormatException
  $real.Message
}

Und die Regel vom Vielfachen von vier hat eine Kante, die beim ersten Mal überrascht: Vier Zeichen ohne jegliches Padding sind einwandfrei gültig, es bedeutet nur, dass die überschüssigen Bits im letzten Zeichen verworfen werden. Drei Zeichen sind kein Vielfaches von vier und werden abgelehnt:

[System.Convert]::FromBase64String("SGVs").Count
# 3: Vier Zeichen ohne Padding sind in Ordnung
[System.Convert]::FromBase64String("SGV")
# FormatException: Drei Zeichen sind kein Vielfaches von vier

Was der Dekodierer akzeptiert und was nicht

Der Dekodierer ist streng beim Alphabet und großzügig bei genau einer Sache. Die gültigen Zeichen sind die 64 Base64-Ziffern (A bis Z, a bis z, 0 bis 9, plus und Schrägstrich) und das Gleichheitszeichen als Padding am Ende. Genau vier Leerraumzeichen werden ignoriert, wo auch immer und so oft sie auftauchen: der Tab, der Zeilenvorschub, das Wagenrückzeichen und das Leerzeichen. Die offizielle .NET-Dokumentation listet sie unter ihren Unicode-Namen, und das verrät, dass es eine dokumentierte Garantie ist und kein glücklicher Zufall.

In der Praxis ist das eine Superkraft. MIME, die Mail-Kodierung, die Base64 berühmt gemacht hat, bricht kodierte Zeilen bei 76 Zeichen um, daher kommt ein Payload, der durch eine E-Mail, ein Ticket oder eine Logdatei gereist ist, normalerweise in vielen Zeilen zerschnitten an. Der Dekodierer kümmert sich nicht darum. Fügen Sie ihn so ein, wie er ist:

$wrapped = "VGhlIHF1aWNrIGJyb3duIGZveCBqdW1wcyBvdmVyIHRoZSBsYXp5IGRvZy4gQmFzZTY0IHRleHQg`r`n" +
           "YXJyaXZlcyB3cmFwcGVkIGF0IHNldmVudHktc2l4IGNvbHVtbnMgaW4gbWFpbCwgc28gdGhlIGRl`r`n" +
           "Y29kZXIgbXVzdCBub3QgY2FyZS4="
[System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($wrapped))
# The quick brown fox jumps over the lazy dog. Base64 text arrives
# wrapped at seventy-six columns in mail, so the decoder must not care.

Alles andere, was kein Alphabetzeichen ist, ist ein hartes Aus. Die häufigsten Übeltäter in der Wildnis sind der Non-Breaking Space (der Liebling von Text, der von Webseiten kopiert wurde) und das Byte-Reihenfolgezeichen (die unsichtbare Marke, die Ihnen partout nicht loslässt, wenn eine Datei mit der falschen Kodierung gelesen wurde). Keines davon ist für diese Methode Leerraum, daher werfen beide:

try {
  [System.Convert]::FromBase64String("SGVs`u{00A0}G8=")
}
catch {
  $_.Exception.InnerException.GetType().Name
  # FormatException
}

Die Strenge ist Absicht, keine Knausrigkeit. RFC 4648, der Standard, der Base64 im Jahr 2006 kodifizierte, sagt, Implementierungen müssen Zeichen außerhalb des Alphabets ablehnen, es sei denn, das Protokoll erlaubt ausdrücklich Nachsicht, denn ein Dekodierer, der fremde Zeichen still und leise schluckt, lässt sich in einen verdeckten Kanal verwandeln, um Daten an alles vorbei zu schmuggeln, was nur das Alphabet prüft. Der .NET-Dekodierer folgt der strengen Regel, und genau so wollen Sie es in der Regel auch.

Ein Byte-Array ist kein String

Die Methode hält absichtlich bei dem Byte-Array an. Was diese Bytes bedeuten, ist eine zweite Entscheidung, die nur Sie treffen können, und sie falsch zu raten ist der berüchtigtste Fehler in PowerShell-Base64-Arbeit. Die Standardannahme, UTF-8, stimmt für fast alles im Internet, und die Hin- und Rückreise sind zwei Aufrufe:

$bytes = [System.Convert]::FromBase64String("SGVsbG8sIFdvcmxkIQ==")
[System.Text.Encoding]::UTF8.GetString($bytes)
# Hello, World!

Die Kodierungen, die Sie tatsächlich zur Hand nehmen werden, und was jede davon tut, wenn Sie sich irren:

Kodierung Nehmen Sie sie, wenn Wenn Sie sich irren
UTF8 Web-APIs, JSON, JWTs, alles Moderne. Der sichere Standard Latin-1- oder UTF-16-Text kommt als Mojibake zurück
Unicode (UTF-16LE) Der Payload stammt aus Windows-Tooling, einem Registry-Wert oder einem .NET-String, der vor dem Versenden kodiert wurde Jedes Zeichen bekommt einen Abstand um sich, denn Sie haben ein Byte gelesen, wo zwei gemeint waren
ASCII Klassische HTTP-Basic-Anmeldedaten und andere garantiert 7-Bit-Protokolle Alles über dem Wert 127 wird zu einem Fragezeichen
Latin1 Alte europäische Texte, die älter sind als UTF-8 Multibyte-UTF-8-Sequenzen zerfallen in mehrere falsche Buchstaben
Default Fast nie. Es ist die System-Codepage der Maschine Ihr Skript verhält sich anders bei jeder Windows-Regionseinstellung

Der klassische Fehler ist UTF-8-Text, der als UTF-16 dekodiert wird. Die Bytes sind echt, die Methode ist zufrieden, und das Ergebnis ist trotzdem Müll:

# "SGk=" sind die UTF-8-Bytes von "Hi"
[System.Text.Encoding]::Unicode.GetString([System.Convert]::FromBase64String("SGk="))
# Ein einzelnes unlesbares Zeichen: 2 Bytes UTF-8, gelesen als eine 2-Byte-UTF-16-Einheit

Die praktische Regel: Wenn der dekodierte Text so aussieht, als hätte jedes Zeichen einen unsichtbaren Abstand um sich, oder wie ein anderes Alphabet, sind Sie um eine Kodierung daneben. Fragen Sie, wo die Daten erzeugt wurden, und wenn Sie unsicher sind, vertrauen Sie UTF-8, aber überprüfen Sie die ersten paar Zeichen mit Ihren eigenen Augen. Und entscheiden Sie die Kodierung vor dem Dekodieren, nicht danach, wenn das Mojibake in Ihrem Log erscheint.

base64url: Das Alphabet, das sich in URLs artig benehmt

In jedem API-Token, in jedem JWT und in jedem in eine URL eingebetteten Identifier, den Sie je berühren werden, treffen Sie einen Cousin von Base64. Das Plus und der Schrägstrich des Standard-Base64 sind in einer URL nur nach dem Percent-Encoding legal, und das Equals-Padding sieht aus wie ein Feldtrenner. Also hat RFC 4648 ein URL- und dateinamensicheres Alphabet definiert: dieselben 64 Zeichen, nur wird Plus zum Bindestrich und Schrägstrich zum Unterstrich. Das Padding wird in der Regel ganz weggelassen, denn die Länge der Daten macht es überflüssig. Der RFC legt Wert darauf, dass diese Variante base64url und nicht einfach "base64" genannt werden soll, und der Rest dieses Abschnitts hält sich daran.

.NET liefert tatsächlich eine dedizierte Klasse dafür mit, System.Buffers.Text.Base64Url, hinzugefügt in .NET 9 mit schnellen Kodier- und Dekodier-Methoden, die komplett auf ReadOnlySpan<T>-Parametern aufbauen. Das aktuelle PowerShell (7.4 und neuer, sobald es auf einer .NET-Version läuft, die die Klasse mitbringt) kann diese Span-nehmenden Overloads heute tatsächlich direkt aufrufen, dank einer impliziten Array- und String-zu-Span-Umwandlung, die der Method-Binder jetzt durchführt, also funktioniert [System.Buffers.Text.Base64Url]::DecodeFromChars("--__AQI") ohne Umstände. Das war nicht immer so: Windows PowerShell 5.1 und ältere PowerShell-7.x-Releases konnten überhaupt nicht an Span-Parameter binden, und die Klasse existierte vor .NET 9 schlicht noch nicht, daher braucht jedes Skript, das auf 5.1, einem älteren 7.x oder einem Host vor .NET 9 laufen muss, die portable Version: die beiden Zeichen tauschen und das Padding wiederherstellen, bevor der Text an den Standard-Dekodierer übergeben wird. Das Padding, das Sie ergänzen, ist genau das, was die Länge zu einem Vielfachen von vier macht:

$token = "--__AQI"  # base64url, ohne Padding
$standard = $token.Replace("-", "+").Replace("_", "/")
$pad = 4 - ($standard.Length % 4)
if ($pad -eq 4) { $pad = 0 }
$standard = $standard.PadRight($standard.Length + $pad, "=")
$bytes = [System.Convert]::FromBase64String($standard)
$bytes -join ","
# 251,239,255,1,2

In dem kleinen Block lauern zwei Fallstricke. Erstens die Padding-Rechnung: Ein Payload, dessen Länge bereits ein Vielfaches von vier ist, braucht kein Padding, und die -eq 4-Abfrage ist es, die den Ausdruck ehrlich hält. Zweitens die Richtung: Wenn Sie nur dekodieren, ergänzen Sie Padding und tauschen die Zeichen; aus Standard-Base64-Input entfernen Sie niemals Padding, denn Standard-Dekodierer erwarten, dass es vorhanden ist. Wenn die Quelle ein JWT oder ein API-Token ist, ist es base64url ohne Padding, und das obige Rezept ist genau die Form, die Sie brauchen.

Einen JWT öffnen, ohne die Schlüssel

Ein JSON Web Token besteht aus drei base64url-Segmenten, verbunden durch Punkte: Header, Payload, Signatur. Die ersten beiden sind nacktes JSON, und Base64 ist keine Verschlüsselung, daher kann jeder, der den Token hat, beide lesen. Das ist ein Feature und kein Fehler: Der Token ist dafür ausgelegt, inspiziert zu werden, und die Signatur ist es, die ihn unfälschbar macht. PowerShell macht den kurzen Blick aus drei Zeilen:

$jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"
$parts = $jwt.Split(".")
function Decode-UrlSegment([string]$segment) {
  $standard = $segment.Replace("-", "+").Replace("_", "/")
  $pad = 4 - ($standard.Length % 4)
  if ($pad -eq 4) { $pad = 0 }
  $standard = $standard.PadRight($standard.Length + $pad, "=")
  return [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($standard))
}
Decode-UrlSegment $parts[0] | ConvertFrom-Json | ConvertTo-Json -Compress
Decode-UrlSegment $parts[1] | ConvertFrom-Json
# name-Eigenschaft:
(Decode-UrlSegment $parts[1] | ConvertFrom-Json).name
# John Doe

Drei Dinge zum Merken. Das dritte Segment, die Signatur, ist ebenfalls base64url, aber es dekodiert zu binären Signatur-Bytes, nicht zu Text, also erwarten Sie dort kein hübsches JSON. Der Header sagt normalerweise nur, welcher Algorithmus den Token signiert hat (HS256, RS256, ...), und ein Header, der none sagt, ist eine rote Flagge und keine Bequemlichkeit. Und das Lesen des Payloads heißt nicht, ihm zu vertrauen: base64 lässt Sie die Claims sehen, nur die Signatur macht sie authentisch. Wenn Sie Tokens akzeptieren sollen, verifizieren Sie die Signatur mit dem Schlüssel des Ausstellers; wenn Sie einen Token debuggen sollen, ist der obige Code alles, was Sie brauchen.

Dateien, PEM und der lange Weg zu Bytes

Die häufigste Dateiform ist eine Textdatei, die Base64 von etwas Größerem enthält: einen Backup-Blob, ein heruntergeladenes Binary, ein serialisiertes Objekt. Die Hin- und Rückreise sind vier Zeilen Code, und der moderne Weg, die Ausgabe zu lesen, ist ein echtes Byte-Array, keine Text-Vermutung:

$encoded = Get-Content -Path ./payload.b64 -Raw
$encoded = $encoded.Trim()
$bytes = [System.Convert]::FromBase64String($encoded)
[System.IO.File]::WriteAllBytes("./payload.bin", $bytes)
$bytes.Length
# wie viele Bytes der Text getragen hat

Das Original-Binary wieder einlesen, dafür verdienen sich PowerShell 6 und neuer ihren Lohn. Der -AsByteStream-Parameter liest rohe Bytes, und mit -Raw gibt er Ihnen ein echtes byte[] in einem Rutsch:

$bytes = Get-Content -Path ./photo.png -AsByteStream -Raw
$encoded = [System.Convert]::ToBase64String($bytes)
Set-Content -Path ./photo.b64 -Value $encoded -NoNewline
$bytes.Length
# ursprüngliche Größe, vor der 33-Prozent-Textsteuer

Lassen Sie -Raw weg, und Sie bekommen einen Stream aus einzelnen Byte-Objekten (ein Object[], wenn Sie ihn auffangen), was zur Inspektion gut ist, aber falsch, wenn Sie ihn an .NET-Methoden weitergeben, die ein Array erwarten. Und Windows PowerShell 5.1 hat überhaupt kein -AsByteStream, daher ist das zuverlässige Einlesen auf 5.1 [System.IO.File]::ReadAllBytes(), das überall existiert.

PEM ist der gepanzerte Cousin, den Sie von jedem Zertifikat und jedem privaten Schlüssel kennen: ein Standard-Base64-Body, normalerweise umgebrochen bei 64 Zeichen, zwischen -----BEGIN ...- und -----END ...-Zeilen. Die Panzerung ist Text; der Body ist der Payload. Panzerung abziehen, Zeilen verbinden, dekodieren:

$pem = Get-Content -Path ./certificate.pem -Raw
$body = ($pem -split "`n") | Where-Object { $_ -notmatch "^-----" } | ForEach-Object { $_.Trim() }
$der = [System.Convert]::FromBase64String(($body -join ""))
$der.Length
# die binäre DER-Größe des Zertifikats

Da der Standard-Dekodierer Leerraum ohnehin ignoriert, ist das -join "" doppelte Absicherung und keine Pflicht, aber wenn das Skript offenlegt, was es entfernt, verhält es sich auf jeder Maschine und bei jeder Zeilenend-Konvention gleich. Die andere Richtung, DER-Bytes in PEM einwickeln, ist nichts als der Base64-Encoder plus zwei Zeilen Text, und der Kodierungsartikel auf der Schwestersite zeigt den 64-Spalten-Umbruch in voller Länge.

Zertifikate und die Windows-Werkzeugkiste

Zertifikate sind die schwersten Base64-Bürger im Alltag, und PowerShell kann die ganze Familie fassen. Eine PFX-Datei ist ein binäres Bündel aus Zertifikat plus privatem Schlüssel, und es ist das Format, das Sie am häufigsten als Base64-Text in Konfigurationsdateien und Deployment-Skripten herumliegen sehen. Es zurück in ein lebendes Zertifikat zu dekodieren ist mit dem .NET-Typ ein One-Liner, und es funktioniert plattformübergreifend in PowerShell 7:

$bytes = [System.Convert]::FromBase64String($pfxText)
$password = ConvertTo-SecureString "secret" -AsPlainText -Force
$cert = [System.Security.Cryptography.X509Certificates.X509Certificate2]::new($bytes, $password)
$cert.Subject
# CN=example.org
$cert.NotAfter
# wann es aufhört, wahr zu sein

PowerShell 7 bringt auch Get-PfxCertificate mit, das eine PFX-Datei direkt von der Platte mit einem -Password-Parameter liest, daher können Sie bei Dateien auf der Platte das manuelle Dekodieren komplett überspringen. Ein nacktes Zertifikat (ohne Schlüssel) ist noch einfacher: Die DER-Bytes gehen ohne irgendein Passwort direkt in denselben X509Certificate2-Typ.

Außerhalb der Sprache lohnt es sich, zwei native Werkzeuge zu kennen. Auf Windows dekodiert certutil -decode infile.b64 outfile eine Base64-Datei mit Datei-rein/Datei-raus-Semantik (zum Überschreiben -f ergänzen), was es zum Mittel der Wahl für schnelle Fixes in einer normalen Eingabeaufforderung macht. Sein Bruder certutil -encode hat ein Flag, das sich zu merken lohnt: -unicodetext wandelt den Eingabetext vor dem Base64-Kodieren in UTF-16 um und versteckt damit eine ganze Kodierungsentscheidung in einem einzigen Schalter. Auf Linux und macOS ist das klassische Dienstprogramm base64 -d, das eine Datei oder die Standardeingabe dekodiert und Zeilenumbrüche standardmäßig überspringt; bei GNU coreutils ergänzen Sie -i, wenn der Payload auch Leerzeichen, Tabs oder CRLF aus Windows-Mails mitbringt.

Befehle in einem Base64-Umschlag

PowerShell hat seit Version 1.0 einen eingebauten Grund, Base64 zu sprechen: den -EncodedCommand-Parameter des Hosts selbst. Sie geben pwsh einen Base64-String, er dekodiert die Bytes als UTF-16LE, und das Ergebnis wird als Befehl ausgeführt. Der offizielle Zweck, direkt aus der Dokumentation, ist es, Befehle einzureichen, die komplexe Anführungszeichen oder geschweifte Klammern brauchen, ohne mit den Quoting-Regeln der äußeren Shell zu ringen:

$command = "Write-Host encoded-hello"
$encoded = [System.Convert]::ToBase64String([System.Text.Encoding]::Unicode.GetBytes($command))
# VwByAGkAdABlAC0ASABvAHMAdAAgAGUAbgBjAG8AZABlAGQALQBoAGUAbABsAG8A
pwsh -NoProfile -EncodedCommand $encoded
# encoded-hello

Lesen Sie die zweite Zeile sorgfältig, denn dort stolpern alle: Der Payload muss UTF-16LE sein, und das ist [System.Text.Encoding]::Unicode. Wenn Sie den Befehl stattdessen als UTF-8 kodieren, dekodiert PowerShell ihn fröhlich als UTF-16LE und führt einen aus Mojibake bestehenden Befehl aus, und die Fehlermeldung, die er dabei produziert, ist ein perfektes Porträt des Fehlers:

$wrong = [System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes($command))
pwsh -NoProfile -EncodedCommand $wrong
# Fehler: eine Wand aus unleserlichen Zeichen, "The term ... is not recognized..."

Derselbe Mechanismus ist der Grund, warum Sicherheitsteams auf Base64 in PowerShell achten. Ein langer, undurchsichtiger Token, der an -EncodedCommand übergeben wird, ist eine übliche Form für automatisiertes Tooling, und genau deshalb dekodieren Endpoint-Schutzprodukte diese Payloads, bevor sie laufen: Nichts an Base64 versteckt den Befehl vor einem Dekodierer, es versteckt ihn nur vor einem Menschen, der eine Prozessliste liest. Wenn Sie für Ihre eigene Automatisierung kodierte Befehle erzeugen, halten Sie den Originalbefehl neben dem Token, denn der Token selbst wird sich um 3 Uhr nachts nicht erklären.

Dekodieren, wenn der Input riesig ist

Für Alltagsgrößen ist der Ansatz mit der einzelnen Methode der schnelle. Ein fünf-Megabyte-Binary wird zu einem String von etwa sechs Millionen neunhunderttausend Zeichen, und das Dekodieren dieses Strings dauert auf einer modernen Maschine einstellige Millisekunden. Der eigene Hinweis der .NET-Dokumentation lautet, dass FromBase64String dafür ausgelegt ist, einen einzelnen String zu verarbeiten, der alle Daten enthält, und das stimmt, und das ist auch noch gut bis zu sehr großen Grenzen, denn die Methode arbeitet den String an Ort und Stelle ab, ohne sinnvolle zusätzliche Kopien.

Wenn der Payload größer ist, als Sie ihn bequem in einem String halten würden, oder als Stream ankommt (ein Download, ein Socket, ein riesiges Log), ist das dokumentierte Werkzeug System.Security.Cryptography.FromBase64Transform, verpackt in einem CryptoStream: Sie füttern es mit Base64-Text und lesen dekodierte Bytes heraus, und zu jedem Zeitpunkt ist nur ein kleiner Puffer am Leben. Beachten Sie, dass TransformStream, der C#-Helfer dafür, eine Erweiterungsmethode ist, und PowerShell sieht keine Erweiterungsmethoden, daher instanziieren Sie den CryptoStream direkt:

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

Für die neunzig Prozent der Jobs ist der einfache Weg immer noch der richtige: Die ganze Textdatei mit Get-Content -Raw lesen, trimmen, dekodieren, die Bytes schreiben. Greifen Sie zur Stream-Version, wenn die Datei zu groß ist, um sie bequem im Speicher zu halten, oder wenn die Daten stückweise ankommen. Und versuchen Sie nicht, über Zeilen zu iterieren und jede Zeile separat zu dekodieren: Base64-Gruppen von vier Zeichen halten sich nicht an Ihre Zeilenumbrüche, daher dekodiert eine Zeile, die eine Gruppe in der Mitte teilt, nicht von allein. Lesen Sie den ganzen Text, dann dekodieren Sie einmal.

Fallen, die Nachmittage kosten

  • Die Charset-Vermutung. UTF-8, gelesen als UTF-16, oder Latin-1, gelesen als UTF-8, produziert überzeugungsvolles Mojibake. Entscheiden Sie die Kodierung aus der Herkunft der Daten, machen Sie UTF-8 zum Standard, und sehen Sie sich die ersten paar dekodierten Zeichen an, bevor Sie dem Rest vertrauen.
  • Unsichtbare Zeichen vom Web. Ein Non-Breaking Space oder ein Byte-Reihenfolgezeichen, kopiert aus einer Seite oder einer Rich-Text-E-Mail, ist für den Dekodierer ein fremdes Zeichen und wirft die generische FormatException. Führen Sie den Input vor dem Dekodieren durch .Trim() und eine Prüfung auf nicht druckbare Zeichen.
  • Padding-Verwechslung. Standard-Base64 kommt mit = oder == am Ende an; base64url aus Tokens kommt ganz ohne. Eines dem Rezept zu füttern, das für das andere gebaut wurde, ist die häufigste stille Beschädigung in der API-Arbeit, und die Längenprüfung im base64url-Abschnitt ist die Sicherung.
  • Eine Meldung, drei Verbrechen. Weil die FormatException-Meldung schlechte Zeichen, zu viel Padding und schmutziges Padding alle auf einmal abdeckt, schicken Catch-Blöcke, die nur die Meldung loggen, Sie im Kreis herum. Loggen Sie außerdem die Länge des Inputs und die erste betroffene Stelle.
  • Einen String zurück zu erwarten. Das Ergebnis ist immer ein Byte-Array. In dem Moment, in dem Sie es direkt string-formatieren, bekommen Sie eine Liste von Zahlen, keinen Text. Wandeln Sie mit einer expliziten Kodierung um, einmal, am Ende.
  • Der 5.1-Dateistandard. Windows PowerShell 5.1 liest Dateien ohne BOM mit der ANSI-Codepage des Systems, während PowerShell 7 UTF-8 annimmt. Wenn Ihr Skript auf 5.1 die Base64-Textdatei liest und die Datei UTF-8 mit Nicht-ASCII um den Payload herum ist, passiert die Beschädigung, bevor der Dekodierer sie je sieht.
  • Base64 als Schloss zu behandeln. Es ist eine Übersetzung. Ein Passwort, Token oder Secret in Base64 ist nackter Text in einem Kostüm, und jeder Dekodierer auf dem Planeten, einschließlich dieses Artikels, öffnet ihn in einer Zeile.

Gewohnheiten, die Skripte ehrlich halten

  • Trimmen Sie externen Input vor dem Dekodieren. Ein einziger .Trim() entfernt mehr Produktionsvorfälle als jeder Fehlerbehandler.
  • Validieren Sie vor dem Dekodieren, wenn die Quelle nicht vertrauenswürdig ist: nachdem die vier erlaubten Leerraumzeichen entfernt wurden, sollte der String nur Alphabetzeichen mit höchstens zwei abschließenden Gleichheitszeichen enthalten. Eine schnelle Regex-Prüfung verwandelt eine Mysterium-Exception in eine saubere Meldung über abgelehnten Input.
  • Behalten Sie die Bytes als Bytes bis ganz zum letzten Schritt. Dekodieren Sie einmal, übergeben Sie das byte[] der Date-API oder dem Encoder, der es braucht, und wandeln Sie erst dann in Text um, mit einer bewussten Kodierung.
  • Loggen Sie Längen, keine Payloads. Die Größe des Inputs und die Größe des dekodierten Outputs erzählen Ihnen fast alles über einen Dekodierfehler, ohne dass Sie möglicherweise sensible Daten in das Log kopieren.
  • Bei allem, was über den Draht geht, notieren Sie, in welchem Alphabet es vorliegt, standard oder base64url, und mit welcher Padding-Konvention, in derselben Codezeile, die es dekodiert. Das zukünftige Sie ist der Konsument dieses Hinweises.

Wie PowerShell seinen Dekodierer geerbt hat

Die kürzeste wahre Geschichte von Base64 in PowerShell ist, dass PowerShell nie eines geschrieben hat. Die Methode, die Sie verwenden, Convert.FromBase64String, erschien mit .NET Framework 1.1 im Jahr 2003, und jedes PowerShell seit Version 1.0 im November 2006 hat schlicht das .NET offengelegt, auf dem es läuft. Das Projekt hieß während der Entwicklung Monad, wurde zum ersten Mal öffentlich auf der Professional Developers Conference im Oktober 2003 gezeigt, und bis zum Release war das .NET-Encoder-Dekoder-Paar, das es einpackt, bereits drei Jahre alt und im täglichen Einsatz.

Das Format selbst wurde im selben Jahr standardisiert, in dem die Shell an den Start ging. RFC 4648, veröffentlicht im Oktober 2006, ist das Dokument, das das Alphabet, die Padding-Regeln, die Erwartung des strengen Dekodierens und die base64url-Variante festlegte, und es beschreibt immer noch exakt das Verhalten, das FromBase64String heute implementiert. Als PowerShell im August 2016 als PowerShell Core open source und plattformübergreifend wurde, kam der Dekodierer ohne Änderungen auf Linux und macOS mit, denn es gab nichts zu ändern.

Das einzige echte Add-on ist das von der Community gepflegte Microsoft.PowerShell.TextUtility-Modul aus der PowerShell Gallery, dessen ConvertFrom-Base64-Cmdlet dieselbe .NET-Methode einpackt und einen -AsByteArray-Schalter plus einen Text-Standardwert hinzufügt, der als UTF-8 dekodiert. Installieren Sie es mit Install-Module -Name Microsoft.PowerShell.TextUtility, wenn Sie die Cmdlet-Form bevorzugen, aber eine Warnung: Das Modul ist inzwischen archiviert und wird nicht mehr aktiv gepflegt, was ein weiterer Grund ist, warum die eingebaute Methode die Empfehlung für neue Skripte bleibt.

Fakten, die sich zu merken lohnen

  • Der Dekodierer ignoriert Tabs, Zeilenvorschübe, Wagenrückzeichen und Leerzeichen an jeder Stelle im Input. Hundert umgebrochene Zeilen dekodieren exakt wie eine einzige lange Zeile.
  • Sowohl $null als auch der leere String dekodieren ohne Murren zu einem leeren Array, was FromBase64String an der Grenze ungewöhnlich nachsichtig macht.
  • Die eine FormatException-Meldung deckt drei verschiedene Fehlerszenarien ab. Wenn sie auslöst, ist die Antwort im Input zu finden, nicht in der Meldung.
  • "SABpAA==" ist der String Hi in der eigenen internen Kodierung von PowerShell, UTF-16LE. Er ist doppelt so lang wie die UTF-8-Kodierung derselben zwei Buchstaben, und dieses Verhältnis ist der Fingerabdruck von Windows-nativem Text in jedem Base64, das Sie lesen werden.
  • -EncodedCommand existiert seit dem ersten PowerShell-Release, und sein Payload ist zwingend als UTF-16LE vorgeschrieben, nicht als UTF-8. Kodieren Sie mit der falschen Kodierung, und die Shell führt fröhlich Ihr Mojibake aus.
  • Die neueren span-basierten Base64-Helfer von .NET, einschließlich der Base64Url-Klasse, waren aus älteren PowerShell-Releases nicht erreichbar, denn Spans sind byref-ähnliche Typen, die der Method-Binder nicht binden konnte. Das hat sich geändert: Das aktuelle PowerShell (7.4+, auf einer .NET-Version, die neu genug ist, um die Klasse mitzuliefern) löst ein Array- oder String-Argument gegen einen ReadOnlySpan<T>-Parameter auf, ohne Murren, also funktioniert der direkte Aufruf heute. Der Tausch der zwei Zeichen verdient seinen Lohn als die Version, die auch auf Windows PowerShell 5.1 und älteren Hosts läuft, nicht als der letzte verbliebene Weg.
  • Get-Content -AsByteStream ohne -Raw gibt Ihnen einen Stream aus Byte-Objekten, kein Byte-Array. Ergänzen Sie -Raw, und der Typ ist genau das, was die .NET-Methoden erwarten.

Der lange Weg im Kreis

Alles in diesem Artikel dreht sich darum, einen Base64-String zu nehmen und Ihre Daten zurückzubekommen. Die Spiegeloperation, Daten in Base64 zu verwandeln, sieht nach einem One-Liner aus, bis Sie die Tatsache treffen, dass PowerShell-Strings keine Bytes sind, dass UTF-16 Ihre Größe verdoppelt, dass der Zeilenumbruch zwei übliche Breiten hat und dass base64url-Ausgabe ihre eigene Zwei-Zeichen-Operation braucht. Diese Richtung bekommt ihre eigene vollständige Behandlung, mit ihren eigenen Fallen und ihrer eigenen Geschichte, im verwandten Artikel auf der Schwestersite, Base64-Kodierung in PowerShell, auf den diese Seite unten verlinkt.

Zuletzt aktualisiert: 2026-09-07

Verwandter Artikel: Base64-Kodierung in PowerShell: Ein vollständiger Leitfaden