PowerShell Remoting(WinRM) 입문 ── 여러 대의 Windows를 일괄 관리하기

· · PowerShell, Windows, WinRM, 원격 관리, 자동화, 운영 개선, 보안, 스크립트

「Windows Update 이후 서버 20대가 전부 제대로 부팅됐는지 확인해 줘」「전 거점 PC에서 그 설정값이 어떻게 되어 있는지 조사해 줬으면 해」── 이런 요청을, 원격 데스크톱으로 한 대씩 로그인해서 확인하고 있지는 않으신가요? 한 대에 3분이 걸려도 20대면 1시간입니다. 사람은 도중에 지치기 마련이고, 확인 누락도 생깁니다.

PowerShell Remoting은 이 「여러 대에 대한 같은 작업」을 명령 한 번으로 바꾸는 구조입니다. Windows에는 WinRM이라는 원격 관리의 기반이 표준으로 탑재되어 있으며, Windows Server에서는 기본적으로 활성화되어 있습니다. 즉 많은 현장에서 추가 소프트웨어 없이 오늘부터 사용할 수 있습니다. 그럼에도 「왠지 무섭다」「워크그룹에서 연결이 안 돼서 포기했다」는 이야기를 자주 듣습니다.

이 글에서는 중소기업의 정보시스템 담당자와 운영 담당자를 대상으로, Remoting의 구조(무엇이 어떤 포트에서 동작하고 누가 연결할 수 있는지)부터 Invoke-Command에 의한 일괄 실행, 도메인 환경과 워크그룹 환경의 차이, second hop 문제와 같은 유명한 함정, 「연결이 안 될」 때의 원인 분리, 그리고 「읽기부터 시작하는」 안전한 운영까지 정리합니다.

전제로 하는 환경

  • 연결받는 쪽: Windows Server 2012 이후의 Windows Server에서는 PowerShell Remoting이 기본적으로 활성화되어 있습니다.1 클라이언트용 Windows에서는 WinRM 서비스가 기본적으로 비활성화되어 있으므로, Enable-PSRemoting으로 활성화해야 합니다.1
  • 연결하는 쪽: 이 글의 명령 예시는 Windows PowerShell 5.1과 PowerShell 7 양쪽 모두에 존재하는 명령어(cmdlet)만으로 작성했습니다. 다만 WSMan: 드라이브나 Test-WSMan 등 WS-Management 관련 명령어는 Windows에서 실행하는 PowerShell에서만 사용할 수 있습니다(Linux·macOS의 PowerShell에서는 6장의 SSH 기반 Remoting을 사용합니다).2
  • 권한: 원격 쪽의 설정 변경(Enable-PSRemoting, TrustedHosts, 리스너)은 모두 관리자 권한으로 실행한 PowerShell이 필요합니다.1
  • 네트워크: 도메인 환경과 워크그룹 환경을 모두 다룹니다. 차이점은 3장에 정리했습니다.

1. 먼저 결론

  • PowerShell Remoting은 WinRM(WS-Management 구현) 위에서 동작하며, 기본적으로 HTTP 5985 / HTTPS 5986 포트를 사용합니다. HTTP라도 통신 내용에는 인증 프로토콜에 의한 메시지 수준 암호화가 걸립니다.3
  • 연결할 수 있는 것은 기본적으로 원격 쪽 Administrators 그룹의 구성원뿐이며, 세션은 연결한 사용자의 컨텍스트에서 동작합니다. 「Remoting을 활성화하면 누구나 들어올 수 있다」는 뜻이 아닙니다.3
  • Enable-PSRemoting이 하는 일은 명확하게 정의되어 있습니다. WinRM 서비스의 시작과 자동 시작화, 리스너 생성, 방화벽 예외, 세션 구성 활성화입니다. Windows Server에서는 기본적으로 활성화되어 있고, 클라이언트 Windows에서는 수동으로 활성화합니다.43
  • 도메인 환경은 Kerberos로 그대로 동작하고, 워크그룹은 NTLM + TrustedHosts + 명시적인 자격 증명이 필요합니다. TrustedHosts는 「상대를 신뢰한다」는 설정이 아니라 「상대의 신원 확인을 포기하는 목록」이므로 최소한으로 좁힙니다.53
  • 일괄 실행은 Invoke-Command, 대화형 조작은 Enter-PSSession, 상태를 유지하며 여러 번 사용하려면 New-PSSession입니다. Invoke-Command는 기본적으로 동시에 32대까지 병렬로 처리합니다.67
  • 원격에서 돌아오는 것은 역직렬화된 객체이며, 메서드가 없습니다. 작업은 ScriptBlock 안(원격 쪽)에서 완결시키고, 로컬에서는 결과 집계만 수행합니다.87
  • 연결 대상에서 다시 다른 서버로는 액세스할 수 없습니다(second hop 문제). 이는 결함이 아니라, 자격 증명을 원격으로 보내지 않는 안전한 설계의 결과입니다. 대처 방법은 여러 가지가 있으며, 요구 사항에 따라 선택합니다.9
  • PowerShell 7에서는 SSH 기반 Remoting도 사용할 수 있습니다. Linux와의 상호 관리가 필요한 경우나, WinRM을 열고 싶지 않은 환경의 선택지가 됩니다.2

2. 동작 원리 ── WinRM 위에서, 누가, 어떻게 들어가는가

PowerShell Remoting의 기반은 WinRM(Windows Remote Management)입니다. WinRM은 표준 프로토콜 WS-Management의 Microsoft 구현이며, PowerShell Remoting은 이 WinRM을 통해 원격 컴퓨터의 PowerShell로 명령을 전달합니다.3 통신은 기본적으로 HTTP 5985번, HTTPS 5986번 포트를 사용합니다.35

「HTTP는 평문이 아닌가」라는 걱정을 하실 수 있지만, 최초 인증이 완료된 후에는 WinRM이 통신을 암호화합니다. HTTPS에서는 TLS, HTTP에서는 인증 프로토콜이 협상한 메시지 수준 암호화(Kerberos라면 최신 환경에서 AES-256)가 적용됩니다.3 또한 연결할 수 있는 것은 기본적으로 원격 쪽 Administrators 그룹의 구성원뿐이며, 세션은 연결한 사용자의 컨텍스트에서 실행되므로 파일이나 레지스트리에 대한 액세스 제어는 평소와 마찬가지로 적용됩니다.3

