‘새 PC에서 스크립트가 “이 시스템에서는 스크립트 실행이 사용하지 않도록 설정되어 있으므로…”라는 오류와 함께 동작하지 않는다’ ‘일단 -ExecutionPolicy Bypass를 붙였더니 동작해서, 모든 작업에 그렇게 적어 두었다’ ‘공유 폴더에 둔 .ps1이 특정 사용자의 단말에서만 서명 오류가 난다’ ── PowerShell의 실행 정책은 사내 자동화를 진행하다 보면 거의 확실히 부딪히는 벽입니다. 그리고 많은 현장에서 구조를 이해하지 못한 채 ‘Bypass로 덮어버리는’ 대응이 쌓여 갑니다.
까다로운 점은 실행 정책이 ‘무엇을 지키기 위한 기능인지’ 오해하기 쉽다는 것입니다. 보안 기능이라고 생각해 지나치게 엄격하게 설정해서 업무가 멈춘다. 반대로 ‘어차피 의미가 없다’며 전부 Bypass로 해 버려서, 실수를 막는 마지막 안전장치까지 벗겨 버린다. 둘 다 구조를 알고 있으면 피할 수 있습니다.
이 글에서는 중소기업의 정보시스템 담당자, 그리고 PowerShell로 사내 정형 작업을 자동화하고 있는 분을 대상으로, 실행 정책의 정체와 범위의 우선순위, Zone.Identifier(이른바 Mark of the Web)와의 관계, 그리고 스크립트 서명을 통한 배포 운영까지를 공식 문서의 근거와 함께 정리합니다.
1. 먼저 결론
- 실행 정책은 보안 경계가 아니라 안전장치입니다. 공식 문서는 ‘실행 정책은 사용자의 조작을 제한하는 보안 시스템이 아니다’, ‘스크립트 내용을 명령줄에 입력하면 간단히 우회할 수 있다’고 명확히 밝히고 있습니다. 목적은 기본 규칙을 정해 의도하지 않은 실행(실수로 인한 사고)을 막는 것입니다.1
- 실행 정책이 영향을 미치는 것은 스크립트 실행뿐이며, 대화형 명령어 실행은 언제나 가능합니다. Windows PowerShell 5.1의 기본값은 클라이언트 OS에서는 Restricted(스크립트 실행 불가), Windows Server에서는 RemoteSigned입니다. PowerShell 7에서는 RemoteSigned가 기본값으로 되어 있습니다.21
- 정책에는 5가지 범위가 있으며, 우선순위는 MachinePolicy > UserPolicy > Process > CurrentUser > LocalMachine입니다. MachinePolicy/UserPolicy는 그룹 정책 전용으로,
Set-ExecutionPolicy로는 변경할 수 없고 명령줄 지정으로도 덮어쓸 수 없습니다.13 - RemoteSigned가 서명을 요구하는 것은 ‘인터넷에서 유래한’ 스크립트뿐입니다. 유래 판정은 파일에 붙는 Zone.Identifier 대체 데이터 스트림(Mark of the Web)으로 이루어지며, 내용을 확인한 뒤
Unblock-File로 제거하면 정책을 바꾸지 않고도 실행할 수 있습니다.14 - AllSigned는 로컬에서 작성한 것을 포함한 모든 스크립트에 신뢰된 게시자의 서명을 요구합니다. 서명은
Set-AuthenticodeSignature로 부여하며, 파일 끝에# SIG #주석 블록으로 삽입됩니다.15 - 서명에는 반드시 타임스탬프(-TimestampServer)를 붙입니다. 타임스탬프가 있으면 서명 인증서의 기한이 만료된 후에도 스크립트가 계속 유효합니다. 코드 서명 인증서는 대부분 유효 기간이 1년이므로, 이를 생략하면 매년 시한폭탄이 됩니다.65
- 자체 서명 인증서는 테스트 용도로만 사용합니다. 자체 서명으로 서명한 스크립트는 다른 컴퓨터에서는 실행할 수 없습니다. 조직 배포에는 인증 기관(사내 CA 또는 상용 CA)이 발급한 코드 서명 인증서를 사용합니다.57
- 조직 차원에서 통제하려면 그룹 정책의 ‘스크립트 실행 사용’으로 일원 관리합니다. 이 설정은 PowerShell 쪽의 모든 범위 설정보다 우선합니다.1
2. 실행 정책의 정체 ── ‘보안 경계’가 아니라 ‘안전장치’
먼저 전제를 확인합니다. 공식 문서(about_Execution_Policies)의 서술은 솔직합니다. 실행 정책은 PowerShell이 구성 파일을 불러오고 스크립트를 실행하는 조건을 제어하는 ‘안전 기능(safety feature)’이며, ‘사용자의 조작을 제한하는 보안 시스템이 아니다’. 스크립트를 실행할 수 없는 사용자라도 스크립트 내용을 명령줄에 붙여 넣으면 같은 처리를 실행할 수 있기 때문입니다. 실행 정책의 역할은 기본 규칙을 설정하고, 이를 의도치 않게 위반하는 것을 막는 것이라고 명시되어 있습니다.1 입문 문서에서도 ‘보안 경계가 아니다. 의도적으로 스크립트를 실행하려는 사용자는 막을 수 없다’는 내용이 반복해서 나옵니다.2
이런 위치를 파악해 두면 운영 설계 방침이 정해집니다. ‘실행 정책을 엄격하게 했으니 공격을 막을 수 있다’도, ‘어차피 우회할 수 있으니 무의미하다’도 둘 다 틀렸습니다. 공격 대책은 별도 계층(애플리케이션 제어, 최소 권한, 감사 로그)의 몫이고, 실행 정책은 사고 방지의 몫입니다.8
주요 정책의 차이를 정리합니다.1
| 정책 | 스크립트 실행 | 서명 요구 | 위치 |
|---|---|---|---|
| Restricted | 불가(개별 명령어만) | ─ | Windows PowerShell 5.1의 클라이언트 OS 기본값2 |
| AllSigned | 가능 | 모든 스크립트・구성 파일에 요구. 미분류 게시자는 실행 전 확인 | 서명 운영이 가능한 조직용 |
| RemoteSigned | 가능 | 인터넷에서 유래한 스크립트에만 요구. 로컬 작성분은 불필요 | 실무 표준. PowerShell 7의 기본값1 |
| Unrestricted | 가능 | 없음(인트라넷 영역 밖은 경고) | 비Windows의 기본값(변경 불가)1 |
| Bypass | 가능 | 없음. 경고도 프롬프트도 없음 | PowerShell을 기반으로 자체 보안 모델을 가진 애플리케이션 내장용1 |
간과하기 쉽지만, Restricted는 업무 스크립트뿐만 아니라 프로필(.ps1)이나 모듈(.psm1), 서식 구성 파일(.ps1xml)의 로드까지 막습니다.1 ‘새 단말에서 프로필이 로드되지 않는다’의 원인이 실행 정책이었다는 것은 흔히 접하는 상담입니다.
3. 범위와 우선순위 ── ‘설정했는데 바뀌지 않는다’의 정체
실행 정책은 하나의 값이 아니라, 5가지 범위마다 설정할 수 있고, 우선순위가 높은 쪽이 유효값이 됩니다.1
| 범위 | 설정 수단 | 저장 위치 | 우선순위 |
|---|---|---|---|
| MachinePolicy | 그룹 정책(컴퓨터 구성) | GPO | 1(최우선) |
| UserPolicy | 그룹 정책(사용자 구성) | GPO | 2 |
| Process | -ExecutionPolicy 시작 매개변수 / -Scope Process |
환경 변수 $Env:PSExecutionPolicyPreference(세션 종료 시 사라짐) |
3 |
| CurrentUser | Set-ExecutionPolicy -Scope CurrentUser |
사용자 구성 | 4 |
| LocalMachine | Set-ExecutionPolicy(기본 범위, 관리자 권한 필요) |
모든 사용자 공통 구성 | 5 |
‘설정했는데 바뀌지 않는다’는 문제의 원인 분리는 유효값이 아니라 목록을 보는 것이 정석입니다.
# 실효 정책뿐 아니라, 어떤 범위가 적용되고 있는지 반드시 확인한다
Get-ExecutionPolicy -List
# 예: LocalMachine을 AllSigned로 해 두어도, CurrentUser의 RemoteSigned가 이긴다
# Scope ExecutionPolicy
# ----- ---------------
# MachinePolicy Undefined
# UserPolicy Undefined
# Process Undefined
# CurrentUser RemoteSigned
# LocalMachine AllSigned
# 자신의 환경만 바꾼다면 관리자 권한이 필요 없는 CurrentUser 범위가 간편하다
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
CurrentUser는 LocalMachine보다 우선하므로, 위 예시의 유효 정책은 RemoteSigned입니다.1 Set-ExecutionPolicy는 기본적으로 LocalMachine 범위에 기록하므로 관리자 권한이 필요하지만, CurrentUser 범위라면 일반 사용자도 변경할 수 있습니다.3
그리고 조직 관리의 본명은 그룹 정책입니다. ‘스크립트 실행 사용(Turn on Script Execution)’ 정책은 PowerShell 쪽에서 설정한 모든 범위보다 우선합니다. 사용 안 함으로 설정하면 Restricted에 해당하고, 사용으로 설정하면 ‘모든 스크립트 허용(Unrestricted)’, ‘로컬 스크립트와 원격 서명된 스크립트 허용(RemoteSigned)’, ‘서명된 스크립트만 허용(AllSigned)’ 중에서 선택할 수 있으며, 관리 템플릿의 Windows 구성 요소\Windows PowerShell 아래에 있습니다. 컴퓨터 구성은 사용자 구성보다 우선합니다.1 GPO로 관리되는 환경에서는 Set-ExecutionPolicy가 설정을 저장은 하지만 실제로 적용되지는 않으며, 충돌을 설명하는 메시지가 표시됩니다.3
여기서 중요한 귀결이 하나 있습니다. GPO로 관리하고 있다면, 작업이나 바로가기에 적힌 -ExecutionPolicy Bypass는 적용되지 않습니다. Process 범위 지정은 LocalMachine/CurrentUser 구성에는 이기지만 그룹 정책에는 이기지 못한다고 명시되어 있습니다.1 ‘Bypass를 적으면 어떻게든 된다’가 통하는 것은, 반대로 말하면 조직 차원에서 실행 정책을 관리하지 않는 환경뿐입니다.
4. Zone.Identifier(Mark of the Web)와 Unblock-File
RemoteSigned의 ‘원격(인터넷에서 유래)’은 파일이 놓인 위치가 아니라 표시로 판정됩니다. 브라우저 등의 프로그램은 다운로드한 파일에 대체 데이터 스트림을 추가해 ‘인터넷에서 온 파일’로 표시합니다.1 이 스트림이 Zone.Identifier이며, 인터넷 영역을 나타내는 값 3이 들어 있습니다. 이른바 Mark of the Web입니다.4
대체 데이터 스트림(Alternate Data Streams)은 NTFS의 기능입니다. NTFS에서는 하나의 파일이 여러 데이터 스트림을 가질 수 있으며, 평소 보는 ‘파일 내용’은 이름 없는 기본 스트림에 들어 있습니다. 그것과는 별도로 파일명:스트림명이라는 표기로 이름 붙은 스트림을 추가할 수 있는 구조입니다.9 Zone.Identifier는 그 이름 붙은 스트림 중 하나이므로, 스크립트 본문은 1바이트도 바뀌지 않았는데 실행 가부만 달라집니다. 내용이 같아도 단말에 따라 동작하거나 동작하지 않는 것은 이 때문이며, 반대로 NTFS 이외의 파일 시스템(USB 메모리의 FAT32 등)을 거치면 스트림째로 사라지므로 표시가 없어져 동작하게 되는 경우도 있습니다.
RemoteSigned 환경에서 이 표시가 붙은 미서명 스크립트를 실행하려고 하면 ‘디지털 서명되어 있지 않습니다’라는 오류로 차단됩니다. 대처는 두 단계입니다.
# 1) 먼저 어느 파일이 차단되어 있는지 확인한다(읽기만 하는 안전한 작업)
Get-Item -Path C:\Tools\*.ps1 -Stream Zone.Identifier -ErrorAction SilentlyContinue
# 2) 내용을 검토해 안전하다고 판단된 것만 차단을 해제한다
# (Unblock-File은 Zone.Identifier 스트림을 제거한다. 실행 정책 자체는 바뀌지 않는다)
Unblock-File -Path C:\Tools\Get-InventoryReport.ps1
Unblock-File은 Zone.Identifier 대체 데이터 스트림을 제거하는 명령어로, 탐색기 속성에 있는 ‘차단 해제(Unblock)’ 버튼과 같은 동작입니다. 실행 정책을 느슨하게 하지 않고 확인이 끝난 파일만 통과시킬 수 있다는 점이 핵심입니다.4 공식 문서도 ‘사용하기 전에 파일과 출처를 확인하고 안전함을 검증할 것’을 필수 절차로 정하고 있습니다.43
반대 방향의 함정도 알아 둘 가치가 있습니다. 모든 입수 경로가 Mark of the Web을 붙이는 것은 아닙니다. curl.exe나 Invoke-WebRequest, Invoke-RestMethod로 다운로드한 파일에는 인터넷 영역 표시가 붙지 않을 수 있다고 명시되어 있습니다.1 즉 RemoteSigned는 ‘다운로드한 위험한 파일을 전부 막는다’는 보증이 아닙니다(그렇기 때문에 안전장치인 것입니다). 또한 UNC 경로와 인터넷 경로를 구분하지 않는 구성의 시스템에서는 공유 폴더 위의 스크립트가 RemoteSigned로 인해 실행을 거부당하는 경우가 있다는 주의 사항도 있습니다.1 ‘공유에 둔 .ps1이 일부 단말에서만 멈춘다’면 영역 설정과 Zone.Identifier 유무를 의심해 보십시오.
또한, 다운로드한 실행 파일(.exe) 쪽에서 비슷한 증상을 일으키는 SmartScreen의 구조는 「Windows에서 ‘Windows에 의해 PC가 보호되었습니다’가 나타나는 이유」에서 다루고 있습니다.
5. 스크립트 서명의 실무 ── Set-AuthenticodeSignature와 타임스탬프
AllSigned 운영, 혹은 RemoteSigned 환경에서 배포물에 서명하는 운영으로 나아가려면 코드 서명 인증서가 필요합니다. 입수 경로는 세 가지로 정리할 수 있습니다.5
| 입수 경로 | 신뢰되는 범위 | 판단 |
|---|---|---|
자체 서명(New-SelfSignedCertificate) |
자신의 컴퓨터뿐. 다른 단말에서는 실행 불가 | 테스트・검증 전용. 배포에는 사용하지 않음57 |
| 사내 CA(인증 기관) 발급 | 사내 CA를 신뢰하도록 구성한 조직 내 단말 | AD 도메인 환경의 본명. 인증서 발급・폐기를 조직에서 통제 가능 |
| 상용 CA 발급(유료) | Windows 전반(공용 CA를 신뢰 완료) | 사외에 스크립트를 배포하는 경우 |
공식 문서의 정리도 동일해서, ‘인증 기관이 발급하는 인증서는 다른 컴퓨터에서도 신뢰된다’, ‘자체 제작한 인증서는 무료지만 자신의 컴퓨터 전용이며 테스트 목적에 한정해야 한다’고 되어 있습니다.5 사내 배포가 목적이라면 Active Directory 인증서 서비스(AD CS) 등의 사내 CA에서 코드 서명 인증서를 발급하는 것이 현실적입니다.
사내 CA에서 발급하는 경우, 다음에 무엇을 할 것인가
‘사내 CA가 현실적이다’로 이야기를 끝내면 다음 발걸음을 내딛을 수 없으므로 절차를 적어 둡니다. AD CS는 공개 키 기반(PKI)을 제공하는 Windows Server의 역할로, 인증 기관(CA) 역할 서비스 외에 웹 등록이나 온라인 응답자(OCSP) 등의 역할 서비스로 구성됩니다.10
- 사내 CA가 있는지 확인한다. 먼저 사내에 AD CS의 엔터프라이즈 CA가 있는지를 정보시스템 쪽에서 확인합니다. 없는 경우 코드 서명만을 위해 CA를 신설하는 것은 무거운 결정입니다. 인증서 1장의 구매 비용과, CA 구축・백업・폐기 목록(CRL) 게시・키 보호 같은 운영 수고를 비교해, 상용 CA 구매와 저울질해 보십시오.
- 코드 서명용 인증서 템플릿을 준비해 받는다. CA 쪽의 작업입니다. 기본 ‘코드 서명’ 템플릿을 복제하고, 복제한 쪽에서 유효 기간・키 길이・신청 가능한 보안 그룹(서명 담당자로만 한정)을 설정한 다음, ‘인증 기관’ 관리 콘솔에서 발급 대상 템플릿에 추가해 받습니다. 기본 템플릿을 직접 편집하지 않는 이유는 도메인 전체에 영향이 미쳐 되돌리기 어렵기 때문입니다.
-
서명 담당자가 인증서를 요청한다. 서명할 단말에서
Get-Certificate명령어에 템플릿 이름을 지정해 요청합니다. 발급되면 그대로 개인 저장소에 들어갑니다(이 명령어가 인증서를 저장할 수 있는 곳은My저장소뿐입니다).11# 사내 엔터프라이즈 CA에 템플릿 이름을 지정해 요청한다(Windows 통합 인증) # 'CodeSigning' 부분은 CA 관리자가 발급 대상으로 공개한 템플릿 이름으로 바꾼다 $result = Get-Certificate -Template 'CodeSigning' -Url ldap: ` -CertStoreLocation Cert:\CurrentUser\My $result.Status # Issued이면 발급 완료, Pending이면 승인 대기 - 신뢰를 각 단말에 배포한다. 사내 CA의 루트 인증서를 ‘신뢰할 수 있는 루트 인증 기관’ 저장소에, 서명에 사용하는 게시자 인증서를 ‘신뢰할 수 있는 게시자’ 저장소에, 그룹 정책(컴퓨터 구성 > 정책 > Windows 설정 > 보안 설정 > 공개 키 정책)으로 배포합니다. 공개 키 정책 아래의 각 저장소를 마우스 오른쪽 버튼으로 클릭해 인증서를 가져오는 절차가 공식적으로 안내되어 있습니다.12 여기까지 해 두면 AllSigned 환경에서 나오는 ‘이 신뢰되지 않은 게시자의 소프트웨어를 실행하시겠습니까?’라는 프롬프트를 운영에서 없앨 수 있습니다.15
CA 쪽(절차 2)은 정보시스템만으로 완결되지 않는 경우가 많으므로, 절차 1의 확인과 절차 4의 배포 방침을 먼저 정한 뒤 CA 관리자와 상담하면 이야기가 빨리 진행됩니다.
도메인에 참여하지 않은 환경(워크그룹)에서는 어떻게 할 것인가
이 글의 대상 독자인 중소기업에서는 애초에 AD 도메인이 없거나, 일부 단말만 참여하지 않은 경우도 있습니다. GPO도 사내 CA도 사용할 수 없다는 전제라면 다음 순서로 현실적인 해법을 쌓아 갑니다.
- 실행 정책은 단말별로 설정하고, 통일되어 있는지 확인한다.
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser(모든 사용자에게 적용하려면 관리자 권한으로 LocalMachine)를 키팅 절차서에 넣습니다.3 GPO에 의한 강제가 없는 이상 단말별로 임의로 바뀔 여지가 남으므로,Get-ExecutionPolicy -List의 결과를 재고 조사 시점에 확인하는 운영과 세트로 둡니다. - 스크립트의 정본을 한 곳으로 하고, 쓰기를 제한한다. 공유 폴더 한 곳을 정본으로 정하고, 쓰기 권한은 관리자에게만 부여합니다. 실행 정책이 막는 것은 ‘실수’뿐이므로, 변조를 막는 것은 NTFS 접근 권한의 몫입니다.
- 서명까지 요구한다면, 자체 서명 인증서를 배포할지 상용 CA를 구매할지를 비용으로 비교한다. 공식 문서는 ‘자체 서명 인증서로 서명한 스크립트는 다른 컴퓨터에서는 실행할 수 없다’, ‘공유하고 싶은 스크립트에는 적합하지 않다’고 하고 있습니다.5 다만 이는 기본 상태에 대한 설명으로, 다른 단말이 그 인증서를 신뢰하지 않기 때문에 동작하지 않는다는 의미입니다. 뒤집어 말하면, 신뢰 쪽을 배포하면 동작합니다. 다음 항목에서 나누어 정리합니다.
- Mark of the Web의 취급을 절차서에 적는다. 메일이나 외부 공유를 통해 받은
.ps1에는 표시가 붙어 있는 경우가 있으므로, ‘내용을 검토한 뒤Unblock-File‘까지를 절차로 명문화합니다(4장).4
자체 서명 인증서를 워크그룹에서 사용한다면
‘자체 서명은 서명한 단말에서만 사용할 수 있다’에서 멈추면 단말이 10대, 20대인 회사에 상용 CA 구매를 강요하는 셈이 됩니다. 실제로는 인증서의 공개 부분을 각 단말에 배포하면 AllSigned를 통과할 수 있습니다. GPO 대신 수작업・설치 프로그램・MDM(Intune 등)으로 배포한다는 차이만 있을 뿐입니다.
배포하는 것은 공개 부분뿐이며, 비밀 키는 서명하는 단말에서 내보내지 않습니다.
# 【서명하는 단말에서 1회】공개 부분만 내보낸다(-Cert는 비밀 키를 포함하지 않는다)
$cert = Get-ChildItem Cert:\CurrentUser\My -CodeSigningCert |
Where-Object Subject -eq 'CN=KomuraSoft Code Signing (Test)'
Export-Certificate -Cert $cert -FilePath .\KomuraSoftCodeSigning.cer
# 【각 단말에서 1회・관리자 권한 필요】루트와 발행자 양쪽에 넣는다.
# 루트에 넣지 않으면 서명 검증 자체가 통과되지 않고(자체 서명이므로 자신이 루트),
# 발행자에 넣지 않으면 AllSigned의 프롬프트가 계속 나타난다
Import-Certificate -FilePath .\KomuraSoftCodeSigning.cer `
-CertStoreLocation Cert:\LocalMachine\Root
Import-Certificate -FilePath .\KomuraSoftCodeSigning.cer `
-CertStoreLocation Cert:\LocalMachine\TrustedPublisher
그런 다음, 떠안게 될 비용을 미리 살펴봐 두십시오. 상용 CA와의 차이는 여기서 드러납니다.
| 논점 | 자체 서명을 배포 | 상용 CA를 구매 |
|---|---|---|
| 초기 비용 | 0원. 다만 전 단말 배포 작업이 필요 | 인증서 구매 비용(연간) |
| 비밀 키 보호 | 서명 단말이 통째로 방어선. 이 키가 유출되면 배포 대상 전 단말이 신뢰하는 코드에 서명할 수 있게 된다. 키의 보관 장소와 반출 금지를 정해 둔다 | 마찬가지로 중요하지만, HSM이나 클라우드 서명 서비스라는 선택지가 있다 |
| 폐기 | 수단이 없음. 유출되면 각 단말에서 저장소를 삭제하러 돌아다녀야 함 | CRL/OCSP로 폐기 가능 |
| 만료 | 갱신할 때마다 전 단말에 다시 배포(타임스탬프를 붙여 두면 기존 서명은 만료 후에도 유효합니다5) | 단말 쪽 작업 불필요 |
| 새 단말 | 키팅 절차에 포함시켜야 함 | 불필요 |
| ‘신뢰할 수 있는 루트’에 넣는 영향 | 그 인증서 1장을 단말이 신뢰함. CA가 아니므로 하위 인증서를 발급할 수는 없지만, 그 키로 서명한 것은 무엇이든 통과함 | 변경 없음 |
단말 수가 적고, 키팅 절차가 관리되고 있으며, 서명 단말을 지킬 수 있다면 자체 서명을 배포하는 구성으로 충분합니다. 반대로 단말이 계속 늘어난다, 키팅이 특정 담당자에게 의존한다, 서명 단말을 누구나 만질 수 있다 ── 이 중 어느 하나라도 해당된다면, 폐기와 갱신의 번거로움을 상용 CA에 외주하는 판단이 더 저렴하게 먹힙니다.
인증서 저장소와 Cert: 드라이브
서명 코드로 들어가기 전에 Cert:에 대해 한마디 해 둡니다. Cert:는 PowerShell의 인증서 공급자가 제공하는 가상 드라이브로, 인증서 저장소를 파일 시스템처럼 경로로 따라갈 수 있습니다.13 구조는 Cert:\<저장소 위치>\<저장소 이름>의 2계층이며, 저장소 위치는 CurrentUser(로그온 중인 사용자용)와 LocalMachine(컴퓨터 전체용) 두 가지, 저장소 이름은 My(개인), Root(신뢰할 수 있는 루트 인증 기관), TrustedPublisher(신뢰할 수 있는 게시자) 등입니다. 인증서 한 장 한 장은 지문(Thumbprint)으로 식별되며, Get-ChildItem으로 나열할 수 있습니다.13
즉 Cert:\CurrentUser\My는 ‘현재 사용자의 개인 저장소’이며, 다음에 나오는 Get-ChildItem -Path Cert:\CurrentUser\My -CodeSigningCert는 ‘거기에 있는 코드 서명용 인증서를 전부 꺼내라’는 의미입니다. -CodeSigningCert는 확장 키 사용법(EKU)에 코드 서명을 가진 인증서로 한정하기 위한, 인증서 공급자 고유의 매개변수입니다.13
먼저 테스트용 자체 서명 인증서로 흐름을 확인합니다.
# 테스트용 코드 서명 인증서를 만든다(자체 서명 ── 이 단말에서만 신뢰됨)
$params = @{
Subject = 'CN=KomuraSoft Code Signing (Test)'
Type = 'CodeSigningCert'
CertStoreLocation = 'Cert:\CurrentUser\My'
HashAlgorithm = 'sha256'
}
$cert = New-SelfSignedCertificate @params
New-SelfSignedCertificate는 테스트 목적의 자체 서명 인증서를 만드는 명령어로, -Type CodeSigningCert를 지정하면 코드 서명용 확장이 들어갑니다. 유효 기간은 기본값으로 1년입니다.7 자체 서명 인증서를 AllSigned 환경 테스트에 사용하는 경우, 해당 단말의 신뢰할 수 있는 루트 인증 기관 저장소에 등록해야 합니다.5
서명의 실전은 이 한 줄입니다.
# 인증서 저장소에서 코드 서명 인증서를 가져와 서명한다
# -CodeSigningCert는 "코드 서명에 사용할 수 있는 인증서"로 한정할 뿐이므로,
# 기한 내이고 비밀 키를 가진 것으로 한정하고, 여러 개 있는 환경에서는 Subject나 Thumbprint로 특정한다
$cert = Get-ChildItem -Path Cert:\CurrentUser\My -CodeSigningCert |
Where-Object { $_.HasPrivateKey -and $_.NotAfter -gt (Get-Date) -and
$_.Subject -eq 'CN=KomuraSoft Code Signing (Test)' } |
Sort-Object NotAfter -Descending |
Select-Object -First 1 # 갱신 등으로 같은 Subject가 여러 개일 때는 유효 기한이 가장 먼 것 1장으로 한정한다
# 타임스탬프는 필수. 인증서 기한이 만료되어도 서명이 계속 유효하다
# URL은 RFC 3161에 대응하는 타임스탬프 서비스를 지정한다. 인증서 발급처(구매처)의 안내가 최우선.
# 예: DigiCert가 공개하고 있는 타임스탬프 서버 http://timestamp.digicert.com
Set-AuthenticodeSignature -FilePath .\Invoke-NightlyBatch.ps1 -Certificate $cert `
-HashAlgorithm SHA256 -TimestampServer 'http://timestamp.digicert.com'
# 서명 상태는 Get-AuthenticodeSignature로 확인할 수 있다(Valid/NotSigned/HashMismatch 등)
# TimeStamperCertificate가 비어 있지 않으면 타임스탬프가 붙어 있는 것이다
Get-AuthenticodeSignature -FilePath .\Invoke-NightlyBatch.ps1 |
Format-List -Property Status, SignerCertificate, TimeStamperCertificate
- 서명은 파일 끝의
# SIG #주석 블록으로 삽입됩니다. 기존 서명이 있으면 교체됩니다. 즉 서명 후에 스크립트를 한 글자라도 고치면 서명은 무효가 됩니다. 이것이 변조 감지로 기능합니다. -TimestampServer를 지정하면 인증서의 유효 기한이 만료되어도 스크립트가 실패하지 않게 됩니다. 서명의 유효성은 ‘서명 인증서가 유효한 동안’ 또는 ‘인증서가 유효했던 시점에 서명되었음을 타임스탬프 서버가 검증할 수 있는 한’이며, 코드 서명 인증서는 대부분 유효 기간이 1년이므로 타임스탬프가 장기 운영의 생명선입니다.65 URL은 가상의 값이 아니라 실재하는 RFC 3161 대응 서비스를 지정합니다. 1순위 후보는 인증서 발급처(구매처인 CA)가 안내하는 URL로, 예를 들어 DigiCert는http://timestamp.digicert.com을 공개하고 있습니다.14 참고로 AD CS의 역할 서비스에는 타임스탬프 응답용이 포함되어 있지 않으므로10, 사내 CA가 발급한 인증서로 서명하는 경우에도 타임스탬프 취득처는 외부 서비스를 사용하는 구성이 되는 것이 일반적입니다. 이 부분은 사내 CA 도입 검토 시 간과하기 쉬우므로, 네트워크적으로 해당 URL에 도달할 수 있는지(프록시・방화벽 허용)까지 포함해 확인하십시오. 서명 후Get-AuthenticodeSignature의TimeStamperCertificate가 비어 있지 않은지 보면 실제로 타임스탬프가 붙었는지 확인할 수 있습니다.- Windows PowerShell 5.1이나 PowerShell 7.2 이전 버전에서 서명하는 스크립트는 ASCII 또는 UTF8NoBOM으로 저장해야 했습니다. PowerShell 7.2 이후는 임의의 인코딩으로 서명된 스크립트를 지원합니다.5 5.1이 남아 있는 현장에서는 일본어 주석이 들어간 스크립트의 인코딩 때문에 서명 검증이 깨지는 사고가 일어나기 쉬우므로 주의가 필요합니다. 5.1과 7의 차이 전반은 「Windows PowerShell 5.1과 PowerShell 7의 차이와 이전」을 참조하십시오.
AllSigned 환경에서는 서명이 되어 있어도 게시자를 아직 신뢰함/거부로 분류하지 않은 경우, 실행 시 ‘이 신뢰되지 않은 게시자의 소프트웨어를 실행하시겠습니까?’라는 프롬프트가 나타납니다. ‘항상 실행’을 선택하면 이후 해당 게시자에 대해서는 확인하지 않습니다.15 사내 CA 운영에서는 발행자 인증서를 각 단말의 ‘신뢰할 수 있는 게시자’에도 함께 배포해 두면 이 확인을 운영에서 없앨 수 있습니다.
6. 실무의 정석(판단표) ── ‘Bypass로 덮기’에서 서명 운영까지
사내 스크립트의 배포・실행 통제는 다음 판단표로 생각하는 것이 정석입니다.
| 논점 | 선택지 | 판단 기준 |
|---|---|---|
| 환경 쪽 정책 | Restricted 유지 / RemoteSigned / AllSigned | 자동화를 추진한다면 RemoteSigned가 하한선. 서명 체계가 있다면 AllSigned1 |
| 설정 배포 | 각자 Set-ExecutionPolicy / 그룹 정책 | 도메인 환경이라면 GPO가 유일한 선택. 모든 범위보다 우선하고 임의 변경도 막을 수 있음1 |
| 배포물의 신뢰 | 미서명+공유 내 배치 / 코드 서명 | 미서명 운영은 변조를 감지할 수 없음. 정기적으로 실행되는 운영 스크립트부터 순서대로 서명으로 |
| 인증서 | 자체 서명 / 사내 CA / 상용 CA | 사내 배포는 사내 CA. 자체 서명은 테스트 한정, 사외 배포는 상용 CA5 |
| 다운로드물의 처리 | 정책을 완화 / 검토 후 Unblock-File | 정책은 건드리지 않고 확인이 끝난 파일만 통과시킴4 |
| 정기 작업의 시작 | -ExecutionPolicy Bypass를 상시 사용 / 환경 정책 정비+서명 |
Bypass 상시 사용은 안전장치의 포기. GPO 관리하에서는 애초에 적용되지 않음1 |
마지막 행을 보충합니다. ‘ExecutionPolicy Bypass로 덮어버리는’ 운영의 문제는 보안 구멍을 여는 것 그 자체가 아닙니다(실행 정책은 애초에 경계가 아니므로). 문제는 다음 세 가지입니다.
- 안전장치의 포기 ── 실수로 다른 스크립트를 실행하는 사고, 변조된 스크립트를 모르고 실행하는 사고를 막는 마지막 그물을 영구적으로 벗겨 버리게 됩니다.
- 통제와의 괴리 ── GPO로 실행 정책을 관리하기 시작하는 순간 Bypass 지정은 적용되지 않게 되어, 덮어 두었던 작업이 일제히 실패합니다.1 ‘동작하던 이유’가 관리 밖의 빠져나갈 구멍이었다는 기술 부채입니다.
- 원인 조사의 교란 ── Bypass가 여기저기 흩어져 있으면 환경의 유효 정책으로부터 동작을 추측할 수 없게 되어, 단말별 차이 조사(왜 이 단말에서만 실패하는가)가 난항을 겪습니다.
Bypass 자체는 PowerShell을 내장한 애플리케이션이 독자적인 보안 모델로 통제하는 구성을 위해 마련된 설정입니다.1 사람이 작성한 운영 스크립트의 시작 옵션으로 상시 사용할 것이 아니라고 확실히 정리해 두십시오. 작업 스케줄러에서의 안전한 정기 실행 구성은 「작업 스케줄러 작업이 실행되지 않는다・0x1로 끝난다 ── 원인 분리와 안전한 운영 설계」에서 자세히 다루고 있습니다.
7. 정리
- 실행 정책은 보안 경계가 아니라 안전장치입니다. 공격 대책은 별도 계층에서 수행하고, 실행 정책에는 ‘실수로 인한 사고 방지’를 맡깁니다.
- 정책은 5가지 범위를 가지며, MachinePolicy > UserPolicy > Process > CurrentUser > LocalMachine 순으로 우선됩니다. 원인 분리는
Get-ExecutionPolicy -List부터 시작합니다. - RemoteSigned가 보고 있는 것은 Zone.Identifier(Mark of the Web)입니다. 확인이 끝난 파일은
Unblock-File로, 정책을 완화하지 않고 통과시킵니다. - 서명은
Set-AuthenticodeSignature로 수행하며,-TimestampServer를 반드시 지정합니다. 인증서는 사내 배포라면 사내 CA 발급, 자체 서명은 테스트 한정입니다. - 조직 통제는 그룹 정책의 ‘스크립트 실행 사용’으로 일원화합니다. 이 설정은 모든 범위와
-ExecutionPolicy지정보다 우선합니다. -ExecutionPolicy Bypass의 상시 사용은 안전장치의 포기이며, GPO 관리하에서는 적용되지 않습니다. 환경 정책 정비와 서명 운영으로 ‘덮개’를 불필요하게 만드는 것이 정도입니다.
관련 글
- PowerShell 명령어의 기초 — 가장 먼저 익힐 조작과 안전한 사용법
- Windows에서 ‘Windows에 의해 PC가 보호되었습니다’가 나타나는 이유
- 작업 스케줄러 작업이 실행되지 않는다・0x1로 끝난다 ── 원인 분리와 안전한 운영 설계
- PowerShell의 에러 처리와 재실행 설계 ── try/catch가 먹히지 않는 함정부터 exit code·재시도의 정석까지
- Windows PowerShell 5.1과 PowerShell 7의 차이 ── 사내 스크립트 이행 실무 가이드
- 그 배치 파일, PowerShell로 이전해야 할까요? ── cmd/bat 자산의 재고 조사와 이전 판단
관련 상담 영역
합동회사 코무라소프트에서는 사내 PowerShell 스크립트의 실행 정책・서명 운영 설계, 그룹 정책을 통한 전개 검토, ‘특정 단말에서만 스크립트가 동작하지 않는다’와 같은 환경 차이 조사를 다루고 있습니다. 기존 배치・스크립트 자산을 안전한 운영으로 이전하는 지원도 가능합니다.
참고 링크
-
Microsoft Learn, about_Execution_Policies. 실행 정책이 안전 기능이며 사용자를 제한하는 보안 시스템이 아니라는 점, 각 정책(AllSigned/Bypass/RemoteSigned/Restricted/Unrestricted 등)의 정의, 5가지 범위와 우선순위, Process 범위가 $Env:PSExecutionPolicyPreference에 저장되며 GPO에는 이기지 못한다는 점, 그룹 정책 ‘Turn on Script Execution’이 모든 범위보다 우선한다는 점, 다운로드 파일에 대체 데이터 스트림이 붙는 것과 curl.exe 등에서는 표시가 붙지 않는 경우가 있다는 점, UNC 경로에 대한 주의 사항에 대해. ↩ ↩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
-
Microsoft Learn, Chapter 1 - Getting started with PowerShell. 실행 정책이 보안 경계가 아니라는 점, Windows 10/11의 기본값이 Restricted, Windows Server 2016/2019/2022의 기본값이 RemoteSigned라는 점, 실행 정책이 스크립트에만 영향을 미치며 대화형 명령어는 항상 실행할 수 있다는 점에 대해. ↩ ↩2 ↩3
-
Microsoft Learn, Set-ExecutionPolicy. 기본 범위가 LocalMachine이며 관리자 권한이 필요하다는 점, MachinePolicy/UserPolicy 범위는 변경할 수 없다는 점, 그룹 정책을 덮어쓸 수 없으며 충돌 시 메시지가 표시된다는 점, Unblock-File이 실행 정책을 변경하지 않고 스크립트의 차단을 해제하는 예시에 대해. ↩ ↩2 ↩3 ↩4 ↩5
-
Microsoft Learn, Unblock-File. Unblock-File이 인터넷 영역을 나타내는 값 3의 Zone.Identifier 대체 데이터 스트림을 제거한다는 점, 탐색기 속성의 ‘차단 해제’ 버튼과 같은 동작이라는 점, 사용하기 전에 파일과 출처의 안전성을 확인해야 한다는 점, Get-Item -Stream으로 Zone.Identifier가 붙은 파일을 검출할 수 있다는 점에 대해. ↩ ↩2 ↩3 ↩4 ↩5 ↩6
-
Microsoft Learn, about_Signing. 서명 대상 파일 종류, 인증 기관 발급 인증서와 자체 서명 인증서의 차이(자체 서명은 테스트 용도로 한정되며 다른 컴퓨터에서는 실행 불가), 서명이 # SIG # 주석 블록으로 추가된다는 점, PowerShell 7.2 이전에는 ASCII/UTF8NoBOM 저장이 필요했다는 점, 타임스탬프 서버에 의해 인증서 기한 후에도 서명이 계속 유효하다는 점, 신뢰되지 않은 게시자의 프롬프트에 대해. ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7 ↩8 ↩9 ↩10 ↩11 ↩12 ↩13 ↩14 ↩15
-
Microsoft Learn, Set-AuthenticodeSignature. Authenticode 서명 부여, 기존 서명의 교체, -TimestampServer 매개변수에 의해 인증서 기한 만료 후에도 스크립트가 실패하지 않게 된다는 점, Cert: 드라이브의 -CodeSigningCert 매개변수로 비밀 키가 있는 코드 서명 인증서를 가져오는 예시에 대해. ↩ ↩2 ↩3
-
Microsoft Learn, New-SelfSignedCertificate. 테스트 목적의 자체 서명 인증서를 만드는 명령어라는 점, -Type 매개변수로 코드 서명 인증서를 지정할 수 있다는 점, 유효 기간의 기본값이 1년이라는 점에 대해. ↩ ↩2 ↩3
-
Microsoft Learn, PowerShell security features. 실행 정책이 스크립트 실행 환경의 보안을 높이는 여러 기능 중 하나로 자리매김되어 있으며, 악의적인 스크립트의 실행 방지를 돕는 안전 기능으로 되어 있다는 점에 대해. ↩
-
Microsoft Learn, File Streams. NTFS 파일 시스템에서는 파일에 기록되는 데이터가 스트림으로 유지되며, 하나의 파일이 여러 스트림을 가질 수 있다는 점, 기본 데이터 스트림에는 이름이 없다는 점, 이름 붙은 스트림이 ‘파일명:스트림명:스트림 종류’ 형식으로 지정된다는 점에 대해. ↩
-
Microsoft Learn, Active Directory Certificate Services documentation. AD CS가 암호화・디지털 인증서・서명 기능을 위한 공개 키 기반(PKI)을 제공한다는 점, 인증 기관・웹 등록・온라인 응답자(OCSP)・네트워크 장치 등록 서비스・인증서 등록 웹 서비스 등의 역할 서비스로 구성된다는 점(타임스탬프 응답 서비스는 포함되지 않는다는 점)에 대해. ↩ ↩2
-
Microsoft Learn, Get-Certificate. 인증서 요청을 등록 서버로 전송해 응답을 설치하는 명령어라는 점, -Template으로 인증서 템플릿의 이름 또는 OID를 지정한다는 점, 자격 증명을 지정하지 않으면 Kerberos 인증이 사용된다는 점, -CertStoreLocation으로 지정할 수 있는 것은 My 저장소뿐이라는 점, 발급 완료 시 Status가 Issued・보류 시 Pending이 된다는 점에 대해. ↩
-
Microsoft Learn, Configure trusted roots and disallowed certificates in Windows. 그룹 정책(컴퓨터 구성 > 정책 > Windows 설정 > 보안 설정 > 공개 키 정책)에서 ‘신뢰할 수 있는 루트 인증 기관’ 등의 저장소로 인증서를 가져와 배포하는 절차에 대해. ↩
-
Microsoft Learn, about_Certificate_Provider. PowerShell의 인증서 공급자가 인증서 저장소와 인증서에 대한 접근을
Cert:드라이브로 제공한다는 점, CurrentUser와 LocalMachine이라는 두 저장소 위치와 그 아래의 각 저장소, 인증서가 지문으로 식별된다는 점, Get-ChildItem 등으로 파일 시스템과 마찬가지로 따라갈 수 있다는 점, -CodeSigningCert 매개변수가 확장 키 사용법에 코드 서명을 가진 인증서를 가져온다는 점에 대해. ↩ ↩2 ↩3 -
DigiCert, RFC 3161 compliant Time Stamp Authority server. DigiCert가 RFC 3161을 준수하는 타임스탬프 서버
http://timestamp.digicert.com을 공개하고 있으며, Authenticode 서명의 타임스탬프에 이용할 수 있다는 점에 대해. ↩
관련 기사
같은 태그를 공유하는 최신 기사입니다. 더 가까운 주제로 지식을 넓힐 수 있습니다.
PowerShell에서 자격 증명을 안전하게 다루기 ── 평문 비밀번호를 스크립트에서 추방한다
PowerShell 스크립트의 평문 비밀번호를 안전한 보관으로 옮기는 절차를 정리합니다. SecureString의 실체와 한계, Export-Clixml에 의한 DPAPI 저장의 구조, SecretManagement/SecretStore를 언제 ...
PowerShell Remoting(WinRM) 입문 ── 여러 대의 Windows를 일괄 관리하기
PowerShell Remoting(WinRM)으로 여러 대의 Windows를 일괄 관리하는 입문서입니다. 동작 원리와 포트 5985/5986, Enable-PSRemoting으로 일어나는 일, 워크그룹의 TrustedHosts, Invoke-C...
PowerShell 스크립트가 느릴 때 살펴볼 곳 ── 배열・파이프라인・대조의 급소
PowerShell 스크립트가 느려지는 대표적인 원인을 정리합니다. 배열의 +=가 O(n^2)이 되는 이유, 파이프라인과 foreach의 차이, 대조의 해시테이블화, 파일 I/O 개선, 그리고 올바른 측정법까지 실무 관점에서 설명합니다.
Write-Host를 그만두다 ── PowerShell의 출력 스트림과 로그 설계
PowerShell 6가지 출력 스트림의 구분 사용법, Write-Host가 안고 있는 문제와 올바른 쓰임새, 함수의 반환값이 오염되는 원인, -Verbose나 -InformationVariable을 통한 호출 측 제어, 구조화 로그를 남기는 방...
PowerShell의 병렬 처리 ── ForEach-Object -Parallel과 작업(Job)의 구분 사용
ForEach-Object -Parallel·Start-ThreadJob·Start-Job의 차이와 구분 사용, $using:와 스레드 안전성, ThrottleLimit을 정하는 법, 오히려 느려지는 경우까지 실무 관점에서 정리합니다.
관련 토픽
이 기사와 가까운 토픽 페이지입니다. 기사를 출발점 삼아 관련 서비스와 다른 기사로 이어집니다.
Windows 기술 토픽
Windows 개발, 장애 조사, 기존 자산 활용에 관한 KomuraSoft LLC 기사를 모은 토픽 허브입니다.
이 주제와 연결되는 서비스
이 기사는 다음 서비스 페이지로 이어집니다. 가까운 입구부터 확인해 주세요.
Windows 앱 개발
상주 처리, 장비 연동, 운영 로그, 유지 보수 가능한 구조가 필요한 Windows 데스크톱 애플리케이션을 지원합니다.
자주 묻는 질문
이 기사 주제에 대해 상담 시 자주 나오는 질문을 모았습니다.
- PowerShell의 실행 정책은 보안 기능인가요?
- 공식 문서는 '실행 정책은 사용자의 조작을 제한하는 보안 시스템이 아니다'라고 명확히 밝히고 있습니다. 스크립트 내용을 명령줄에 붙여 넣으면 간단히 우회할 수 있기 때문입니다. 실행 정책의 목적은 기본 규칙을 정해 '실수로 의도하지 않은 스크립트를 실행해 버리는' 사고를 막는 안전장치이며, 공격자를 막는 보안 경계로 설계에 끌어들여서는 안 됩니다. 공격 대책은 별도의 계층(애플리케이션 제어, 최소 권한 등)에서 수행합니다.
- RemoteSigned와 AllSigned는 어떻게 다른가요?
- RemoteSigned는 인터넷에서 유래한(Mark of the Web이 붙은) 스크립트에 대해서만 신뢰된 게시자의 서명을 요구하며, 로컬에서 작성한 스크립트는 서명 없이 실행할 수 있습니다. AllSigned는 로컬에서 작성한 것을 포함한 모든 스크립트와 구성 파일에 서명을 요구하며, 아직 분류되지 않은 게시자의 스크립트는 실행 전에 확인을 요구합니다. 사내에서 서명 운영(코드 서명 인증서 배포와 서명 절차)을 갖출 수 있다면 AllSigned, 그만한 체계가 없다면 RemoteSigned가 현실적인 선택입니다.
- 다운로드한 스크립트가 '디지털 서명되어 있지 않습니다'라는 메시지와 함께 실행되지 않는 이유는 무엇인가요?
- 브라우저 등으로 다운로드한 파일에는 Zone.Identifier라는 대체 데이터 스트림이 붙어 '인터넷에서 온 파일'로 취급되기 때문입니다. 실행 정책이 RemoteSigned인 경우, 이 표시가 붙은 미서명 스크립트는 실행이 차단됩니다. 내용을 확인해 안전하다고 판단되면 Unblock-File 명령어나 탐색기 속성의 '차단 해제'로 Zone.Identifier를 제거하면, 실행 정책을 바꾸지 않고도 실행할 수 있습니다.
- 사내 배포용 PowerShell 스크립트는 어떻게 운영하는 것이 현실적인가요?
- 선택지는 크게 두 가지입니다. 첫 번째는 RemoteSigned와 파일 서버 배치 조합으로, 서명 체계를 만들지 않고도 시작할 수 있지만 배포 경로에 따라 Mark of the Web이 붙어 실행이 막힐 수 있고 스크립트 변조도 감지할 수 없습니다. 두 번째는 AllSigned와 서명 운영 조합으로, 코드 서명 인증서(사내 CA 발급이 현실적)로 Set-AuthenticodeSignature를 통해 서명하고 그룹 정책으로 정책을 일원 관리합니다. 실행 정책 통제와 변조 감지가 효과를 발휘하는 대신, 인증서 배포・갱신에 운영 비용이 듭니다.
- 작업 스케줄러에서 -ExecutionPolicy Bypass를 계속 지정해도 괜찮은가요?
- 동작은 하지만 권장하지 않습니다. 우선, 그룹 정책으로 실행 정책을 관리하는 환경에서는 명령줄의 ExecutionPolicy 지정이 그룹 정책을 이기지 못하므로 애초에 적용되지 않습니다. 또한 Bypass를 상시 사용하는 것은 '실수로 인한 실행을 막는' 안전장치를 스스로 제거하는 운영이며, 조직의 정책과 현장의 실태가 점점 괴리되는 원인이 됩니다. 항구적인 운영으로 삼으려면 그룹 정책이나 관리자에 의한 Set-ExecutionPolicy로 환경 측 정책을 적절히 설정하고, 스크립트 쪽은 서명으로 신뢰를 나타내는 것이 순리입니다.
- 스크립트 서명에 타임스탬프(-TimestampServer)가 왜 필요한가요?
- 서명의 유효성은 원칙적으로 서명 인증서의 유효 기간에 묶여 있지만, 타임스탬프가 있으면 '인증서가 유효했던 시점에 서명되었다'는 사실을 타임스탬프 서버가 보증하므로 인증서 기한이 만료된 후에도 스크립트를 계속 사용할 수 있습니다. 코드 서명 인증서는 대부분 유효 기간이 1년 정도이므로, 타임스탬프 없이 운영하면 매년 '어느 날 갑자기 사내의 서명된 스크립트가 일제히 동작하지 않게 되는' 위험을 안게 됩니다. 서명할 때는 반드시 -TimestampServer를 지정하세요.