about_Case-Sensitivity
about_Case-Sensitivity
PowerShell은 대소문자 구분을 최대한 느슨하게 하면서도, 원래 쓰인 형태(case)는 그대로 보존해요. 이 문서에서는 PowerShell이 어디서 대소문자를 무시하는지, 또 어떤 특수한 경우에 대소문자를 구분하는지 하나씩 정리해드릴게요. 어렵게 느껴질 수 있는데, "원칙은 무시하되 형태는 보존"이라는 한 줄만 머리에 넣고 따라오시면 돼요.
출처: Microsoft Learn – about_Case-Sensitivity · 원문(Markdown): GitHub
본문
간단한 설명
PowerShell은 대소문자를 보존하면서도 가능한 한 대소문자를 구분하지 않아요.
자세한 설명
기본 원칙은 이래요. PowerShell은 원래 쓰인 대소문자를 보존하고, 운영체제(OS)를 망가뜨리지 않는 선에서 가능한 모든 곳의 대소문자를 구분하지 않아요.
Windows 계열 시스템은 대부분의 작업에서 대소문자를 구분하지 않지만, Windows가 아닌 시스템은 특히 파일 시스템과 환경 변수 접근에서 대부분의 작업을 대소문자를 구분해서 처리해요.
다음 영역에서는 어떤 시스템에서라도 PowerShell이 대소문자를 구분하지 않는다고 보장해요:
- 변수 이름
- 연산자 이름
- 사전(Dictionary)이 아닌 멤버 접근
- PowerShell 명령과 별칭의 명령 검색. 단
ExternalScript와Application명령은 제외돼요. - 매개 변수 이름과 별칭
- PowerShell 언어 키워드
using namespace문- 형식 리터럴
#Requires문- 주석 기반 도움말 키워드
- PSProvider 이름
- PSDrive 이름
- 범위 한정자(Scope modifier)
특수 사례
일반 원칙과 다르게 동작하는 특별한 경우들을 하나씩 볼게요.
모듈 이름은 대소문자를 구분하지 않아요 (예외 있음)
모듈의 name은 순전히 PowerShell 개념이라 대소문자를 구분하지 않게 다뤄요. 그런데 이게 폴더 이름과 강하게 연결되어 있어서, 밑바탕이 되는 운영체제에서는 그 폴더 이름이 대소문자를 구분할 수 있어요. 대소문자만 다른 같은 이름의 모듈 두 개를 가져오는 것은, 서로 다른 경로에서 같은 이름의 모듈을 가져오는 것과 똑같이 동작해요.
모듈 이름은 가져올 때 쓴 그 대소문자 그대로 세션 상태(session state)에 저장돼요. 이렇게 저장된 이름은 Update-Help가 새 도움말 파일을 찾을 때 사용해요. Microsoft 도움말 파일을 제공하는 웹 서비스는 대소문자를 구분하는 파일 시스템을 쓰거든요. 그래서 가져온 모듈 이름의 대소문자가 안 맞으면 Update-Help가 도움말 파일을 못 찾고 오류를 보고해요.
PS providers:
FileSystem과 Environment provider는 Windows가 아닌 시스템에서 대소문자를 구분해요. 보통 그런 시스템에서는 경로나 환경 변수를 다루는 작업이 대소문자를 구분하죠.
다만 와일드카드 일치(wildcard matching)는 provider cmdlet이 시스템과 무관하게 대소문자를 구분하지 않아요.
PS /home/user01> New-Item -Path Temp:foo.txt -Force
Directory: /tmp
UnixMode User Group LastWriteTime Size Name
-------- ---- ----- ------------- ---- ----
-rw-r--r-- user01 user01 1/6/2026 10:53 0 foo.txt
PS /home/user01> (Get-Item -Path Temp:FOO.txt).Name
Get-Item: Cannot find path 'Temp:/FOO.txt' because it does not exist.
PS /home/user01> (Get-Item -Path Temp:F[O]*.txt).Name
foo.txt
PS /home/user01> (Get-Item -Path Env:hOM[E]).Name
HOME
매개 변수 집합 이름은 대소문자를 구분해요.
DefaultParameterSetName의 대소문자는 반드시 ParameterSetName과 일치해야 해요.
.NET 메서드는 보통 기본적으로 대소문자를 구분해요.
예를 들면 이런 경우가 있어요.
일반적인 PowerShell 연산자에 해당하는 .NET 메서드(명시적으로 옵션을 켜지 않으면)는 다음과 같아요:
Array.Contains(), String.Contains(), String.Replace(),
Regex.Match(), Regex.Replace()
리플렉션(Reflection) — 멤버 이름은 정확한 대소문자를 써야 해요.
사전(Dictionary)을 리터럴로 만들지 않고 만들 때예요. 예를 들면:
[hashtable]::new()는 키를 대소문자 구분해서 만들지만, 해시테이블 리터럴 @{}는 대소문자를 구분하지 않는 키를 만들어요.
[ordered]::new()는 키를 대소문자 구분해서 만들지만, [ordered] @{}는 대소문자를 구분하지 않는 키를 만들어요. 그리고 [ordered] 형식 단축키(accelerator)는 PowerShell v5.1 이하에서는 쓸 수 없어요.
Enum.Parse()를 명시적으로 호출하면 기본적으로 대소문자를 구분하지만, PowerShell은 보통 enum을 대소문자 구분 없이 다뤄요.
-Unique 계열 cmdlet:
Select-Object -Unique와 Get-Unique는 기본적으로 대소문자를 구분해요. -CaseInsensitive 스위치는 PS v7.4에서 추가됐어요.
Sort-Object -Unique는 기본적으로 대소문자를 구분하지 않지만, 원래부터 -CaseSensitive 스위치가 있었어요.
Compare-Object는 기본적으로 대소문자를 구분하지 않지만 -CaseSensitive 스위치가 있어요. [char] 형식 비교는 기본적으로 대소문자를 구분하고, 문자열 비교는 기본적으로 대소문자를 구분하지 않아요.
# Compare strings - Equal (no output)
Compare-object -ReferenceObject a -DifferenceObject A
# Compare chars - Different (output)
Compare-object -ReferenceObject ([char] 'a') -DifferenceObject ([char] 'A')
ConvertFrom-Json -AsHashtable:
-AsHashtable은 PS v6에서 추가됐어요. PS v7.3에서 이 매개 변수를 지정하면 JSON 키를 대소문자 구분해서 다루도록 바뀌었어요.
이 매개 변수를 쓰면 Management.Automation.OrderedHashtable 형식의 객체가 나오는데, 여기서 키는 대소문자를 구분해요.
이 매개 변수 없이 쓰면 JSON 키는 대소문자를 구분하지 않게 다뤄져요. 출력은 사용자 지정 객체(custom object)이고, 마지막에 나온 대소문자 무시 키가 이겨요.
기본적으로 대소문자를 구분하지 않지만 -CaseSensitive 스위치가 있어요.
Windows PowerShell v5.1에서는 -CaseSensitive와 -AsHashtable을 함께 쓰면 대소문자를 구분하지 않는 해시테이블이 만들어져요. 키가 중복되면 오류가 나요.
[pscustomobject] @{ Foo = 'Bar' }, [pscustomobject] @{ Foo = 'bar' } |
Group-Object -Property Foo -CaseSensitive -AsHashtable
Group-Object : The objects grouped by this property cannot be expanded
because there is a key duplication. Provide a valid value for the
property, and then try again.
At line:2 char:11
+ Group-Object -Property Foo -CaseSensitive -AsHashtable
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [Group-Object], Exception
+ FullyQualifiedErrorId : The objects grouped by this property
cannot be expanded because there is a key duplication. Provide a valid
value for the property, and then try again.,Microsoft.PowerShell.Comman
ds.GroupObjectCommand
PowerShell v7 이상에서는 -CaseSensitive와 -AsHashtable을 함께 쓰면 대소문자를 구분하는 해시테이블이 만들어져요. 키가 중복돼도 오류가 나지 않아요.
[pscustomobject] @{ Foo = 'Bar' }, [pscustomobject] @{ Foo = 'bar' } |
Group-Object -Property Foo -CaseSensitive -AsHashtable
Name Value
---- -----
Bar {@{Foo=Bar}}
bar {@{Foo=bar}}
기본적으로 대소문자를 구분하지 않지만 -CaseSensitive 스위치가 있어요.
Get-Command와 명령 검색/호출:
대소문자를 구분하는 파일 시스템에서는 ExternalScript와 Application 명령의 검색과 호출이 대소문자를 구분해요.
Get-Command의 와일드카드 일치도 이런 형식에서는 대소문자를 구분해요.
그 밖의 모든 CommandTypes는 대소문자를 구분하지 않아요.
기본적으로 연산자는 대소문자를 구분하지 않아요.
-c* 연산자는 대소문자를 구분해요.
-i* 연산자는 대소문자를 구분하지 않아요.
-replace/-ireplace는 기본적으로 대소문자를 구분하지 않지만, 명명된 캡처 그룹(named capture groups)과 함께 쓸 때는 예외적으로 대소문자를 구분해요.
'Bar' -replace '(?<a>a)', '${a}${a}'
# Baar
'Bar' -replace '(?<a>a)', '${A}${A}'
# B${A}${A}r
-split과 -isplit은 대소문자를 구분하지 않아요.
-csplit은 IgnoreCase 옵션을 지정하지 않는 한 대소문자를 구분해요.
'Bar' -csplit 'A', 0
# Bar
'Bar' -csplit 'A', 0, 'IgnoreCase'
# B
# r
대소문자를 구분하는 파일 시스템이어도 탭 완성과 globbing은 둘 다 대소문자를 구분하지 않아요. 예를 들어 TabExpansion2 -inputScript ./foo는 Linux에서 ./Foo.txt로 완성돼요.
대소문자를 구분하는 파일 시스템에서는 using module과 using assembly가 경로를 지정할 때 대소문자를 구분해요.
모듈 이름만 쓰는 using module은 대소문자를 구분하지 않아요.
using namespace는 항상 대소문자를 구분하지 않아요.
`n 같은 이스케이프 시퀀스는 대소문자를 구분해요.