받는 쪽의 준비는 Enable-PSRemoting입니다. 이 명령어가 무엇을 하는지는 공식적으로 나열되어 있습니다. 내부에서 Set-WSManQuickConfig를 실행하여 (1) WinRM 서비스 시작, (2) 시작 유형의 자동화, (3) 임의의 IP 주소로 받는 리스너 생성, (4) WS-Management 통신에 대한 방화벽 예외 활성화, (5) 세션 구성(엔드포인트)의 생성·활성화와 원격 액세스 허용을 수행한 다음, WinRM 서비스를 다시 시작합니다.4

# 연결을 "받는" 쪽에서 관리자 권한 PowerShell로 한 번만 실행한다
# (Windows Server에서는 기본적으로 활성화되어 있으므로 보통은 불필요. 클라이언트 Windows에서 필요)
Enable-PSRemoting

# 연결을 "하는" 쪽에서의 연결 확인 ── 이것이 통과되면 Remoting의 기반은 갖춰진 것이다
Test-WSMan -ComputerName sv-app01

모르면 걸려 넘어지는 사양이 두 가지 있습니다. 첫째는 방화벽입니다. 서버판 Windows에서는 Enable-PSRemoting이 퍼블릭 네트워크용으로도 「동일 서브넷에서만 허용」하는 규칙을 만들지만, 클라이언트판에서는 네트워크 프로필이 퍼블릭이면 활성화 자체가 오류가 됩니다(검증용 기기를 사내 Wi-Fi에 연결했을 때 자주 발생하는 문제입니다). 이 경우 -SkipNetworkProfileCheck를 붙이거나, 프로필을 프라이빗으로 바꿉니다.4

둘째는 PowerShell 버전과 엔드포인트의 관계입니다. Enable-PSRemoting은 「실행한 PowerShell 버전용」 엔드포인트를 구성합니다. PowerShell 7에서 실행해도 Windows PowerShell 5.1의 엔드포인트에는 영향을 주지 않으며, 그 반대도 마찬가지입니다.4 게다가 PowerShell 7에서 연결하더라도 기본적으로는 Windows PowerShell 5.1의 기존 엔드포인트(Microsoft.PowerShell)가 사용되기 때문에10, 「내 쪽은 7인데 원격에서 동작하는 것은 5.1이었다」라는 일이 아주 흔하게 발생합니다. 원격 쪽에서 $PSVersionTable을 표시해 확인하는 습관을 들이시기 바랍니다.

3. 도메인과 워크그룹 ── 인증의 벽은 여기에 있다

Remoting 입문에서 걸려 넘어지는 가장 큰 지점은 명령의 문법이 아니라 인증입니다. 환경에 따라 필요한 준비가 달라집니다.

항목 도메인 환경 워크그룹 환경
인증 프로토콜 Kerberos(상호 인증 있음)5 NTLM(서버의 신원 검증 없음)5
추가 설정 원칙적으로 불필요. 컴퓨터 이름으로 그대로 연결 연결하는 쪽에서 TrustedHosts 등록이 필요5
자격 증명 로그온 중인 사용자가 그대로 사용됨 -Credential로 명시적 지정이 기본
IP 주소 지정 TrustedHosts 등록 또는 HTTPS가 필요11 왼쪽과 동일

도메인 환경이라면 Kerberos에 의한 상호 인증(클라이언트도 서버도 서로를 검증)이 작동하므로 Invoke-Command -ComputerName sv-app01 { ... }가 그대로 통과합니다. 워크그룹에서는 Kerberos를 사용할 수 없으므로5, 연결하는 쪽의 TrustedHosts에 상대를 등록합니다.

# 연결을 "하는" 쪽에서, 관리자로 실행한 PowerShell에서 실행(워크그룹에서만 필요)
# TrustedHosts 변경에도 관리자 권한이 필요하다. 기존 값이 덮어써지므로 먼저 현재 값을 확인한다
Get-Item WSMan:\localhost\Client\TrustedHosts

# 필요 최소한의 호스트 이름만 추가한다. -Concatenate 없이 실행하면 기존 등록이 사라진다. '*'로 전체 허용하는 것은 피한다
Set-Item WSMan:\localhost\Client\TrustedHosts -Value 'sv-app01,sv-app02' -Concatenate

# 자격 증명을 명시하여 연결 테스트
$cred = Get-Credential sv-app01\Administrator
Invoke-Command -ComputerName sv-app01 -Credential $cred -ScriptBlock { hostname }

여기서 중요한 것이 TrustedHosts의 의미입니다. 공식 문서는 「TrustedHosts에 올린 컴퓨터는 인증되지 않으며, 클라이언트가 자격 증명을 보내 버릴 가능성이 있다」고 명시하고 있습니다.5 즉 이것은 「신뢰할 수 있는 상대의 목록」이라기보다는 「서버의 신원을 검증할 수 없다는 경고를 억제하는 목록」입니다.3 DNS나 ARP가 조작된 환경에서는 가짜 서버에 관리자 자격 증명을 넘겨줄 위험이 있습니다. 그래서 와일드카드 등록을 피하고, 고정된 호스트 이름·IP를 최소한만 올립니다. 본격적으로 운영하는 워크그룹 환경이나 DMZ에서는 인증서를 준비해 HTTPS(5986) 리스너를 구성하는 쪽이 더 합리적이라는 것이 실무의 판단입니다.3

참고로 Get-Credential로 받은 자격 증명을 스크립트에 평문으로 적기 시작했다면 노란 신호입니다. 자격 증명의 저장과 전달에 관한 정석은 함께 공개한 「PowerShell에서 자격 증명을 안전하게 다루기」에 정리했습니다.

워크그룹에서 또 하나 놓치기 쉬운 것이 비밀번호의 유무입니다. 연결 대상 계정에 비밀번호가 설정되어 있지 않은(빈 비밀번호) 경우, 원격 명령을 실행할 수 없습니다.1

