빌드노트
ConvertFrom-Json이 name과 Name을 함께 읽지 못할 때
대소문자만 다른 name과 Name은 유효한 JSON에서도 PowerShell의 기본 객체 변환을 실패시킬 수 있다. PowerShell 7.6.6에서 -AsHashtable의 키·값·왕복 결과를 확인하고, 철자까지 같은 중복 키와 구분한다.
PowerShell에서 {"name":"lower","Name":"upper"}를 ConvertFrom-Json으로 읽으면 JSON 문법이 맞아도 변환 오류가 날 수 있다. 기본 반환형인 PSCustomObject의 속성 이름은 대소문자만으로 구별되지 않기 때문이다. 원본에서 두 키를 별개로 쓰고 있다면 -AsHashtable로 읽고, 정확한 철자의 문자열 키로 각각 조회한다.
아래 결과는 Windows의 PowerShell 7.6.6에서 합성 JSON으로 확인했다. PowerShell 7이 설치된 터미널에서 pwsh -NoProfile을 연 뒤, 먼저 실행 버전과 옵션 지원 여부를 확인한다. 추가 패키지나 입력 파일은 필요 없다.
$PSVersionTable.PSVersion.ToString()
(Get-Command ConvertFrom-Json).Parameters.ContainsKey('AsHashtable')
7.6.6
True
두 번째 값이 False라면 아래 옵션을 그대로 쓸 수 없다. 공식 문서의 매개변수 설명 (새 탭에서 열림)에 따르면 -AsHashtable은 PowerShell 6.0부터 제공된다. Windows PowerShell 5.1은 이번에 실행하지 않았으며, 이 글의 해결 명령을 5.1용으로 적용하지 않는다.
오류가 가리키는 것은 키 충돌이다
같은 세션에서 두 키를 가진 문자열을 기본 방식으로 변환하고, 실패하면 오류 식별자를 출력한다.
$json = '{"name":"lower","Name":"upper"}'
try {
$json | ConvertFrom-Json -ErrorAction Stop
} catch {
$_.FullyQualifiedErrorId
}
KeysWithDifferentCasingInJsonString,Microsoft.PowerShell.Commands.ConvertFromJsonCommand
이 환경에서는 오류 메시지도 대소문자가 다른 키를 포함한다고 설명하며 -AsHashTable을 안내했다. 대조 입력인 {"name":"lower"}는 기본 변환에 성공했다. 키 하나를 추가하자 발생한 위 오류는 쉼표나 따옴표가 빠졌다는 뜻이 아니라, name과 Name을 기본 객체의 서로 다른 속성으로 만들 수 없다는 뜻이다.
JSON의 이름 비교에서는 이 두 문자열을 구별할 수 있다. RFC 8259의 문자열 비교 설명 (새 탭에서 열림)은 문자 코드 단위의 비교를 다룬다. 변환을 통과시키려고 모든 키를 소문자로 바꾸면 두 이름이 하나로 겹친다. 원본이 두 키를 구별하는 데이터라면 반환형을 바꾸는 쪽이 맞다.
두 값을 남기려면 반환형을 바꾼다
앞에서 만든 $json에 -AsHashtable을 적용한 뒤, 키 목록과 두 값, 다시 만든 JSON을 확인한다.
$data = $json | ConvertFrom-Json -AsHashtable
$data.Keys
$data['name']
$data['Name']
ConvertTo-Json -InputObject $data -Compress
name
Name
lower
upper
{"name":"lower","Name":"upper"}
키 목록에 두 철자가 모두 있고, 각 조회는 서로 다른 값을 반환했다. 다시 만든 JSON에도 두 이름과 값이 남았다. 별도로 이 결과를 -AsHashtable로 재변환했을 때도 두 값을 각각 조회할 수 있었다. 이후 단계에서 JSON을 다시 읽는다면 그 변환에도 같은 반환형 선택이 필요하다.
문자열 키를 대괄호에 넣는 조회 방식은 해시 테이블 값 접근 문서 (새 탭에서 열림)에서 확인할 수 있다. 여기서는 $data['name']과 $data['Name']을 그대로 구별해 쓴다. 변환 결과를 수작업으로 만든 @{}에 다시 옮겨도 같은 동작이라고 가정하면 안 된다. 별도 비교에서 @{}에 두 철자를 차례로 대입하자 항목은 하나만 남았다.
이번 반환형은 System.Management.Automation.OrderedHashtable이었다. 공식 문서는 PowerShell 7.3부터 이 타입으로 입력 키 순서를 보존한다고 설명한다. 앞선 버전의 해시 테이블 순서까지 위 출력과 같다고 기대해서는 안 된다. 이 예제에서 보존을 판단한 기준은 두 키의 철자와 각 값이다.
실제 입력에 적용할 때는 $json을 변환 전의 JSON 문자열로 바꾸고, 조회할 두 키를 원본 철자에 맞춘다. 이미 다른 변환에서 키를 합치거나 값을 잃었다면 -AsHashtable을 나중에 붙여도 되살릴 수 없다. 원본 문자열을 읽는 단계부터 바꿔야 한다.
철자까지 같은 중복 키는 보존되지 않는다
name과 Name을 보존했다는 결과를 같은 이름의 반복에도 적용할 수는 없다. 이번에는 첫 글자까지 같은 name을 두 번 넣어 항목 수와 값을 확인한다.
$repeated = '{"name":"first","name":"last"}' |
ConvertFrom-Json -AsHashtable
$repeated.Count
$repeated['name']
ConvertTo-Json -InputObject $repeated -Compress
1
last
{"name":"last"}
같은 철자의 키는 한 항목이 됐고 마지막 값만 남았다. -AsHashtable은 같은 이름으로 들어온 모든 값을 모아 주는 옵션이 아니다. RFC 8259의 객체 규칙 (새 탭에서 열림)은 이름의 유일성을 권고하며, 중복된 이름을 받는 구현들의 동작이 다를 수 있다고 설명한다. 두 값이 모두 필요하다면 생산자와 배열이나 서로 다른 필드 이름을 쓰는 데이터 형식을 정해야 한다.
또한 값이 빠진 {"name":}는 기본 변환과 -AsHashtable 모두 실패했다. 실제 오류가 위의 키 충돌 식별자와 다르다면 오류 내용을 확인하고 JSON 입력 문제부터 구분한다. 이 옵션은 잘못된 JSON 문법을 고치지 않는다.
검증한 범위는 PowerShell 7.6.6의 평평한 객체와 문자열 값이다. 다른 PowerShell 버전·운영체제, 중첩 구조 전체의 왕복 보존은 실행하지 않았다. 자기 입력에서도 필요한 키와 값을 변환 직후 확인해야 한다.