Post

[PowerShell] 인코딩 지옥 탈출하기 - UTF-8 BOM과 chcp 65001

PowerShell에서 한글 깨짐을 해결하는 완벽한 UTF-8 설정 가이드

문제 상황 (Problem)

PowerShell 스크립트에서 한글을 출력하면 깨진다.

1
2
Write-Host "보안 스캔 시작..."
# 출력: ë³´ì ìºì  ììì...

JSON 파일을 읽어도 한글이 깨진다.

1
2
3
$config = Get-Content -Path config.json -Raw | ConvertFrom-Json
Write-Host $config.description
# 출력: ì¤ì  íì¼

Windows의 기본 인코딩이 CP949(또는 Windows-1252)라서 발생하는 문제다.


인코딩 기초 (Encoding Basics)

인코딩이란?

문자를 컴퓨터가 이해할 수 있는 바이트로 변환하는 규칙이다.

문자UTF-8 (3바이트)CP949 (2바이트)
0xED 0x95 0x9C0xC7 0xD1
0xEA 0xB8 0x800xB1 0xDB

주요 인코딩

인코딩설명한글 지원바이트 수
UTF-8유니코드, 전 세계 문자가변 (1-4바이트)
UTF-16유니코드, Windows 내부고정 (2바이트)
CP949한글 Windows 기본✅ (한글만)2바이트
Windows-1252영문 Windows 기본1바이트
ASCII영문, 숫자, 기호만1바이트

PowerShell 인코딩 설정

PowerShell은 여러 곳에서 인코딩을 설정해야 한다.

1. 콘솔 코드 페이지 (chcp)

Windows 콘솔의 문자 인코딩을 설정한다.

1
2
3
4
5
6
7
# 현재 코드 페이지 확인
chcp
# 출력: Active code page: 949 (CP949, 한글 Windows 기본)

# UTF-8로 변경
chcp 65001
# 출력: Active code page: 65001 (UTF-8)

주요 코드 페이지

코드 페이지인코딩설명
949CP949한글 Windows 기본
1252Windows-1252영문 Windows 기본
65001UTF-8유니코드
437OEM-USDOS 기본

2. OutputEncoding

PowerShell이 외부 프로그램에 전달하는 문자열의 인코딩이다.

1
2
3
4
5
6
7
8
# 현재 OutputEncoding 확인
$OutputEncoding
# 출력: IsSingleByte      : True
#      BodyName          : iso-8859-1
#      EncodingName      : Western European (Windows)

# UTF-8로 변경
$OutputEncoding = [System.Text.Encoding]::UTF8

3. Console Encoding

콘솔 입출력의 인코딩을 설정한다.

1
2
3
4
5
6
7
# 현재 Console Encoding 확인
[Console]::OutputEncoding
[Console]::InputEncoding

# UTF-8로 변경
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
[Console]::InputEncoding = [System.Text.Encoding]::UTF8

4. 파일 읽기/쓰기 기본 인코딩

Get-Content, Set-Content, Out-File 등의 기본 인코딩을 설정한다.

1
2
3
4
5
6
7
8
9
10
# 기본 인코딩 확인 (PowerShell 5.1)
Get-Content -Path test.txt -Encoding Default  # ASCII

# PowerShell 7+에서는 기본이 UTF-8 (No BOM)

# 모든 파일 관련 cmdlet의 기본 인코딩을 UTF-8로 설정
$PSDefaultParameterValues['*:Encoding'] = 'utf8'
$PSDefaultParameterValues['Out-File:Encoding'] = 'utf8'
$PSDefaultParameterValues['Set-Content:Encoding'] = 'utf8'
$PSDefaultParameterValues['Add-Content:Encoding'] = 'utf8'

완전한 UTF-8 설정 패턴

Windows Agent 스크립트에 사용한 표준 패턴이다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# Console encoding settings
try {
    # 1. 콘솔 코드 페이지를 UTF-8(65001)로 변경
    # 출력 버리기: $null = ... 2>&1
    $null = cmd /c chcp 65001 2>&1

    # 2. 외부 프로그램 전달 인코딩
    $OutputEncoding = [System.Text.Encoding]::UTF8

    # 3. 콘솔 입출력 인코딩
    [Console]::OutputEncoding = [System.Text.Encoding]::UTF8
    [Console]::InputEncoding = [System.Text.Encoding]::UTF8

    # 4. 파일 관련 cmdlet 기본 인코딩
    $PSDefaultParameterValues['*:Encoding'] = 'utf8'
    $PSDefaultParameterValues['Out-File:Encoding'] = 'utf8'
    $PSDefaultParameterValues['Set-Content:Encoding'] = 'utf8'
    $PSDefaultParameterValues['Add-Content:Encoding'] = 'utf8'
} catch {
    # 인코딩 설정 실패 시 무시 (일부 환경에서 권한 문제 발생 가능)
    # 하지만 대부분의 경우 문제없이 동작
}

적용 전후 비교

1
2
3
4
5
6
7
8
9
10
# Before: CP949 (기본)
Write-Host "보안 스캔 시작..."
# 출력: ë³´ì ìºì  ììì... (깨짐)