3.1. HTTPS(5986) 리스너 구성하기

워크그룹이나 DMZ에서 상시로 사용한다면, TrustedHosts로 끝내지 말고 HTTPS 리스너를 세웁니다. 절차의 골자는 다음과 같습니다.12

  1. 서버 인증용 인증서를 준비한다. 요건은 「로컬 컴퓨터의 서버 인증 인증서일 것」, 「CN(또는 주체 대체 이름)이 호스트 이름과 일치할 것」, 「유효 기간 내이고, 폐기되지 않았으며, 자체 서명이 아닐 것」입니다. 사내 CA가 있다면 https://<인증 기관 서버>/certsrv의 웹 등록에서 요청할 수 있습니다.
  2. 인증서를 로컬 컴퓨터의 개인 저장소에 넣는다. 확인은 인증서 스냅인(MMC에서 「인증서」를 추가하고, 마법사에서 「컴퓨터 계정」을 선택)의 인증서(로컬 컴퓨터) > 개인 > 인증서에서 합니다.
  3. HTTPS 리스너를 만든다. 간편한 방법은 다음 한 줄입니다.

     winrm quickconfig -transport:https
    

    인증서가 여러 개 있어서 어느 것을 사용할지 명시하고 싶다면, PowerShell에서 지문을 지정해 만들 수도 있습니다(지문은 Get-ChildItem Cert:\LocalMachine\My로 확인할 수 있습니다).

     New-Item -Path WSMan:\localhost\Listener -Address * -Transport HTTPS -CertificateThumbPrint '인증서 지문' -Force
    
  4. 방화벽에서 TCP 5986의 수신을 허용한다. Enable-PSRemoting이 만드는 규칙은 HTTP(5985)용이므로, HTTPS는 별도로 필요합니다.
  5. 리스너가 만들어졌는지 확인한다.

     winrm enumerate winrm/config/listener
    

연결하는 쪽은 -UseSSL을 붙이기만 하면 됩니다.

Invoke-Command -ComputerName sv-app01.example.local -UseSSL -Credential $cred -ScriptBlock { hostname }

인증서 조건을 충족하지 않으면, 리스너 생성 시 「Cannot create a WinRM listener on HTTPS because this machine does not have an appropriate certificate.(오류 번호 -2144108267 / 0x80338115)」라는 오류가 발생합니다. 이 경우 인증서의 유효 기간, 발급 대상이 호스트 이름과 일치하는지, 고급 키 사용에 「서버 인증」이 포함되어 있는지, 인증 경로가 유효한지를 순서대로 확인합니다.12

4. Invoke-Command ── 「20대에 같은 작업을 하는」 기본형

Remoting의 주역은 Invoke-Command입니다. -ComputerName에 여러 대를 전달하고, -ScriptBlock에 「원격에서 할 작업」을 작성합니다.6 먼저 읽기 전용 점검부터 시작하는 것이 안전한 운영의 철칙입니다.

$servers = 'sv-app01', 'sv-app02', 'sv-db01'

# 패치 적용 후 상태 확인 ── 읽기만 하므로 안심하고 실행할 수 있다
$result = Invoke-Command -ComputerName $servers -ScriptBlock {
    # 이 블록 안은 "원격 쪽"에서 실행된다
    $os = Get-CimInstance Win32_OperatingSystem
    [PSCustomObject]@{
        LastBoot   = $os.LastBootUpTime                      # 재부팅이 끝났는지
        SpoolerRun = (Get-Service -Name Spooler).Status      # 업무에 필요한 서비스 상태
        FreeGB     = [math]::Round((Get-PSDrive C).Free / 1GB, 1)
    }
}

# 어느 결과가 어느 서버의 것인지는 PSComputerName으로 알 수 있다
$result | Sort-Object PSComputerName |
    Select-Object PSComputerName, LastBoot, SpoolerRun, FreeGB |
    Export-Csv -Path .\patch-check.csv -NoTypeInformation -Encoding UTF8

각 서버로의 연결은 병렬로 처리되며, 기본 동시 실행 수(ThrottleLimit)는 32입니다.7 결과는 도착한 순서대로 섞여서 반환되므로, 위 예시처럼 자동으로 부여되는 PSComputerName 속성으로 다시 정렬합니다.8

4.1. 변수를 전달하는 방법 ── $using:와 -ArgumentList

ScriptBlock은 원격에서 실행되므로, 로컬의 변수는 그대로는 보이지 않습니다. 값을 가져오는 방법에는 두 가지가 있습니다.13

$threshold = (Get-Date).AddDays(-30)

# 방법 1: $using: ── 호출하는 쪽 변수의 "값 복사본"을 원격에 삽입한다
Invoke-Command -ComputerName $servers -ScriptBlock {
    (Get-ChildItem 'D:\AppLogs' -Filter *.log |
        Where-Object LastWriteTime -lt $using:threshold).Count
}

# 방법 2: -ArgumentList ── ScriptBlock 쪽의 param으로 받는다(인수가 많을 때 읽기 쉽다)
Invoke-Command -ComputerName $servers -ScriptBlock {
    param($limit)
    (Get-ChildItem 'D:\AppLogs' -Filter *.log |
        Where-Object LastWriteTime -lt $limit).Count
} -ArgumentList $threshold

$using:로 전달되는 값은 원격 쪽에서는 독립적인 복사본입니다. 원격 쪽에서 값을 변경해도 로컬의 변수는 바뀌지 않습니다.13

4.2. 돌아오는 것은 “스냅샷” ── 역직렬화된 객체

Remoting의 결과에서 처음 당황하게 되는 부분이 바로 이것입니다. 살아 있는 .NET 객체는 네트워크를 넘을 수 없으므로, 원격의 출력은 XML(CLIXML)로 직렬화되어 전송되고, 로컬에서는 역직렬화된 객체로 복원됩니다. 이는 실행 시점의 속성을 찍은 스냅샷이며, 메서드를 갖지 않습니다.87

