一尘不染

从Go查询WMI

go

我想从Go运行WMI查询。有几种方法可以从Go 调用DLL函数。我的理解是,在某个地方必须有一些DLL,通过正确的调用,它将返回一些我可以解析和使用的数据。我宁愿避免调用C或C
++,尤其是因为我猜想它们是Windows API本身的包装。

我检查了的输出dumpbin.exe /exports c:\windows\system32\wmi.dll,以下条目看起来很有希望:

WmiQueryAllDataA (forwarded to wmiclnt.WmiQueryAllDataA)

但是我不确定从这里做什么。此函数采用什么参数?它返回什么?搜索WmiQueryAllDataA没有帮助。并且该名称仅出现在的注释中c:\program files (x86)\windows kits\8.1\include\shared\wmistr.h,但没有函数签名。

有更好的方法吗?还有另一个DLL吗?我想念什么吗?我应该只使用C包装器吗?

使用.NET
Reflector在Linqpad中运行WMI查询显示了WmiNetUtilsHelper:ExecQueryWmi(和_f版本)的使用,但都没有可见的实现。

更新:
使用github.com/StackExchange/wmi软件包,该软件包在接受的答案中使用解决方案。


阅读 788

收藏
2020-07-02

共1个答案

一尘不染

从C
++刚刚起步的新世纪开始,您就来到了COM的美好世界,即C语言中的面向对象编程。

在github上,mattn 在Go中集成了一个小包装,我曾经使用它包装了一个快速的示例程序。“
这个存储库是为实验而创建的,应该被认为是不稳定的。 ”灌输了各种各样的信心。

我省去了很多错误检查。当我说时,请相信我,您将想要重新添加。

package main

import (
        "github.com/mattn/go-ole"
        "github.com/mattn/go-ole/oleutil"
)

func main() {
    // init COM, oh yeah
    ole.CoInitialize(0)
    defer ole.CoUninitialize()

    unknown, _ := oleutil.CreateObject("WbemScripting.SWbemLocator")
    defer unknown.Release()

    wmi, _ := unknown.QueryInterface(ole.IID_IDispatch)
    defer wmi.Release()

    // service is a SWbemServices
    serviceRaw, _ := oleutil.CallMethod(wmi, "ConnectServer")
    service := serviceRaw.ToIDispatch()
    defer service.Release()

    // result is a SWBemObjectSet
    resultRaw, _ := oleutil.CallMethod(service, "ExecQuery", "SELECT * FROM Win32_Process")
    result := resultRaw.ToIDispatch()
    defer result.Release()

    countVar, _ := oleutil.GetProperty(result, "Count")
    count := int(countVar.Val)

    for i :=0; i < count; i++ {
        // item is a SWbemObject, but really a Win32_Process
        itemRaw, _ := oleutil.CallMethod(result, "ItemIndex", i)
        item := itemRaw.ToIDispatch()
        defer item.Release()

        asString, _ := oleutil.GetProperty(item, "Name")

        println(asString.ToString())
    }
}

真正的问题是对ExecQuery的调用,我碰巧从可用的类中获取Win32_Process,因为它易于理解和打印。

在我的机器上,将打印:

System Idle Process
System
smss.exe
csrss.exe
wininit.exe
services.exe
lsass.exe
svchost.exe
svchost.exe
atiesrxx.exe
svchost.exe
svchost.exe
svchost.exe
svchost.exe
svchost.exe
spoolsv.exe
svchost.exe
AppleOSSMgr.exe
AppleTimeSrv.exe
... and so on
go.exe
main.exe

我不是在提升运行状态或未禁用UAC的情况下运行,但某些WMI提供程序将需要特权用户。

我也不是100%不会漏掉一点,您需要深入研究一下。COM对象是按引用计数的,因此defer应该很合适(前提是该方法长期运行不会疯狂),但是go-
ole可能有一些我没注意到的魔术。

2020-07-02