# After: UTF-8 설정 적용
$null = cmd /c chcp 65001 2>&1
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8

Write-Host "보안 스캔 시작..."
# 출력: 보안 스캔 시작... (정상)

UTF-8 BOM vs UTF-8 (No BOM)

BOM (Byte Order Mark)이란?

파일 맨 앞에 붙는 3바이트 마커: 0xEF 0xBB 0xBF

1
2
3
UTF-8 BOM:    EF BB BF 48 65 6C 6C 6F
UTF-8 No BOM:           48 65 6C 6C 6F
              ↑ BOM      ↑ "Hello"

차이점

특성UTF-8 BOMUTF-8 (No BOM)
크기+3 바이트원본 크기
Windows 호환✅ 우수⚠️ 일부 도구 문제
Unix/Linux 호환⚠️ 일부 스크립트 문제✅ 우수
PowerShell 인식✅ 자동 인식⚠️ 명시 필요
JSON/XML✅ 권장✅ 동일

PowerShell에서 BOM 처리

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# UTF-8 BOM으로 저장 (PowerShell 5.1 기본)
"안녕하세요" | Out-File -FilePath test.txt -Encoding UTF8

# UTF-8 No BOM으로 저장 (PowerShell 7+ 기본)
"안녕하세요" | Out-File -FilePath test.txt -Encoding utf8NoBOM

# BOM 확인
$bytes = [System.IO.File]::ReadAllBytes("test.txt")
if ($bytes.Length -ge 3 -and
    $bytes[0] -eq 0xEF -and
    $bytes[1] -eq 0xBB -and
    $bytes[2] -eq 0xBF) {
    Write-Host "UTF-8 BOM detected"
} else {
    Write-Host "No BOM or different encoding"
}

파일 읽기/쓰기 인코딩

Get-Content

1
2
3
4
5
6
7
8
# PowerShell 5.1 (기본: ASCII)
$content = Get-Content -Path config.json  # ❌ 한글 깨짐

# UTF-8 명시
$content = Get-Content -Path config.json -Encoding UTF8  # ✅ 정상

# PowerShell 7+ (기본: UTF-8 No BOM)
$content = Get-Content -Path config.json  # ✅ 정상

Set-Content

1
2
3
4
5
6
7
# PowerShell 5.1
$data = "한글 데이터"
Set-Content -Path output.txt -Value $data -Encoding UTF8  # ✅ UTF-8 BOM

# PowerShell 7+
Set-Content -Path output.txt -Value $data  # ✅ UTF-8 No BOM
Set-Content -Path output.txt -Value $data -Encoding utf8BOM  # UTF-8 BOM

Out-File

1
2
3
4
5
6
# PowerShell 5.1
"한글" | Out-File -FilePath output.txt  # ❌ UTF-16 LE (기본)
"한글" | Out-File -FilePath output.txt -Encoding UTF8  # ✅ UTF-8 BOM

# PowerShell 7+
"한글" | Out-File -FilePath output.txt  # ✅ UTF-8 No BOM

ConvertFrom-Json / ConvertTo-Json

1
2
3
4
5
6
7
8
9
10
# JSON 파일 읽기 (UTF-8)
$json = Get-Content -Path config.json -Raw -Encoding UTF8 | ConvertFrom-Json

# JSON 파일 쓰기 (UTF-8)
$data = @{
    name = "김철수"
    description = "한글 설명"
}

$data | ConvertTo-Json -Depth 10 | Out-File -FilePath output.json -Encoding UTF8

실전 문제 해결

문제 1: 한글 파일명이 깨짐

1
2
3
4
5
6
7
# ❌ 문제
Get-ChildItem "C:\Users\한글폴더"
# 오류: Cannot find path '...çNìÜíìë' because it does not exist.

# ✅ 해결
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
Get-ChildItem "C:\Users\한글폴더"

문제 2: REST API 응답 한글 깨짐

1
2
3
4
5
6
7
8
# ❌ 문제
$response = Invoke-RestMethod -Uri "https://api.example.com/data"
Write-Host $response.message  # 깨짐

# ✅ 해결
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
$response = Invoke-RestMethod -Uri "https://api.example.com/data" -ContentType "application/json; charset=utf-8"
Write-Host $response.message

문제 3: 로그 파일 한글 깨짐

1
2
3
4
5
6
7
8
9
10
# ❌ 문제
"보안 스캔 완료" | Out-File -Append -FilePath log.txt
# 파일 열면: ë³´ì ìºì  ìë£

# ✅ 해결 1: 인코딩 명시
"보안 스캔 완료" | Out-File -Append -FilePath log.txt -Encoding UTF8

# ✅ 해결 2: 기본 인코딩 설정
$PSDefaultParameterValues['Out-File:Encoding'] = 'utf8'
"보안 스캔 완료" | Out-File -Append -FilePath log.txt

PowerShell 5.1 vs 7+ 인코딩 차이

