이 연재를 쓰는 동안 작업 관리자의 세부 정보 탭을 수없이 열었다. 그러다 눈치챈 것이 있다. 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 프로세스는 그 자체가 문제인 경우보다 그것을 부르는 다른 프로그램이 문제인 경우가 많았다. 작업 관리자에서 낯선 이름을 만나면 끝내기보다 "누가 띄웠나"를 먼저 물어보면 된다.