- 공유 링크 만들기
- X
- 이메일
- 기타 앱
이 글의 목적은 PowerShell 7(pwsh) 설치 이후 Windows PowerShell 5.1과 모듈 경로가 뒤섞여 발생하는 PSModulePath 충돌 문제를 원인별로 진단하고, 실무에서 재발 없이 정리하는 표준 절차를 제공하는 것이다.
1. PSModulePath 충돌이란 무엇인가
PSModulePath는 PowerShell이 모듈을 탐색할 때 참고하는 경로 목록이다. PowerShell 7(pwsh)과 Windows PowerShell 5.1(powershell.exe)은 기본적으로 서로 다른 모듈 생태계를 가진다. 그러나 설치·업데이트·프로필 스크립트·환경변수 설정이 겹치면, 한쪽이 다른 쪽의 경로를 과도하게 포함하거나 순서가 뒤바뀌어 모듈 로딩 결과가 예기치 않게 변한다.
1-1. 대표 증상
- Import-Module이 성공하나 실행 시 타입/어셈블리 오류가 발생하다.
- Get-Module -ListAvailable 결과에 동일 모듈이 여러 경로로 중복 표시되다.
- PSReadLine, Pester, Az, SqlServer, VMware.PowerCLI 등에서 버전 꼬임이 발생하다.
- pwsh에서만 모듈이 안 보이거나, 반대로 powershell.exe에서만 안 보이다.
- 회사 표준 스크립트가 특정 모듈 버전을 기대하는데 다른 버전이 먼저 로드되다.
1-2. 충돌이 자주 생기는 지점
Windows에서는 사용자 범위(User) 모듈 경로와 시스템 범위(AllUsers) 모듈 경로가 각각 존재하고, 제품/버전에 따라 기본 경로가 조금씩 다르다. 또한 환경변수는 프로세스 시작 시점에 고정되므로, 설치 직후 터미널을 재시작하지 않으면 테스트가 왜곡되다.
| 구분 | 설명 | 문제 포인트 |
|---|---|---|
| 환경변수 PSModulePath | OS 레벨 경로 목록이며 세미콜론(;)으로 구분되다. | 사용자/시스템 변수에 중복·오타·순서 역전이 생기다. |
| $env:PSModulePath | 현재 세션에서 사용되는 최종 경로 문자열이다. | 프로필에서 덮어쓰면 세션마다 결과가 바뀌다. |
| $PSVersionTable.PSVersion | 실행 중인 PowerShell 엔진 버전이다. | pwsh(7)과 powershell(5.1)을 혼동하면 원인 파악이 틀어지다. |
| PowerShellGet/PackageManagement | 모듈 설치·업데이트를 담당하다. | 동일 모듈을 서로 다른 경로에 설치하며 충돌이 누적되다. |
2. 먼저 해야 하는 기본 진단(10분 내 원인 분류)
2-1. 현재 실행 엔진 확인
$PSVersionTable Get-Process -Id $PID | Select-Object ProcessName, Path ProcessName이 pwsh이면 PowerShell 7이며, powershell이면 Windows PowerShell 5.1이다. 동일 PC에서 두 엔진을 번갈아 실행하면 PSModulePath는 같아 보여도 모듈 호환성은 달라질 수 있다.
2-2. 세션에서 실제로 쓰는 PSModulePath 확인
$env:PSModulePath -split ';' | ForEach-Object { $_.Trim() } | Where-Object { $_ } | Select-Object -Unique 중복 경로가 존재하는지, 비어 있는 항목이 섞여 있는지, 존재하지 않는 폴더가 포함되는지 확인하다.
2-3. 사용자/시스템 환경변수 원본 확인
[Environment]::GetEnvironmentVariable('PSModulePath','User') -split ';' [Environment]::GetEnvironmentVariable('PSModulePath','Machine') -split ';' 세션 값($env:PSModulePath)은 보통 Machine + User를 조합한 결과이며, 프로필에서 추가 변경이 있으면 추가로 변형되다.
2-4. 모듈 중복 설치 여부 확인
$name = 'PSReadLine' Get-Module -ListAvailable -Name $name | Sort-Object Version -Descending | Select-Object Name, Version, ModuleBase 동일 Name이 서로 다른 ModuleBase에 여러 개 있으면, 경로 순서에 따라 “원치 않는 버전”이 먼저 로드되다.
3. 원인별 해결 전략(가장 안전한 순서)
3-1. 원인 A: PSModulePath에 잘못된 경로가 추가되거나 순서가 꼬이다
가장 흔한 케이스는 설치 스크립트, 레거시 배치파일, 회사 공통 로그인 스크립트가 PSModulePath를 Append 하는 과정에서 중복이 누적되거나, 사용자 변수에 시스템 경로까지 복사해 넣어 순서를 망치는 경우이다.
해결 절차 A-1: “정상 경로 목록”을 기준으로 정리하다
일반적으로 Windows에서 최소한 유지해야 하는 경로는 다음 범주로 나뉘다.
- AllUsers 범위 모듈 경로(프로그램 파일 아래)이다.
- User 범위 모듈 경로(문서/사용자 프로필 아래)이다.
- Windows PowerShell 전용 경로(5.1 기본 모듈)이다.
환경마다 폴더가 다를 수 있으므로, “내 PC에 실제로 존재하는 경로”만 살려야 하다. 다음 스크립트는 존재하는 경로만 필터링하고, 중복을 제거하며, 사용자/시스템 변수에 저장 가능한 형태로 정리하다.
# 1) 현재 세션 PSModulePath를 정리(중복 제거 + 존재 경로만) $paths = $env:PSModulePath -split ';' | ForEach-Object { $_.Trim() } | Where-Object { $_ -and (Test-Path $_) } | Select-Object -Unique # 2) 권장: User와 Machine을 섞어 덮어쓰지 말고, 우선 User만 "최소"로 구성하다 # 일반적으로 User에는 사용자 모듈 경로 1~2개만 유지하는 것이 안전하다 $userCandidates = $paths | Where-Object { $_ -match '\\Users\\' -or $_ -match '\\Documents\\' -or $_ -match '\\OneDrive\\Documents\\' } # 사용자 후보가 비정상적으로 많으면, 문서 아래 Modules만 남기는 보수적 필터를 적용하다 $userMinimal = $userCandidates | Where-Object { $_ -match '\\Documents\\PowerShell\\Modules$' -or $_ -match '\\Documents\\WindowsPowerShell\\Modules$' } | Select-Object -Unique # 3) User PSModulePath를 설정하다(필요한 경우에만) # 값이 비어 있으면 변경하지 말고 원인 재점검을 권장하다 if($userMinimal.Count -gt 0){ $newUser = ($userMinimal -join ';') [Environment]::SetEnvironmentVariable('PSModulePath', $newUser, 'User') $newUser } 해결 절차 A-2: 새 터미널에서 재검증하다
# 새 pwsh/ powershell 창에서 각각 실행하다 $PSVersionTable.PSVersion $env:PSModulePath -split ';' | Select-Object -Unique 환경변수는 기존 세션에 즉시 반영되지 않을 수 있으므로, 반드시 새 창에서 확인하다.
3-2. 원인 B: 프로필에서 PSModulePath를 덮어쓰거나 과도하게 추가하다
$PROFILE 스크립트는 사용자 로그인마다 실행되며, 여기서 $env:PSModulePath를 조작하면 매번 결과가 달라지다. 특히 “= 값”으로 덮어쓰는 패턴은 위험하다.
진단: 프로필 파일 위치와 내용 확인
$PROFILE | Format-List * Test-Path $PROFILE if(Test-Path $PROFILE){ Get-Content $PROFILE -ErrorAction SilentlyContinue | Select-Object -First 200 } 해결: 덮어쓰기 대신 “존재 경로만 안전하게 추가” 패턴으로 바꾸다
# 프로필에 넣는 권장 패턴 예시이다 # 이미 들어 있는지 확인하고, 폴더가 존재할 때만 추가하다
$add = @(
"$HOME\Documents\PowerShell\Modules"
)
$current = $env:PSModulePath -split ';' | ForEach-Object { $.Trim() } | Where-Object { $ }
foreach($p in $add){
if((Test-Path $p) -and ($current -notcontains $p)){
$env:PSModulePath = ($p + ';' + $env:PSModulePath)
}
}
이 방식은 기존 값을 보존하면서 필요한 경로만 앞쪽에 추가하여 우선순위를 부여하다.
3-3. 원인 C: 동일 모듈이 여러 위치에 설치되어 “원치 않는 버전”이 먼저 로드되다
PSModulePath가 정상이어도, 같은 모듈이 사용자 경로와 시스템 경로에 동시에 존재하면 로딩 우선순위에 의해 버전 충돌이 발생하다. 대표적으로 PSReadLine, Pester, Az 계열이 이 문제를 자주 일으키다.
진단: 로딩될 가능성이 높은 후보를 찾다
$target = 'PSReadLine' Get-Module -ListAvailable -Name $target | Sort-Object Version -Descending | Select-Object Name, Version, ModuleBase 해결: “남길 위치 1곳”을 정하고 나머지를 정리하다
운영 원칙은 다음 중 하나로 고정하는 것이 좋다.
- 개인 PC: 사용자(User) 범위에만 설치하여 권한 문제를 줄이다.
- 공용/서버: 시스템(AllUsers) 범위에만 설치하여 표준화를 유지하다.
정리 전에는 어떤 경로의 모듈이 실제로 로드되는지 확인하는 것이 안전하다.
# 실제로 로드되는 모듈 경로 확인이다 Import-Module PSReadLine -Force (Get-Module PSReadLine).Path (Get-Module PSReadLine).ModuleBase 그 다음 “원치 않는 위치”에 있는 모듈을 제거하거나, 우선순위가 뒤로 가도록 경로 순서를 조정하다. 제거는 위험하므로 먼저 백업을 권장하다.
3-4. 원인 D: PowerShell 7에서 Windows PowerShell 모듈을 무리하게 가져오다
PowerShell 7은 호환 가능한 모듈도 많지만, .NET Framework 전용 모듈은 그대로 가져오면 실패하다. 이때 사용되는 기능이 WindowsCompatibility 계열의 “WinPSModulePath” 추가 또는 Import-Module -UseWindowsPowerShell이다.
권장 운영 방식
- 가능하면 PowerShell 7 네이티브 모듈로 전환하다.
- 불가피하면 “해당 모듈만” Windows PowerShell 세션을 통해 로드하다.
- PSModulePath 전체에 WindowsPowerShell 경로를 상시로 섞는 방식은 최소화하다.
실무 팁: 필요한 순간에만 Windows PowerShell을 사용하다
# 모듈이 5.1 전용이면, 작업 단위로 powershell.exe에서 실행하는 방식이 가장 예측 가능하다 powershell.exe -NoProfile -Command "Import-Module SomeLegacyModule; Get-Command -Module SomeLegacyModule" 이 접근은 pwsh의 PSModulePath를 오염시키지 않으면서 레거시 작업을 분리하다.
4. 재발 방지 체크리스트(운영 표준으로 쓰기)
| 체크 항목 | 권장 기준 | 점검 명령 |
|---|---|---|
| User PSModulePath 과다 여부 | 사용자 문서 Modules 경로 중심으로 1~2개 유지하다. | |
| Machine PSModulePath 임의 수정 여부 | 가능하면 변경하지 않다. | |
| 프로필에서 덮어쓰기 여부 | = 로 덮어쓰기 금지, 존재 경로만 조건부 추가하다. | |
| 중복 모듈 설치 여부 | 남길 위치 1곳을 정해 표준화하다. | |
| 세션 혼동 방지 | pwsh/powershell을 명확히 구분하여 테스트하다. | |
5. 현장에서 바로 쓰는 “원클릭 진단” 스크립트
아래 스크립트는 pwsh와 powershell에서 각각 실행해 비교하는 용도이다. 결과를 텍스트로 저장하면 장애 보고와 변경 이력 관리가 쉬워지다.
# PSModulePath 진단 리포트이다 $report = [ordered]@{} $report.Time = (Get-Date).ToString('yyyy-MM-dd HH:mm:ss') $report.Process = (Get-Process -Id $PID).ProcessName $report.PowerShellVersion = $PSVersionTable.PSVersion.ToString() $report.Edition = $PSVersionTable.PSEdition $userVar = [Environment]::GetEnvironmentVariable('PSModulePath','User') $machVar = [Environment]::GetEnvironmentVariable('PSModulePath','Machine') $report.PSModulePath_User = $userVar $report.PSModulePath_Machine = $machVar $paths = ($env:PSModulePath -split ';' | ForEach-Object { $_.Trim() } | Where-Object { $_ }) $report.PSModulePath_Effective_Count = $paths.Count $report.PSModulePath_Effective_Distinct_Count = ($paths | Select-Object -Unique).Count $report.PSModulePath_Missing = ($paths | Where-Object { -not (Test-Path $_) }) -join '; ' $reportObj = [pscustomobject]$report $reportObj "---- Effective Paths ----" $paths | Select-Object -Unique "---- Duplicate Paths ----" $paths | Group-Object | Where-Object { $_.Count -gt 1 } | Select-Object Count, Name FAQ
PowerShell 7 설치 후 pwsh에서 모듈이 안 보이는 이유는 무엇인가?
대부분 PSModulePath 순서 문제이거나, 모듈이 Windows PowerShell 5.1 전용(.NET Framework 기반)이라 pwsh에서 로드되지 않는 문제이다. 먼저 $env:PSModulePath를 분해하여 존재하지 않는 경로와 중복을 제거하고, Get-Module -ListAvailable로 동일 모듈의 설치 위치와 버전을 확인하는 것이 우선이다.
PSModulePath를 레지스트리에서 직접 고쳐도 되는가?
환경변수는 내부적으로 레지스트리 기반이지만, 직접 편집은 오타·인코딩·확장 문자열 처리 실수 위험이 있다. [Environment]::SetEnvironmentVariable로 변경하고, 반드시 새 터미널에서 검증하는 방식이 안전하다.
왜 터미널을 재시작해야 하는가?
환경변수는 프로세스 시작 시점에 로드되며, 이미 떠 있는 pwsh나 Windows Terminal 세션은 변경을 자동 반영하지 않을 수 있다. 따라서 변경 후에는 새 창에서 $env:PSModulePath를 확인해야 한다.
모듈이 여러 경로에 있는데 어떤 것을 남겨야 하는가?
개인 PC는 사용자(User) 범위, 서버나 공용 환경은 시스템(AllUsers) 범위로 표준화하는 것이 일반적으로 관리가 쉽다. 핵심은 동일 모듈을 여러 위치에 두지 않고 한 곳만 남겨 로딩 우선순위를 고정하는 것이다.
PowerShell 7에서 Windows PowerShell 모듈을 쓰기 위해 PSModulePath에 WindowsPowerShell 경로를 계속 넣어도 되는가?
상시 혼합은 재발 위험이 크다. 레거시 모듈이 꼭 필요하면 해당 작업만 powershell.exe에서 수행하거나, 필요한 모듈만 제한적으로 다루는 방식으로 분리하는 것이 안전하다.
- 워드 페이지 번호 초기화 안됨 해결법: 섹션 나누기·머리말 연결 끊기·번호 다시 시작 설정 완벽 가이드
- Windows Search 인덱스 중지 오류 0x8004117B 해결 방법 (Windows 10/11)
- Schannel 36887 치명적 오류(이벤트 36887) 해결 방법과 원인별 점검 체크리스트
- 워드 목차 업데이트 안될 때 완전 해결 가이드(자동목차 안됨, TOC 오류 해결법)
- 파워포인트 레이저 포인터 안보임 해결 방법: 발표 화면에서 포인터가 사라질 때 1분 점검 가이드
- MS Word 한영 폰트 자동변경 차단 방법 완벽 가이드