동작PowerShell 5.1PowerShell 7+
Get-Content 기본ASCIIUTF-8 No BOM
Set-Content 기본ASCIIUTF-8 No BOM
Out-File 기본UTF-16 LEUTF-8 No BOM
ConvertTo-JsonUTF-16 LEUTF-8
콘솔 출력CP949/1252UTF-8

마이그레이션 팁

1
2
3
4
5
6
7
8
9
10
11
12
13
# PowerShell 5.1 스크립트를 7+로 마이그레이션할 때

# Before (5.1)
Get-Content -Path file.txt -Encoding UTF8
Out-File -FilePath output.txt -Encoding UTF8

# After (7+) - 명시적 인코딩 불필요
Get-Content -Path file.txt
Out-File -FilePath output.txt

# 하지만 호환성을 위해 명시하는 것이 안전
Get-Content -Path file.txt -Encoding utf8
Out-File -FilePath output.txt -Encoding utf8

디버깅 팁

1. 현재 인코딩 확인

1
2
3
4
5
6
Write-Host "=== Encoding Information ==="
Write-Host "Console Output Encoding: $([Console]::OutputEncoding.EncodingName)"
Write-Host "Console Input Encoding: $([Console]::InputEncoding.EncodingName)"
Write-Host "Output Encoding: $($OutputEncoding.EncodingName)"
Write-Host "Code Page: $(chcp)"
Write-Host "PowerShell Version: $($PSVersionTable.PSVersion)"

2. 파일 인코딩 감지

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
function Get-FileEncoding {
    param([string]$Path)

    $bytes = [System.IO.File]::ReadAllBytes($Path)

    # BOM 확인
    if ($bytes.Length -ge 3) {
        if ($bytes[0] -eq 0xEF -and $bytes[1] -eq 0xBB -and $bytes[2] -eq 0xBF) {
            return "UTF-8 BOM"
        }
    }

    if ($bytes.Length -ge 2) {
        if ($bytes[0] -eq 0xFF -and $bytes[1] -eq 0xFE) {
            return "UTF-16 LE"
        }
        if ($bytes[0] -eq 0xFE -and $bytes[1] -eq 0xFF) {
            return "UTF-16 BE"
        }
    }

    return "UTF-8 No BOM or ASCII"
}

# 사용 예
Get-FileEncoding -Path "config.json"

3. 인코딩 변환 스크립트

1
2
3
4
5
6
# 모든 .ps1 파일을 UTF-8 BOM으로 변환
Get-ChildItem -Path . -Filter *.ps1 -Recurse | ForEach-Object {
    $content = Get-Content -Path $_.FullName -Raw -Encoding UTF8
    Set-Content -Path $_.FullName -Value $content -Encoding UTF8
    Write-Host "Converted: $($_.Name)"
}

VS Code 설정

VS Code에서 PowerShell 스크립트를 작성할 때도 인코딩 설정이 중요하다.

settings.json

1
2
3
4
5
6
7
8
{
  "files.encoding": "utf8bom",
  "files.autoGuessEncoding": true,
  "[powershell]": {
    "files.encoding": "utf8bom",
    "files.eol": "\r\n"
  }
}

.editorconfig

1
2
3
[*.ps1]
charset = utf-8-bom
end_of_line = crlf

실전 팁 (Best Practices)

1. 스크립트 시작 부분에 인코딩 설정

1
2
3
# 모든 PowerShell 스크립트 맨 위에
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
$PSDefaultParameterValues['*:Encoding'] = 'utf8'

2. JSON 파일은 UTF-8 (No BOM) 권장

1
2
# JSON은 BOM 없이 저장 (표준)
$data | ConvertTo-Json -Depth 10 | Out-File -Encoding utf8NoBOM -FilePath config.json

3. 로그 파일은 UTF-8 BOM 사용

1
2
# Windows에서 Notepad로 열 때 한글이 정상 표시됨
"로그 메시지" | Out-File -Append -Encoding UTF8 -FilePath app.log

4. 외부 프로그램 호출 시 주의

1
2
3
4
5
# cmd.exe는 기본이 CP949
cmd /c dir  # 한글 파일명 깨질 수 있음

# UTF-8로 변경 후 실행
cmd /c chcp 65001 '&' dir

결론 (Conclusion)

PowerShell의 인코딩 문제는 여러 설정을 모두 맞춰야 해결된다.

Key Takeaways

  1. chcp 65001: 콘솔 코드 페이지를 UTF-8로
  2. OutputEncoding: 외부 프로그램 전달 인코딩
  3. Console Encoding: 콘솔 입출력 인코딩
  4. PSDefaultParameterValues: 파일 cmdlet 기본 인코딩
  5. UTF-8 BOM: Windows 환경에서는 BOM 사용 권장

한 곳만 설정하면 안 됩니다. 4곳 모두 설정해야 완벽하게 해결됩니다.

1
2
3
4
5
# 완벽한 UTF-8 설정 (4종 세트)
$null = cmd /c chcp 65001 2>&1
$OutputEncoding = [System.Text.Encoding]::UTF8
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
$PSDefaultParameterValues['*:Encoding'] = 'utf8'

도움이 되셨길 바랍니다! 😀

This post is licensed under CC BY 4.0 by the author.