65.9K
CodeProject 正在变化。 阅读更多。
Home

使用 WMI 服务连接系统

starIconstarIconstarIconstarIconstarIcon

5.00/5 (1投票)

2014年4月21日

CPOL

4分钟阅读

viewsIcon

15674

downloadIcon

298

使用 WMI 服务连接系统,包括远程和本地系统

WMI 在不同的操作系统上行为不同。本技巧/窍门中提供的代码已在 Window XP SP2、SP3(域和工作组)、Windows 7 SP1(域)、Windows Server 2003 SP2 和 Windows 8(域)上进行过测试。

引言

对于本技巧中的任何语法错误,敬请谅解。本技巧主要讲解如何连接 WMI 服务到本地和远程计算机。

背景

嗯,一开始我不想写这个技巧,因为网上已经有很多代码了。但很多时候,这些代码并不尽如人意。最终促使我写了这篇文章。希望我做到了。

Using the Code

很多时候,在连接 WMI 服务时,我都会收到“访问被拒绝”的错误消息。但我对 VC++ 并没有失去信心,这要归功于 MSDN。

这里有一个简单的程序,可以通过 WMI 服务连接到远程系统。

在每一步,我都检查了远程系统的安全性。

我从以下网址找到了获取主机名和域名的方法

http://msdn.microsoft.com/en-us/library/ms992621%28v=EXCHG.65%29.aspx

上面的部分是必需的,因为我们不知道是否会意外地输入本地计算机名,因为与 Explorer 不同,WMI 类无法连接到本地计算机。因此,为了预防起见,我使用了这个。另外,我们也不知道输入的字符串是计算机名还是 IP 地址。因此,我们使用了 Is3Dots。如果提供了 IP 地址,则获取所提供 IP 的主机(计算机)名,然后执行比较。

CREDUI_INFO 结构用于传递用于 "CredUIPromptForCredentials" 的结构。这会提供凭据对话框,从中提取用户名和密码。一旦我们有了 **用户名** 和 **密码**,我们就可以为将来使用而保留它们。这里需要注意的重要一点是 -

slash = _tcschr ( pszName , L'\\' ) ;
if ( slash == NULL )
{
    AfxMessageBox ( _T("Could not create Auth identity. No domain specified\nEnter the Credentails as \"DomainName\\UserName\"") ) ;
                        
    continue ;
}  

这样可以确保我们一次性获取 **用户名** 和 **域名**。

运行窗口直到提供的 **用户名** 和 **密码** 与远程计算机的 Windows 凭据匹配,或者用户取消操作。在我们获取 **用户名** 和 **密码** 后,我们验证凭据。首先,我们使用 WNetCancelConnection2http://msdn.microsoft.com/en-us/library/windows/desktop/aa385427%28v=vs.85%29.aspx)取消为远程计算机设置的所有凭据,然后使用 WNetUseConnectionhttp://msdn.microsoft.com/en-us/library/windows/desktop/aa385482%28v=vs.85%29.aspx),该函数使用用户提供的用户名和密码来验证连接详细信息。与 WNetAddConnectionhttp://msdn.microsoft.com/en-us/library/windows/desktop/aa385413%28v=vs.85%29.aspx)不同,它将使用先前提供的凭据。

这是在一个循环中进行的,直到执行了“成功”或“取消”操作。

在验证了远程系统后,我们可以通过步骤 4 连接到远程系统的 WMI 服务

 hres = pLoc->ConnectServer(
        _bstr_t ( strServer ),
        _bstr_t ( useToken ? NULL : pszName ) ,   // User name
        _bstr_t ( useToken ? NULL : pszPwd  ) ,   // User password
        NULL,                              // Locale             
        NULL,                              // Security flags
        _bstr_t ( useNTLM ? NULL : pszAuthority ) ,// Authority        
        NULL,                              // Context object 
        &pSvc                              // IWbemServices proxy
        ); 

