Subir un archivo
  1. base64hub
  2. Base64 en código
  3. PowerShell
Código

Base64 en PowerShell

PowerShell no tiene un cmdlet para Base64: llama directamente a la clase [Convert] de .NET. La dificultad está en elegir la codificación de texto correcta. Las salidas de esta página son de PowerShell 7.4 en Linux.

Codificar y decodificar una cadena

Convierte la cadena en bytes con una codificación explícita y después llama a [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

La codificación determina la salida. [Text.Encoding]::Unicode es UTF-16LE, así que las mismas dos letras dan un resultado distinto:

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

Usa UTF-8 para todo lo que envíes a API web, archivos de configuración u otros lenguajes. Usa Unicode solo para -EncodedCommand. Si una cadena decodificada muestra un hueco entre cada letra, era UTF-16; la herramienta Base64 a UTF-16 decodifica ese tipo de cadenas.

Para una cabecera Basic Auth en una llamada REST:

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

PowerShell 6+ también puede construir la cabecera por sí mismo con Invoke-RestMethod -Authentication Basic -Credential $cred, lo que evita tener la contraseña en una cadena de texto plano.

-EncodedCommand

powershell.exe y pwsh aceptan un script en Base64 mediante -EncodedCommand (formas abreviadas -enc, -e). Existe para pasar scripts con comillas y caracteres especiales a través de cmd.exe, programadores de tareas y herramientas remotas sin problemas de escapado. El texto debe estar en 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 los atacantes también usan -enc para ocultar scripts a una inspección rápida, las herramientas de seguridad lo marcan. Para leer uno sin ejecutarlo:

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

La herramienta comando codificado de PowerShell funciona en ambos sentidos en el navegador y nunca ejecuta el script.

Base64 URL-safe

[Convert] no tiene un modo URL-safe integrado. Sustituye tú los caracteres y el relleno:

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

PowerShell 7.5 funciona sobre .NET 9, así que ahí también está disponible [System.Buffers.Text.Base64Url]::EncodeToString($bytes); en la 7.4 y en Windows PowerShell 5.1, quédate con los reemplazos de arriba. Consulta Base64 frente a Base64URL para ver dónde se usa cada variante.

Codificar y decodificar un archivo

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

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

El prefijo $PWD/ hace falta porque los métodos de .NET resuelven las rutas relativas respecto al directorio de trabajo del proceso, y Set-Location no lo cambia. Si arrancas pwsh en /tmp, ejecutas Set-Location /w y luego [IO.File]::ReadAllBytes("hello.txt"), obtienes FileNotFoundException aunque el archivo esté justo ahí.

La vía de los cmdlets también lee bytes, pero el parámetro cambió entre versiones:

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

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

Sin -Raw, Get-Content devuelve un objeto por byte, lo que es muy lento con archivos grandes.

Archivos grandes

ReadAllBytes carga el archivo entero. Con cientos de megabytes, procésalo en flujo con ToBase64Transform de .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()

Libera el CryptoStream antes de usar la salida; si no, faltarán el último bloque y el relleno. Nuestro archivo de prueba de 300 KB produjo la misma cadena que ToBase64String. La decodificación funciona igual con FromBase64Transform en modo 'Read'; la página Base64 en C# tiene esa versión.

En Windows, certutil -encode in.bin out.txt y certutil -decode también funcionan, pero -encode envuelve la salida entre líneas -----BEGIN CERTIFICATE-----, así que quítalas antes de usarla en otro sitio.

Saltos de línea MIME

Pasa InsertLineBreaks para obtener líneas de 76 caracteres con CRLF:

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

Errores y validación

Una entrada no válida lanza una System.FormatException de .NET, que PowerShell envuelve en 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 falla porque falta el relleno. El mismo mensaje aparece con caracteres URL-safe, prefijos data: y comillas copiadas junto con la cadena. Una función de prueba sencilla:

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

Cuando una cadena sacada de un log o de un correo se niega a decodificarse, Reparar Base64 quita comillas y saltos de línea y corrige el relleno. La guía de errores de Base64 explica las causas.

Notas de versión

  • [Convert]::ToBase64String / FromBase64String: todas las versiones de PowerShell, incluido Windows PowerShell 5.1.
  • Get-Content -AsByteStream: PowerShell 6+. Ahí se eliminó -Encoding Byte.
  • Clase Base64Url: PowerShell 7.5+ (sobre .NET 9).

Preguntas frecuentes

¿Qué codificación espera -EncodedCommand?

UTF-16LE, que .NET llama [Text.Encoding]::Unicode. Un comando codificado a partir de bytes UTF-8 se decodifica como basura y falla con un error de análisis.

¿Cómo decodifico con seguridad un comando -enc sospechoso?

Decodifícalo sin ejecutarlo: [Text.Encoding]::Unicode.GetString([Convert]::FromBase64String($b)), o pégalo en el decodificador de comandos codificados de PowerShell, que solo muestra el script.

¿Existe un cmdlet para Base64 como ConvertTo-Base64?

No en PowerShell como tal. Algunos módulos añaden uno, pero [Convert]::ToBase64String y [Convert]::FromBase64String funcionan en todas partes sin instalar nada.

¿Por qué [IO.File]::ReadAllBytes dice que no encuentra el archivo?

.NET resuelve las rutas relativas respecto al directorio de trabajo del proceso, que Set-Location no cambia. Pasa (Resolve-Path file.bin) o "$PWD/file.bin" en su lugar.

Sigue leyendo