예를 들어 Get-Service의 결과를 로컬에서 받아 .Stop()을 호출할 수는 없습니다. 서비스를 중지하고 싶다면 ScriptBlock 안에서 Stop-Service를 실행하는 것── 즉 작업은 원격 쪽에서 완결시키고, 로컬로 가져오는 것은 보고용 데이터뿐이라는 식으로 역할을 나누는 것이 올바른 형태입니다. 속성 선별·정리·CSV화와 같은 로컬에서의 가공은 평소의 PowerShell과 같은 감각으로 할 수 있습니다(이 부분의 기본 조작은 「PowerShell 명령어의 기초」를 참고하시기 바랍니다).

5. Enter-PSSession과 New-PSSession ── 대화형 사용과 재사용

한 대를 대화형으로 조사하고 싶을 때는 Enter-PSSession입니다. 프롬프트가 [sv-app01]: PS>로 바뀌고, 입력한 명령이 원격에서 실행됩니다. exit로 빠져나옵니다.11 원격 데스크톱과 달리 화면은 가져오지 않지만, 「로그를 본다」「설정을 확인한다」 정도라면 이쪽이 더 빠르며, 연결에도 Administrators 그룹의 구성원이어야 한다는 조건은 동일합니다.11

한편 Invoke-Command를 -ComputerName으로 호출할 때마다 연결의 수립과 해제가 매번 이루어집니다.14 같은 서버 그룹에 여러 번 명령을 보내는 조사 작업에서는, New-PSSession으로 지속적인 세션을 만들어 재사용하면 빠르고, 게다가 원격 쪽의 변수나 상태가 명령 간에 유지됩니다.1415

# 세션을 한 번만 만들고, 변수 $s로 재사용한다
$s = New-PSSession -ComputerName $servers
try {
    # 1회차: 원격 쪽에 $hotfix라는 변수를 만든다
    Invoke-Command -Session $s { $hotfix = Get-HotFix | Sort-Object InstalledOn -Descending }

    # 2회차: 앞의 명령에서 만든 변수를 그대로 사용할 수 있다(세션이 상태를 유지하고 있다)
    Invoke-Command -Session $s { $hotfix | Select-Object -First 5 }
}
finally {
    # 도중에 오류나 중단이 있어도 반드시 해제한다(원격 쪽의 리소스를 해제한다)
    Remove-PSSession $s
}

6. 함정 ── second hop, 그리고 SSH라는 선택지

6.1. second hop(더블 홉) 문제

현장에서 가장 유명한 벽이 바로 이것입니다. 내 PC(A)에서 Remoting으로 서버 B에 들어가, B 안에서 \\fs01\share(서버 C)를 읽으려고 하면 액세스가 거부됩니다. 기본값인 Kerberos/NTLM 인증은 자격 증명 자체를 B로 보내지 않고 인증하는 안전한 방식이므로, B는 사용자를 대리하여 C에 인증할 수 없는 것입니다.39

대처 방법은 여러 가지가 있으며, 공식 문서가 권장 순서로 정리하고 있습니다.9 주요한 것만 꼽으면 다음과 같습니다.

  • ScriptBlock 안에서 자격 증명을 명시적으로 전달한다 ── 서버 쪽 구성 변경이 필요 없어 가장 손쉽습니다. $using:cred로 내부의 Invoke-Command에 자격 증명을 전달합니다.9 다만 자격 증명 객체가 중계 서버(B)의 세션에 전달되는 이상, B가 침해당했다면 전달한 자격 증명도 악용될 수 있으므로, B를 완전히 신뢰할 수 있는 경우에 한해, 전달하는 계정도 C 쪽에서 필요 최소한의 권한만 가진 전용 계정으로 한다는 것이 전제입니다.
  • 리소스 기반 Kerberos 제한 위임 ── 자격 증명을 저장하지 않고, 액세스 대상(C) 쪽에서 「B로부터의 위임을 받는다」고 구성하는 방식입니다. 도메인 관리자 권한 없이 구성할 수 있으며, 보안과 구성의 간편함 사이의 균형이 좋은 선택지입니다.9
  • JEA(Just Enough Administration) ── 「그 업무에 필요한 명령만」을 허용한 전용 엔드포인트를 준비하여 권한을 좁히는 PowerShell의 구조입니다. 가상 계정을 사용하는 구성으로 하면, 이용자는 관리자가 아닌 자격 증명으로 연결하면서도 허용된 관리 명령만 실행할 수 있습니다.16 second hop의 맥락에서는 중계 서버(B)에 관리자 자격 증명을 배포하는 대신, C에 대한 액세스를 포함한 정형화된 작업만 실행할 수 있는 창구를 만드는 방식으로 사용하게 됩니다.9
  • CredSSP ── 자격 증명이 원격 서버에 캐시되므로, 그 서버가 침해당하면 자격 증명까지 함께 탈취됩니다. 기본적으로 비활성화되어 있으며, 활성화는 가장 신뢰할 수 있는 환경으로 한정해야 합니다.9
# 가장 손쉬운 회피 방법: 내부의 Invoke-Command에 $using:cred로 자격 증명을 전달한다
# 바깥쪽(sv-app01)에는 자기 자신의 자격 증명으로 연결하고, 내부에 전달하는 것은
# fs01 쪽에서 필요 최소한의 권한을 가진 전용 계정만으로 한다(관리자 자격 증명을 배포하지 않는다)
#
# 【전제】내부의 호출은 "sv-app01에서 fs01로의 새로운 Remoting 연결"이므로, 다음이 필요하다:
#   1. sv-app01에서 fs01로 WinRM(5985/5986)이 도달할 수 있을 것
#   2. 워크그룹이나 IP 주소 지정이라면, sv-app01 쪽의 TrustedHosts에 fs01이 등록되어 있을 것
#   3. $cred가 fs01에서 유효한 계정(도메인 계정, 또는 fs01의 로컬 계정)일 것
# 이를 확인하지 않고 그대로 복사해서 쓰면 "내 쪽에서는 동작하는데 중계 서버에서는 실패한다"가 되기 쉽다
$cred = Get-Credential CONTOSO\svc-fileread
Invoke-Command -ComputerName sv-app01 -ScriptBlock {
    Invoke-Command -ComputerName fs01 -Credential $using:cred -ScriptBlock { hostname }
}