本地计算机的 strServer 将是 -

strServer = _T("\\\\.\\root\\cimv2") ;  

远程系统的 strServer 将是 -

strServer = _T("\\\\<Computer_Name> or <IP Address>\\root\\cimv2") ;  

COAUTHIDENTITY 在步骤 5 中起着重要作用,可用于设置代理的安全。

主要问题在于连接以及通过正确的逻辑来处理。这可以通过“CoSetProxyBlanket”(http://msdn.microsoft.com/en-us/library/aa910618.aspx)来实现。正确使用它可以使我们一开始就“赢得一半的战斗”。这在步骤 6 和步骤 8 中完成。

CoSetProxyBlanket(
        pSvc,                           // Indicates the proxy to set
        RPC_C_AUTHN_DEFAULT,            // RPC_C_AUTHN_xxx
        RPC_C_AUTHZ_DEFAULT,            // RPC_C_AUTHZ_xxx
        COLE_DEFAULT_PRINCIPAL,         // Server principal name 
        RPC_C_AUTHN_LEVEL_PKT_PRIVACY,  // RPC_C_AUTHN_LEVEL_xxx 
        RPC_C_IMP_LEVEL_IMPERSONATE,    // RPC_C_IMP_LEVEL_xxx
        userAcct,                       // client identity
        EOAC_NONE                       // proxy capabilities 
    );  

与其他语言一样,C++ 也通过 WMI 类维护安全性,这不仅有助于用户正确验证远程系统的凭据,还有助于开发人员维护安全性,以避免凭据验证中的任何缺陷或泄露。

在绑定了凭据之后,我们就可以在 ExecQuery 中获取所有需要的信息了,这在步骤 7 中完成。该函数看起来像 -

IEnumWbemClassObject* pEnumerator = NULL ;
hres = pSvc->ExecQuery ( SysAllocString(L"WQL"),  SysAllocString(L"Select * from Win32_LogicalDisk"),
        WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_WBEM_COMPLETE , 
        NULL , &pEnumerator ) ; 

凭据之后的重要部分是运行查询。在此示例中,我使用了 -Win32_LogicalDisk。此函数不区分大小写。

**步骤 7** 处理所需数据的提取。在此示例中,我只需要逻辑磁盘名称及其驱动器号。

我在每一步之后都使用了 GetErrorMessage 函数,以便了解代码生成失败的位置,并从系统中适当地获取错误消息。

void GetErrorMessage ( HRESULT hresRet = NULL, CString strText = _T("") )
{
    LPVOID lpMsgBuf = NULL ;
    FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
                NULL , hresRet , 0, (LPTSTR) &lpMsgBuf, 0, NULL ) ;
    
    strText = (LPCTSTR)lpMsgBuf + strText ;
    
    AfxMessageBox ( strText , MB_OK | MB_ICONERROR ) ;

    LocalFree ( lpMsgBuf ) ;
} 

在列表控件中收到输出后,请勿忘记在程序结束前释放所有使用的资源。优秀的程序员总是明智地使用计算机和代码资源。

要获取正确的信息,请转到 **运行** 命令,键入“**wbemtest**”,然后连接到所需的计算机。

其他 WMI 类和参考可以在以下网址找到

http://msdn.microsoft.com/en-us/library/aa394554%28v=vs.85%29.aspx

一旦您熟悉了 WMI 类,就很容易理解。

WMI 类工具可以从以下网址下载 -

http://www.microsoft.com/en-us/download/details.aspx?id=24045

关注点

我搜索了数百个代码,但找不到正确的连接方法。这最终导致我破解了 Microsoft Windows 安全部门的 WMI 类。希望这能帮助您理解 WMI 类并提取所需的信息。

历史

将来我将发布一些关于枚举 WMI 类中的所有属性/标题和信息的内容。在那之前,祝您好运。

使用 WMI 服务连接系统 - CodeProject - 代码之家
© . All rights reserved.