WMI는 은근히 재미있는 주제입니다. COM을 사용하는 방법과 WMI에 접근하는 방법을 같이 공부할 수 있거든요.
또한, AD를 사용한다면, 에이전트 없이 원격 클라이언트의 정보를 상당량 수집할 수 있구요.

WMI에 대한 자세한 설명은 MSDN을 참조해주시구요, 전체적인 과정을 살펴보면 대략 다음과 같습니다.

1. CoInitialize로 COM을 초기화한다.
2. CoInitializeSecurity로 보안 레벨을 설정한다.
3. CoCreateInstance로 WMI 의 COM Object 를 생성한다.
4. ConnectServer로 "root\\cimv2" 네임스페이스로 접속한다.
5. ExecQuery 로 WQL 구문을 실행한다.
6. 실행결과 Enumerator 를 분석하고, 제조번호를 파싱한다.

그리하여, 전체 코드는 다음과 같이 되겠습니다.


#include "stdafx.h"

int _tmain(int argc, _TCHAR* argv[])
{
	int nRet = 0;
	HRESULT hr = S_OK;
	TCHAR tszMsg[1024] = {0, };

	try
	{
		if (_tsetlocale(LC_ALL, _T("")) == NULL)
			throw _T("_tsetlocale");

		hr = CoInitializeEx(0, COINIT_MULTITHREADED);
		if (FAILED(hr))
			throw _T("CoInitialize");

		hr = CoInitializeSecurity(NULL, -1, NULL, NULL,
			RPC_C_AUTHN_LEVEL_DEFAULT,
			RPC_C_IMP_LEVEL_IMPERSONATE,
			NULL, EOAC_NONE, NULL);
		if (FAILED(hr))
			throw _T("CoInitializeSecurity");

		CComPtr<IWbemLocator> wbemLocater = NULL;
		hr = CoCreateInstance(
				CLSID_WbemAdministrativeLocator,
			NULL, CLSCTX_INPROC_SERVER, IID_IWbemLocator,
			(LPVOID*)&wbemLocater);
		if (FAILED(hr))
			throw _T("CoCreateInstance");

		CComPtr<IWbemServices> wbemServices = NULL;
		hr = wbemLocater->ConnectServer(L"root\\cimv2",
			NULL, NULL, NULL,
			WBEM_FLAG_CONNECT_USE_MAX_WAIT,
			NULL, NULL, &wbemServices);
		if (FAILED(hr))
			throw _T("ConnectServer");

		CComPtr<IEnumWbemClassObject> wbemEnumerator = NULL;
		hr = wbemServices->ExecQuery(L"WQL",
			L"SELECT * FROM Win32_ComputerSystemProduct",
			WBEM_FLAG_FORWARD_ONLY, NULL, &wbemEnumerator);
		if (FAILED(hr))
			throw _T("ExecQuery");

		ULONG uReturned;
		while (wbemEnumerator)
		{
			CComPtr<IWbemClassObject> wbemObject = NULL;
			hr = wbemEnumerator->Next(
				WBEM_INFINITE, 1, &wbemObject, &uReturned);
			if (FAILED(hr))
				throw _T("Next");

			if (uReturned == 0)
				break;

			_variant_t vtProp;
			hr = wbemObject->Get(L"IdentifyingNumber",
				0, &vtProp, 0 ,0);
			if (FAILED(hr))
				throw _T("Get");

			wprintf(_T("%s\n"), (LPCTSTR)vtProp.bstrVal);
		}
	}
	catch (LPTSTR tszErr)
	{
		DWORD dwErr = GetLastError();
		FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, 0,
			hr, 0, tszMsg, sizeof(tszMsg), NULL);
		if (*tszMsg == 0)
		{
			BSTR bstrErr;
			IErrorInfo* pErrInfo;
			GetErrorInfo(0, &pErrInfo);
			pErrInfo->GetDescription(&bstrErr);
			if (*bstrErr == 0)
			{
				if (*tszMsg == 0)
				{
					FormatMessage(
						FORMAT_MESSAGE_FROM_SYSTEM, 
						0, dwErr, 0,
						tszMsg, sizeof(tszMsg), NULL);
				}
			}
		}
		_tprintf(_T("Error: [%s] %s\n"), tszErr, tszMsg);
		nRet = 1;
	}
	catch (...)
	{
		FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, 0,
			GetLastError(), 0,
			tszMsg, sizeof(tszMsg), NULL);
		_tprintf(_T("Error: [UnExpected], %s\n"), tszMsg);
		nRet = 1;
	}

	CoUninitialize();

	return nRet;
}