애초에 「B를 경유해 C의 파일을 읽는」 것이 아니라, 내 쪽에서 C를 상대로 직접 Invoke-Command하는 구성으로 바꿀 수는 없는지를 먼저 생각하는 것이 가장 비용이 적게 드는 해결책입니다.

6.2. PowerShell 7이라면 SSH 기반 Remoting도 선택할 수 있다

PowerShell 6.0 이후로는 WinRM 대신 SSH로 연결하는 Remoting을 사용할 수 있습니다. Invoke-Command / Enter-PSSession / New-PSSession에 -HostName, -UserName, -KeyFilePath라는 SSH용 매개변수 세트가 추가되어, Windows와 Linux를 넘나드는 관리가 가능합니다.2 연결 대상에는 SSH 서버와 PowerShell의 SSH 서브시스템 구성이 필요하며, WinRM 기반에 있는 엔드포인트 구성이나 JEA와 같은 기능은 현재로서는 지원되지 않습니다.2 Linux 서버가 혼재하는 환경이나, 키 인증으로 운영을 통일하고 싶은 경우의 선택지로 기억해 두면 좋습니다. Windows PowerShell 5.1에는 이 기능이 없으므로, 필요하다면 이관의 동기가 될 수 있습니다(차이점의 전체상은 함께 공개한 「Windows PowerShell 5.1과 PowerShell 7의 차이」를 참고하시기 바랍니다).

참고로 Remoting의 세션은 RDP와 같은 데스크톱 세션을 만들지 않습니다. 「원격에서 동작한다」는 의미가 두 방식에서 어떻게 다른지는 「Windows의 세션 분리를 어떻게 이해할까」에서 정리하고 있습니다.

7. 연결이 안 될 때의 원인 분리

입문자가 Remoting을 포기하는 이유의 대부분은 「연결이 안 된다」는 것입니다. 게다가 실패의 원인은 서비스·리스너·방화벽·인증·권한 중 어디에라도 있을 수 있습니다. 상류부터 순서대로 하나씩 제거해 나가면 헤매지 않습니다.

7.1. 원인 분리의 순서

  1. 연결 상태를 본다. 먼저 연결하는 쪽에서 Test-WSMan -ComputerName sv-app01을 실행합니다. 여기가 통과되면 WinRM 서비스·리스너·방화벽까지는 살아 있는 것입니다(인증이나 권한 문제는 남아 있습니다). 통과되지 않으면 다음으로 넘어갑니다.
  2. 원격 쪽에서 WinRM 서비스가 동작하고 있는가. 서버판은 시작 유형이 자동이지만, 클라이언트판 Windows에서는 WinRM 서비스가 기본적으로 비활성화되어 있습니다.1 Get-Service WinRM으로 확인하고, 필요하면 Enable-PSRemoting(서비스 시작·자동 시작화·리스너·방화벽 예외·세션 구성을 한꺼번에 구성)을 실행합니다.4
  3. 리스너가 대기하고 있는가. 원격 쪽에서 다음을 실행하여 ListeningOn이 비어 있지 않은지 봅니다. 비어 있는 경우는 그룹 정책으로 리스너를 배포하는 환경에서의 설정 실수가 단골입니다.1

     Get-WSManInstance winrm/config/listener -Enumerate
    
  4. 네트워크 프로필을 본다. 클라이언트판에서 네트워크가 퍼블릭이면, Enable-PSRemoting 자체가 「Unable to check the status of the firewall」로 실패합니다. 프로필을 프라이빗으로 바꾸거나, -SkipNetworkProfileCheck를 붙입니다.1
  5. 방화벽 규칙을 본다. 서버판이라도 퍼블릭 프로필에서는 「동일 서브넷에서만 허용」하는 규칙이 됩니다. 다른 서브넷에서 들어오려면 규칙 재검토가 필요합니다(Get-NetFirewallRule로 규칙 이름을 확인한 뒤 변경하시기 바랍니다. 규칙 이름은 Windows 버전에 따라 다릅니다).1
  6. 인증 방식의 조건을 충족하는가. 워크그룹, 비도메인 참가, IP 주소 지정의 경우 Kerberos를 사용할 수 없어 NTLM이 되므로, TrustedHosts 등록(또는 HTTPS)과 -Credential의 명시적 지정이 필수입니다. 연결 대상 계정에 빈 비밀번호는 사용할 수 없습니다.1
  7. 연결할 수 있는 권한이 있는가. 기본 엔드포인트에 연결할 수 있는 것은 원격 쪽 Administrators 구성원뿐입니다. 다른 도메인의 사용자나 로컬 계정은 기본적으로 표준 사용자 토큰이 되므로 관리자로서 동작할 수 없습니다(필요하다면 LocalAccountTokenFilterPolicy를 사용할 수 있지만, UAC의 원격 제한을 모든 사용자에 대해 비활성화하는 설정이므로 영향을 이해한 뒤 적용하시기 바랍니다).1
  8. 엔드포인트의 PowerShell 버전을 확인한다. 연결은 되었는데 「그런 명령어는 없다」는 말을 듣는다면, 2장에서 설명한 대로 Windows PowerShell 5.1 쪽의 엔드포인트에 들어가 있을 가능성이 있습니다. Invoke-Command -ComputerName sv-app01 { $PSVersionTable.PSVersion }로 확인하고, 필요하면 -ConfigurationName으로 명시합니다.10

7.2. 대표적인 오류 메시지 읽는 법

오류 문구는 거의 정형화되어 있으므로, 외운다기보다 「이 문구라면 여기를 본다」고 대응시켜 두는 것이 실용적입니다.1

