이 연재를 쓰는 동안 작업 관리자의 세부 정보 탭을 수없이 열었다. 그러다 눈치챈 것이 있다. PowerShell 로 프로세스 목록을 한 번 뽑을 때마다 WmiPrvSE.exe 가 하나씩 새로 생겼다가 얼마 뒤 사라졌다. 조사하는 도구가 조사 대상을 만들고 있었던 셈이다. 마지막 편은 이 WmiPrvSE.exe 다. "WMI Provider Host CPU 높음"은 Windows 프로세스 검색어 중에서도 오래된 단골이다.

세 개의 WmiPrvSE 와 그 부모

확인한 시점에 WmiPrvSE.exe 는 세 개였다.

Get-CimInstance Win32_Process -Filter "Name='WmiPrvSE.exe'" |
    Select-Object ProcessId, ParentProcessId, CreationDate

세 개 모두 부모가 같은 svchost.exe 였고, 그 svchost 안의 서비스는 DcomLaunch, BrokerInfrastructure, PlugPlay, Power, SystemEventsBroker 였다. Runtime Broker 를 띄우는 것과 같은 부모다. 시작 시각은 12시 46분, 12시 57분, 12시 57분으로 모두 그날 생긴 것이었고, 뒤의 둘은 내가 PowerShell 로 질의를 던진 시각과 겹쳤다. 작업 집합은 하나에 11.625.5MB, 개인 메모리는 2.011.3MB 였다.

파일은 C:\Windows\System32\wbem\WmiPrvSE.exe, 544,768바이트, 설명 "WMI Provider Host", 버전 10.0.26100.9711 이고 Microsoft Windows 서명이 유효했다. 32비트 공급자용으로 C:\Windows\SysWOW64\wbem 에도 같은 이름이 있다. 일반 권한에서는 명령줄이 비어 보였는데, 관리자 권한으로 보면 -Embedding 같은 COM 인수가 붙어 있는 것으로 알려져 있다. 경로가 wbem 폴더가 아니거나 서명이 없으면 이름만 빌린 것이다.

WMI 와 공급자, 그리고 WmiPrvSE

WMI(Windows Management Instrumentation)는 "이 PC 의 BIOS 버전은?", "C 드라이브 남은 용량은?", "TPM 이 켜져 있나?" 같은 질문을 프로그램이 한 가지 방식으로 물을 수 있게 해 주는 창구다. 이 연재에서 쓴 Get-CimInstance 도 WMI 를 부르는 명령이다.

창구 역할은 Windows Management Instrumentation 서비스(Winmgmt)가 맡는다. 이 PC 에서는 svchost.exe -k netsvcs -p 그룹 안에서 돌고 있었다. 실제 답을 만드는 것은 분야별 "공급자(provider)" DLL 인데, 공급자가 잘못되어도 서비스 전체가 죽지 않게 별도 프로세스에 담아 돌린다. 그 그릇이 WmiPrvSE.exe 다. 계정이나 격리 수준에 따라 그릇이 나뉘기 때문에 여러 개가 뜨고, 한동안 일이 없으면 스스로 내려간다.

그래서 WmiPrvSE 의 CPU 가 높다는 건 어떤 공급자가 바쁘게 답을 만들고 있다는 뜻이고, 거의 언제나 누군가 그 공급자에게 계속 묻고 있다는 뜻이다. 끝내기를 누르면 잠깐 내려가지만 묻는 쪽이 그대로면 금방 새 WmiPrvSE 가 뜬다. 찾아야 할 것은 묻는 쪽이다.

WMI-Activity 로그로 묻는 쪽 찾기

Windows 는 WMI 활동을 이벤트 로그 Microsoft-Windows-WMI-Activity/Operational 에 남긴다. 이벤트 뷰어에서는 응용 프로그램 및 서비스 로그 → Microsoft → Windows → WMI-Activity → Operational 이다. 이 PC 의 로그에는 1,527건이 있었다. 가장 오래된 것이 10월 28일 아침, 최신이 11월 1일 낮이었고, 로그 파일 크기가 최대치(약 1MB)에 닿아 있어 그보다 오래된 기록은 밀려난 상태였다.

