문자열 인코딩과 디코딩
인코딩을 명시해서 문자열을 바이트로 바꾼 다음 [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
출력은 인코딩에 따라 달라집니다. [Text.Encoding]::Unicode는 UTF-16LE이므로 같은 두 글자라도 결과가 다릅니다.
[Convert]::ToBase64String([Text.Encoding]::UTF8.GetBytes("hi")) # aGk=
[Convert]::ToBase64String([Text.Encoding]::Unicode.GetBytes("hi")) # aABpAA==
웹 API, 설정 파일, 다른 언어로 보내는 것에는 UTF-8을 쓰세요. Unicode는 -EncodedCommand에만 쓰세요. 디코딩한 문자열의 글자 사이마다 빈칸이 보인다면 UTF-16이었던 것입니다. Base64 UTF-16 변환 도구로 디코딩할 수 있습니다.
REST 호출용 Basic Auth 헤더는 다음과 같습니다.
$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 이상에서는 Invoke-RestMethod -Authentication Basic -Credential $cred로 헤더를 직접 만들 수도 있으며, 이렇게 하면 비밀번호가 일반 문자열로 남지 않습니다.
-EncodedCommand
powershell.exe와 pwsh는 -EncodedCommand(줄임형 -enc, -e)로 Base64 스크립트를 받습니다. 따옴표와 특수 문자가 든 스크립트를 이스케이프 문제 없이 cmd.exe, 스케줄러, 원격 도구에 넘기기 위해 존재합니다. 텍스트는 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
공격자들도 대충 훑어보는 눈을 피해 스크립트를 숨기려고 -enc를 쓰기 때문에 보안 도구는 이를 경고 대상으로 표시합니다. 실행하지 않고 읽으려면 다음과 같이 합니다.
[Text.Encoding]::Unicode.GetString([Convert]::FromBase64String($b))
# Write-Output "hi from base64"
PowerShell 인코딩 명령 도구는 브라우저에서 양방향 변환을 하며 스크립트를 절대 실행하지 않습니다.
URL-safe Base64
[Convert]에는 내장 URL-safe 모드가 없습니다. 문자와 패딩을 직접 바꾸세요.
$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는 .NET 9에서 실행되므로 그곳에서는 [System.Buffers.Text.Base64Url]::EncodeToString($bytes)도 쓸 수 있습니다. 7.4와 Windows PowerShell 5.1에서는 위의 치환 방식을 쓰세요. 각 변형이 쓰이는 곳은 Base64와 Base64URL 비교를 참고하세요.
파일 인코딩과 디코딩
[Convert]::ToBase64String([IO.File]::ReadAllBytes("$PWD/hello.txt")) # aGVsbG8K
[IO.File]::WriteAllBytes("$PWD/copy.txt", [Convert]::FromBase64String("aGVsbG8K"))
$PWD/ 접두사가 필요한 이유는 .NET 메서드가 상대 경로를 프로세스 작업 디렉터리 기준으로 해석하고, Set-Location은 이를 바꾸지 않기 때문입니다. /tmp에서 pwsh를 시작해 Set-Location /w를 실행한 다음 [IO.File]::ReadAllBytes("hello.txt")를 호출하면, 파일이 바로 거기 있는데도 FileNotFoundException이 발생합니다.
cmdlet으로도 바이트를 읽을 수 있지만, 매개변수가 버전에 따라 바뀌었습니다.
# PowerShell 7+
[Convert]::ToBase64String((Get-Content hello.txt -AsByteStream -Raw))
# Windows PowerShell 5.1
[Convert]::ToBase64String((Get-Content hello.txt -Encoding Byte -Raw))
-Raw가 없으면 Get-Content는 바이트마다 객체 하나를 반환하므로 큰 파일에서는 매우 느립니다.
큰 파일
ReadAllBytes는 파일 전체를 메모리에 올립니다. 수백 MB라면 .NET의 ToBase64Transform으로 스트리밍하세요.
$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()
출력을 쓰기 전에 CryptoStream을 dispose하세요. 그렇지 않으면 마지막 블록과 패딩이 빠집니다. 300 KB 테스트 파일에서 ToBase64String과 같은 문자열이 나왔습니다. 디코딩도 'Read' 모드의 FromBase64Transform으로 같은 방식으로 동작합니다. 그 버전은 C#에서 Base64 사용하기 페이지에 있습니다.
Windows에서는 certutil -encode in.bin out.txt와 certutil -decode도 동작하지만, -encode는 출력을 -----BEGIN CERTIFICATE----- 줄로 감싸므로 다른 곳에 쓰기 전에 그 줄을 제거하세요.
MIME 줄 바꿈
InsertLineBreaks를 넘기면 CRLF로 구분된 76자 줄을 얻습니다.
[Convert]::ToBase64String([Text.Encoding]::UTF8.GetBytes("x" * 60), 'InsertLineBreaks')
# eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4
# eHh4
오류와 검증
잘못된 입력은 .NET System.FormatException을 일으키며, PowerShell은 이를 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는 패딩이 없어서 실패합니다. URL-safe 문자, data: 접두사, 문자열과 함께 복사된 따옴표에서도 같은 메시지가 나옵니다. 간단한 테스트 함수는 다음과 같습니다.
function Test-Base64([string]$s) {
try { $null = [Convert]::FromBase64String($s); $true } catch { $false }
}
Test-Base64 "aGk=" # True
Test-Base64 "aGk" # False
로그나 이메일에서 가져온 문자열이 디코딩되지 않으면 Base64 복구가 따옴표와 줄 바꿈을 제거하고 패딩을 고쳐 줍니다. 원인은 Base64 오류 가이드에서 설명합니다.
버전별 참고 사항
[Convert]::ToBase64String/FromBase64String: Windows PowerShell 5.1을 포함한 모든 PowerShell 버전.Get-Content -AsByteStream: PowerShell 6 이상. 이 버전에서-Encoding Byte가 제거되었습니다.Base64Url클래스: PowerShell 7.5 이상(.NET 9 기반).
자주 묻는 질문
-EncodedCommand는 어떤 인코딩을 기대하나요?
.NET에서 [Text.Encoding]::Unicode라고 부르는 UTF-16LE입니다. UTF-8 바이트로 인코딩한 명령은 깨진 값으로 디코딩되어 구문 분석 오류로 실패합니다.
의심스러운 -enc 명령을 안전하게 디코딩하려면 어떻게 하나요?
실행하지 말고 디코딩만 하세요. [Text.Encoding]::Unicode.GetString([Convert]::FromBase64String($b))를 쓰거나, 스크립트를 표시만 하는 PowerShell 인코딩 명령 디코더에 붙여넣으세요.
ConvertTo-Base64 같은 Base64 cmdlet이 있나요?
PowerShell 자체에는 없습니다. 일부 모듈이 추가해 주기도 하지만, [Convert]::ToBase64String과 [Convert]::FromBase64String은 아무것도 설치하지 않고 어디서나 동작합니다.
[IO.File]::ReadAllBytes가 파일을 찾을 수 없다고 하는 이유는 무엇인가요?
.NET은 상대 경로를 프로세스 작업 디렉터리 기준으로 해석하는데, Set-Location은 이를 바꾸지 않습니다. 대신 (Resolve-Path file.bin)이나 "$PWD/file.bin"을 넘기세요.