오류 메시지(발췌) 흔한 원인 가장 먼저 볼 곳
Access is denied. You need to run this cmdlet from an elevated process. 로컬 PowerShell이 관리자 권한이 아님 「관리자 권한으로 실행」으로 다시 연다
ACCESS IS DENIED 연결 대상에서 Remoting이 비활성화됨/연결 사용자가 Administrators가 아님/다른 도메인·로컬 관리자의 토큰 제한 연결 대상에서 Enable-PSRemoting, -Credential로 관리자 지정, 필요하면 세션 구성의 권한이나 LocalAccountTokenFilterPolicy
The connection to the remote host was refused. Verify that the WS-Management service is running on the remote host and configured to listen for requests on the correct port and HTTP URL. WinRM 서비스가 정지됨, 리스너가 없음, 포트가 다름 Get-Service WinRM, 리스너 열거, 포트 설정
The client cannot connect to the destination specified in the request. Verify that the service on the destination is running and is accepting requests. 리스너의 ListeningOn이 비어 있음(정책 설정 실수), 프록시의 영향 리스너 열거, New-PSSessionOption의 프록시 설정
The WinRM client cannot process the request. If the authentication scheme is different from Kerberos, or if the client computer is not joined to a domain, then HTTPS transport must be used or the destination machine must be added to the TrustedHosts configuration setting. 워크그룹, 비도메인 참가, IP 주소 지정 TrustedHosts 등록 + -Credential, 또는 3.1의 HTTPS 구성
Unable to check the status of the firewall(Enable-PSRemoting 실행 시) 클라이언트판에서 네트워크가 퍼블릭 프로필을 프라이빗으로, 또는 -SkipNetworkProfileCheck
The WS-Management service cannot complete the operation within the time specified in OperationTimeout. 처리가 오래 걸림, 상대가 고부하 상태 New-PSSessionOption -OperationTimeout으로 연장
The total data received from the remote client exceeded allowed maximum. 반환하는 데이터가 너무 큼 ScriptBlock 안에서 집계·선별한 뒤 반환. 필요하면 할당량 조정

원인 분리의 요령은 「내 쪽의 문제인지, 경로의 문제인지, 상대의 문제인지」를 하나씩 확정해 나가는 것입니다. Test-WSMan이 통과되는지 여부로 경로와 상대의 서비스까지를 가려내고, 통과된 뒤의 오류는 인증과 권한 문제로 좁힙니다. 이 2단계 방식으로 하면 원인을 모른 채 설정을 이리저리 만지는 일이 없어집니다.

8. 실무의 정석(판단표)

논점 선택지 판단 기준
한 대를 대화형으로 조사 RDP / Enter-PSSession 화면이 필요하면 RDP, 명령으로 끝난다면 Enter-PSSession이 더 가볍다11
여러 대에 같은 처리 한 대씩 수작업 / Invoke-Command 3대를 넘으면 Invoke-Command. 기본적으로 32대까지 병렬67
여러 번 명령을 보냄 -ComputerName으로 매번 연결 / New-PSSession 재사용 조사에서 대화형으로 왔다갔다 한다면 세션 재사용. 끝나면 Remove-PSSession14
워크그룹의 인증 TrustedHosts(HTTP) / HTTPS 리스너 일시적 이용은 최소한의 TrustedHosts. 상시 사용한다면 HTTPS 구성(절차는 3.1)5312
second hop 대처 자격 증명을 명시적으로 전달 / 리소스 기반 위임 / CredSSP 먼저 구성 변경이 필요 없는 명시적 전달. 상시적이라면 리소스 기반 위임. CredSSP는 최후의 수단9
처음에 실행하는 명령 변경계 / 읽기계 반드시 Get 계열로 점검부터. 변경계는 -WhatIf 대응 명령으로 예행 연습한 뒤 본실행

마지막 줄은 강조해 두겠습니다. Invoke-Command는 「20대를 순식간에 고치는 명령」인 동시에 「20대를 순식간에 망가뜨리는 명령」입니다. 다행히 Stop-Service나 Set-ItemProperty와 같은 변경계 명령어의 상당수는 -WhatIf를 지원하며, ScriptBlock 안에서도 그대로 사용할 수 있습니다. 새 스크립트는 먼저 한 대에, 다음으로 -WhatIf를 붙여 전체 대수에, 마지막으로 본실행이라는 3단계를 습관화하면 사고율이 눈에 띄게 낮아집니다.

9. 정리

  • Remoting은 WinRM(WS-Management) 위에서 동작하며, 기본 포트는 HTTP 5985 / HTTPS 5986입니다. 연결할 수 있는 것은 기본적으로 원격 쪽 Administrators의 구성원뿐이며, 통신은 인증 후에 암호화됩니다.
  • Enable-PSRemoting은 WinRM 서비스 시작·리스너 생성·방화벽 예외·세션 구성 활성화를 수행합니다. 실행한 PowerShell 버전용 엔드포인트가 구성된다는 점에 주의하시기 바랍니다.
  • 도메인은 Kerberos로 그대로, 워크그룹은 TrustedHosts + 명시적 자격 증명. TrustedHosts는 신원 검증을 포기하는 목록이므로 최소한으로.
  • 일괄 실행은 Invoke-Command(기본 32 병렬), 대화형은 Enter-PSSession, 상태를 유지하려면 New-PSSession의 재사용. 결과는 메서드를 갖지 않는 역직렬화된 객체이므로, 작업은 원격 쪽에서 완결시킵니다.
  • 연결 대상에서 다시 그 너머로는 닿지 않습니다(second hop). 먼저 자격 증명의 명시적 전달을, 상시 운영이라면 리소스 기반 Kerberos 제한 위임을 검토합니다.
  • 「연결이 안 될」 때는 Test-WSMan으로 경로와 상대의 서비스까지를 가려낸 다음, 인증(TrustedHosts·자격 증명)과 권한(Administrators)으로 좁혀서 봅니다. 대표적인 오류 문구와 대응 방법은 7장의 표에 정리했습니다.
  • 운영은 먼저 읽기계부터. 변경계는 한 대 → -WhatIf → 본실행의 3단계로. 파일 서버 점검에 응용하는 구체적인 예시는 함께 공개한 「PowerShell로 파일 서버를 점검하기」를 참고하시기 바랍니다.

관련 글

관련 상담 영역

합동회사 코무라소프트에서는 PowerShell을 이용한 서버·클라이언트 일괄 관리 체계 구축, Remoting을 포함한 운영 스크립트의 설계·리뷰, 「연결이 안 된다」「특정 환경에서만 인증에 실패한다」와 같은 WinRM/인증 관련 조사를 다루고 있습니다.