이벤트 번호별로 나눠 보면 이렇다.

이벤트 ID 건수 내용
5857 882 공급자가 어느 WmiPrvSE 에 올라왔는지 (공급자 이름, DLL 경로, HostProcess ProcessID)
5858 633 실패한 질의 (ClientProcessId, 질의 내용, 결과 코드)
5860·5861·5859 12 이벤트 구독 등록

CPU 를 먹는 WmiPrvSE 의 PID 를 작업 관리자에서 확인했다면 5857 에서 그 PID 를 찾는다. 그 그릇에 어떤 공급자가 올라왔는지가 나온다. 이 PC 에서 12시 57분에 생긴 WmiPrvSE 에는 CIMWin32, Win32_DeviceGuard, ScheduledTaskProv, PS_MMAgent 공급자가 올라와 있었다. 이 연재를 쓰며 내가 돌린 프로세스 목록, VBS 상태, 예약 작업, 메모리 압축 설정 조회와 그대로 맞는다. 4일 전체로는 CIMWin32 가 465번으로 가장 많았고, DNS 클라이언트(99번), TPM(52번) 공급자가 뒤를 이었다.

Get-WinEvent -LogName 'Microsoft-Windows-WMI-Activity/Operational' -MaxEvents 200 |
    Where-Object Id -eq 5857 | Select-Object TimeCreated, Message

묻는 쪽은 5858 의 ClientProcessId 로 찾는다. 5858 은 실패한 질의만 남는 것으로 알려져 있어서 모든 질의가 다 보이지는 않지만, 같은 질문을 반복하는 프로그램은 실패도 반복하기 때문에 꽤 잘 드러난다. 이 PC 의 633건에는 서로 다른 클라이언트 프로세스 번호가 231개 있었다. 그중 아직 살아 있던 것은 몇 개뿐이었다. WMI 에 묻는 프로그램 상당수가 잠깐 떴다가 끝나는 작은 프로세스였다는 뜻이다. 남아 있던 것 중에는 Windows 보안의 SecurityHealthService 가 VBS 상태를 22번 물었고, 메인보드 제조사 유틸리티의 서비스가 BIOS 정보를 25번 물었다.

Get-Process -Id <ClientProcessId>

로그에서 본 번호를 이렇게 넣으면 이름이 나온다. 이미 끝난 프로세스라면 아무것도 나오지 않으니, CPU 가 높은 바로 그때 확인하는 편이 낫다.

결과 코드도 단서다. 이 PC 에서는 0x80041032 가 509건으로 대부분이었는데, WMI 오류 코드 표로는 호출이 취소되었다는 뜻이라 대개 묻는 쪽이 기다리다 그만둔 기록으로 보인다. 0x80041003(권한 거부)은 42건이었다. 그중 하나는 내가 일반 권한으로 Get-MMAgent 를 실행했다가 거부당한 바로 그 순간이었다. 0x80041010(없는 클래스)이 같은 프로그램에서 계속 나온다면 그 프로그램이 이 PC 에 없는 것을 찾느라 헛돌고 있는 것이다.

범인을 찾았다면 그 프로그램을 업데이트하거나 설정에서 감시 주기를 늘리거나, 쓰지 않는 프로그램이면 지우면 된다. Winmgmt 서비스를 끄거나 WMI 저장소를 다시 만드는 방법도 검색에 나오지만, 많은 Windows 기능과 관리 도구가 WMI 에 기대고 있어서 원인을 모른 채 할 일은 아니다.

연재를 마치며

아홉 편 동안 작업 관리자에서 자주 묻는 이름들을 열어 봤다. svchost.exe 부터 WmiPrvSE.exe 까지, 쓴 방법은 거의 같았다. 경로와 서명을 보고, 부모 프로세스를 따라가고, 그 프로세스가 누구의 일을 대신하는지 찾는다. 대부분의 Windows 프로세스는 그 자체가 문제인 경우보다 그것을 부르는 다른 프로그램이 문제인 경우가 많았다. 작업 관리자에서 낯선 이름을 만나면 끝내기보다 "누가 띄웠나"를 먼저 물어보면 된다.