참고 링크

  1. Microsoft Learn, about_Remote_Troubleshooting. Windows Server 2012 이후의 Windows Server에서는 Remoting이 기본적으로 활성화되어 있다는 점, 클라이언트판 Windows에서는 WinRM 서비스가 기본적으로 비활성화되어 있다는 점, WSMan: 드라이브의 설정 변경에 관리자 권한이 필요하다는 점, 대표적인 오류 메시지(Access is denied/연결 거부/Unable to check the status of the firewall/TrustedHosts와 HTTPS에 관한 WinRM 클라이언트 오류/타임아웃/할당량 초과)와 그 대처법, Get-WSManInstance에 의한 리스너 열거와 ListeningOn이 비게 되는 정책 설정 실수, 퍼블릭 네트워크에서의 방화벽 규칙 동작, 워크그룹에서는 빈 비밀번호 계정을 사용할 수 없다는 점, 다른 도메인・로컬 계정의 관리자에 대한 토큰 제한과 LocalAccountTokenFilterPolicy에 대해 다룹니다.  2 3 4 5 6 7 8 9 10 11

  2. Microsoft Learn, PowerShell remoting over SSH. PowerShell 6 이후로 SSH 기반 Remoting을 사용할 수 있다는 점, New-PSSession/Enter-PSSession/Invoke-Command에 -HostName/-UserName/-KeyFilePath 매개변수 세트가 추가되었다는 점, 멀티플랫폼에서 동작한다는 점, 엔드포인트 구성이나 JEA는 현재로서는 지원되지 않는다는 점에 대해 다룹니다.  2 3 4

  3. Microsoft Learn, Security Considerations for PowerShell Remoting using WinRM. Remoting이 WinRM(WS-Management의 Microsoft 구현)을 사용한다는 점, 기본 포트가 HTTP 5985/HTTPS 5986이라는 점, 기본적으로 Administrators 그룹의 구성원만 연결할 수 있고 세션이 사용자의 컨텍스트에서 동작한다는 점, 인증 후의 통신이 암호화된다는 점, TrustedHosts가 신원 검증 오류를 억제하는 목록에 불과하다는 점, second hop 문제의 배경에 대해 다룹니다.  2 3 4 5 6 7 8 9 10 11 12

  4. Microsoft Learn, Enable-PSRemoting. Enable-PSRemoting이 수행하는 작업의 목록(WinRM 서비스 시작・자동 시작화, 리스너 생성, 방화벽 예외, 세션 구성 활성화와 보안 설명자 변경), Windows Server에서는 기본적으로 활성화되어 있다는 점, 클라이언트판의 퍼블릭 네트워크에서의 제한과 SkipNetworkProfileCheck, 실행한 버전용 엔드포인트가 구성된다는 점에 대해 다룹니다.  2 3 4 5

  5. Microsoft Learn, Installation and configuration for Windows Remote Management. WinRM 2.0의 기본 리스너 포트가 5985/5986이라는 점, 도메인 계정에는 Kerberos・로컬 계정에는 NTLM이 선택된다는 점, Kerberos는 워크그룹에서는 사용할 수 없고 도메인에서만 사용할 수 있다는 점, TrustedHosts의 컴퓨터는 인증되지 않고 자격 증명이 전송될 수 있으므로 최소한으로 유지해야 한다는 점에 대해 다룹니다.  2 3 4 5 6 7 8

  6. Microsoft Learn, Invoke-Command. Invoke-Command가 단일 명령으로 여러 컴퓨터에 명령을 실행할 수 있다는 점, -ComputerName에 의한 임시 연결과 -Session에 의한 PSSession 사용의 구분, -ArgumentList나 -FilePath 등의 매개변수에 대해 다룹니다.  2 3

  7. Microsoft Learn, PowerShell Remoting FAQ. 동시 연결 수의 기본값이 32이며 ThrottleLimit 매개변수로 변경할 수 있다는 점, 원격 명령의 출력이 CLIXML로 직렬화되어 역직렬화된 객체(메서드 없음)로 반환된다는 점, Invoke-Command의 결과에 출처 판별용 속성이 붙는다는 점에 대해 다룹니다.  2 3 4 5

  8. Microsoft Learn, about_Remote_Output. 원격 명령의 출력이 직렬화/역직렬화를 거쳐 속성만 남은 스냅샷이 된다는 점, 결과가 도착한 순서대로 반환되므로 PSComputerName으로 재정렬한다는 점에 대해 다룹니다.  2 3

  9. Microsoft Learn, Making the second hop in PowerShell Remoting. second hop 문제의 시나리오, 대처 방법의 목록과 권장 순서(CredSSP, 리소스 기반 Kerberos 제한 위임, JEA 등), CredSSP가 자격 증명을 원격에 캐시하기 때문에 침해 시 위험이 있으며 기본적으로 비활성화되어 있다는 점, ScriptBlock 안에서 $Using:cred로 자격 증명을 전달하는 예시에 대해 다룹니다.  2 3 4 5 6 7 8

  10. Microsoft Learn, Migrating from Windows PowerShell 5.1 to PowerShell 7. WinRM이 활성화된 환경에서는 PowerShell 7이 기본적으로 Windows PowerShell 5.1의 기존 엔드포인트(Microsoft.PowerShell)를 사용해 연결한다는 점, PowerShell 7 자체의 엔드포인트를 만들려면 Enable-PSRemoting을 실행해야 한다는 점에 대해 다룹니다.  2

  11. Microsoft Learn, Enter-PSSession. Enter-PSSession이 단일 원격 컴퓨터와의 대화형 세션을 시작한다는 점, exit/Exit-PSSession으로 종료한다는 점, 원격 쪽 Administrators 그룹의 구성원이어야 한다는 점, IP 주소 지정 시에는 HTTPS 구성 또는 TrustedHosts 등록이 필요하다는 점에 대해 다룹니다.  2 3 4

  12. Microsoft Learn, How to configure WINRM for HTTPS (KB 2019527). HTTPS 리스너에 필요한 인증서 요건(로컬 컴퓨터의 서버 인증 인증서, CN이 호스트 이름과 일치, 만료・폐기・자체 서명이 아닐 것), 인증서 스냅인에서의 확인 절차, winrm quickconfig -transport:https에 의한 구성, winrm enumerate winrm/config/listener에 의한 확인, Windows 7 이후의 HTTP 5985/HTTPS 5986이라는 포트, 적절한 인증서가 없을 경우의 오류 0x80338115와 확인해야 할 인증서 속성에 대해 다룹니다.  2 3

  13. Microsoft Learn, about_Remote_Variables. 원격으로 실행되는 명령에서 로컬 변수를 사용하기 위한 $using: 범위 한정자, 원격 세션에서는 값이 독립적인 복사본으로 전달된다는 점, 직렬화로 인해 메서드가 사라진다는 점에 대해 다룹니다.  2

  14. Microsoft Learn, New-PSSession. New-PSSession이 지속적인 연결(PSSession)을 생성한다는 점, 데이터를 공유하는 여러 명령의 실행에 사용한다는 점, -ComputerName을 지정하면 임시 연결이 만들어져 명령마다 닫힌다는 점, SSH 기반 연결도 지원한다는 점에 대해 다룹니다.  2 3

  15. Microsoft Learn, Running Remote Commands. Invoke-Command에 의한 스크립트 파일 실행(-FilePath), New-PSSession으로 만든 지속적 세션에서는 변수 등의 상태가 명령 간에 유지된다는 점에 대해 다룹니다. 

  16. Microsoft Learn, Overview of Just Enough Administration (JEA). JEA가 PowerShell로 관리하는 대상에 대한 위임 관리를 가능하게 하는 보안 기술이라는 점, 실행할 수 있는 명령어・함수・외부 명령을 제한할 수 있다는 점, 가상 계정이나 그룹 관리 서비스 계정을 통해 관리자 계정의 수를 줄일 수 있다는 점, 트랜스크립트와 로그로 실행 내용을 파악할 수 있다는 점에 대해 다룹니다. 

같은 태그를 공유하는 최신 기사입니다. 더 가까운 주제로 지식을 넓힐 수 있습니다.

이 기사와 가까운 토픽 페이지입니다. 기사를 출발점 삼아 관련 서비스와 다른 기사로 이어집니다.

이 기사는 다음 서비스 페이지로 이어집니다. 가까운 입구부터 확인해 주세요.

자주 묻는 질문

이 기사 주제에 대해 상담 시 자주 나오는 질문을 모았습니다.

Enable-PSRemoting을 실행하면 무슨 일이 일어나나요?
내부적으로 Set-WSManQuickConfig가 실행되어, WinRM 서비스의 시작과 시작 유형의 자동화, 임의의 IP 주소로 요청을 받는 리스너 생성, WS-Management 통신에 대한 방화벽 예외 활성화, 세션 구성(엔드포인트)의 활성화 및 원격 액세스 허용으로의 변경이 이루어집니다. Windows Server에서는 기본적으로 활성화되어 있지만, 클라이언트 Windows에서는 직접 실행해야 합니다. 연결을 받는 쪽에서만 필요하며, 연결하는 쪽에서는 실행할 필요가 없습니다.
워크그룹 환경(도메인 없음)에서 PowerShell Remoting을 사용하려면 무엇이 필요한가요?
도메인이 없으면 Kerberos 인증을 사용할 수 없기 때문에 NTLM 인증이 됩니다. 연결하는 쪽에서 연결 대상을 WSMan의 TrustedHosts 목록에 등록하고, -Credential로 자격 증명을 명시적으로 전달하는 것이 기본 형태입니다. 다만 TrustedHosts에 올린 상대는 인증(신원 위장 여부 검증)되지 않은 채로 자격 증명이 전송될 수 있으므로, 와일드카드가 아니라 필요 최소한의 호스트 이름만 등록하고, 가능하다면 HTTPS(5986) 리스너 구성을 검토하시기 바랍니다.
Invoke-Command의 결과 객체에서 메서드를 호출할 수 없는 이유는 무엇인가요?
원격 명령의 출력은 네트워크를 통해 전송하기 위해 XML(CLIXML)로 직렬화되고, 로컬에서는 역직렬화된 객체로 복원되기 때문입니다. 이는 실행 시점의 속성을 스냅샷으로 찍은 것이며, 살아 있는 객체가 아니므로 메서드를 갖지 않습니다. 서비스 중지와 같은 작업은 로컬 쪽에서 메서드를 호출하는 것이 아니라 ScriptBlock 안(원격 쪽)에서 실행해야 합니다.
second hop(더블 홉) 문제란 무엇인가요?
PC A에서 Remoting으로 서버 B에 들어가, B에서 다시 다른 서버 C(파일 서버 등)에 액세스하려고 하면 거부되는 문제입니다. 기본값인 Kerberos/NTLM 인증은 자격 증명 자체를 B로 보내지 않기 때문에, B는 사용자로서 C에 인증할 수 없습니다. 대처 방법으로는 ScriptBlock 안에서 자격 증명을 명시적으로 전달하는 방법, 리소스 기반 Kerberos 제한 위임, CredSSP(자격 증명이 원격 쪽으로 전달되므로 위험 증가) 등이 있으며, 요구 사항에 따라 선택합니다.
PowerShell Remoting에는 누구나 연결할 수 있는 건가요?
아니요. 기본적으로는 원격 컴퓨터의 Administrators 그룹 구성원만 연결할 수 있습니다. 또한 연결 후의 세션은 연결한 사용자의 컨텍스트에서 동작하므로, OS의 액세스 제어가 그대로 적용됩니다. 다만 관리자에게는 강력한 진입점이므로, 방화벽 규칙 재검토, HTTPS 리스너, 필요한 관리자로만 제한하는 것과 같은 다층 방어와 함께 운영하시기 바랍니다.

저자 프로필

기사 저자의 프로필 페이지입니다.

Go Komura

합동회사 코무라소프트 대표

Windows 소프트웨어 개발, 기술 상담, 장애 조사를 중심으로 재현이 어려운 장애 조사와 기존 자산이 남아 있는 프로젝트에 강점이 있습니다.

블로그 목록으로 돌아가기