从 Go 查询 WMI [英] Query WMI from Go

查看:30
本文介绍了从 Go 查询 WMI的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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

WmiQueryAllDataA(转发到 wmiclnt.WmiQueryAllDataA)

但是我不知道从这里做什么.这个函数接受什么参数?它返回什么?搜索 WmiQueryAllDataA 没有帮助.而且这个名字只出现在c:program files (x86)windows kits8.1includesharedwmistr.h的注释中,没有函数签名.

有更好的方法吗?是否有另一个DLL?我错过了什么吗?我应该只使用 C 包装器吗?

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

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

解决方案

欢迎来到COM,当 C++ 还是年轻的新贵"时,C 中的面向对象编程.

在 github mattn 上拼凑了一个 Go 中的小包装器,我用它来组合一个快速示例程序.这个存储库是为实验而创建的,应该被认为是不稳定的."灌输了各种信心.

我省略了很多错误检查.当我说的时候相信我,你会想把它加回来的.

主包进口 (github.com/mattn/go-ole"github.com/mattn/go-ole/oleutil")功能主要(){//初始化 COM,哦,是的ole.CoInitialize(0)推迟 ole.CoUninitialize()未知,_ := oleutil.CreateObject("WbemScripting.SWbemLocator")推迟未知.Release()wmi, _ := unknown.QueryInterface(ole.IID_IDispatch)推迟 wmi.Release()//服务是一个 SWbemServicesserviceRaw, _ := oleutil.CallMethod(wmi, "ConnectServer")服务 := serviceRaw.ToIDispatch()延迟服务.Release()//结果是一个 SWBemObjectSetresultRaw, _ := oleutil.CallMethod(service, "ExecQuery", "SELECT * FROM Win32_Process")结果 := resultRaw.ToIDispatch()推迟结果.Release()countVar, _ := oleutil.GetProperty(result, "Count")计数:= int(countVar.Val)对于我:= 0;我<数数;我++ {//item 是一个 SWbemObject,但实际上是一个 Win32_ProcessitemRaw, _ := oleutil.CallMethod(result, "ItemIndex", i)项目 := itemRaw.ToIDispatch()推迟 item.Release()asString, _ := oleutil.GetProperty(item, "Name")println(asString.ToString())}}

真正的关键是调用 ExecQuery,我正好抢到Win32_Process 来自可用类因为它易于理解和打印.

在我的机器上,打印:

系统空闲进程系统短信程序csrss.exe初始化程序服务.exelsass.exesvchost.exesvchost.exeatiesrxx.exesvchost.exesvchost.exesvchost.exesvchost.exesvchost.exespoolsv.exesvchost.exeAppleOSSMgr.exeAppleTimeSrv.exe... 等等去.exe主程序

我没有在提升或禁用 UAC 的情况下运行它,但一些 WMI 提供程序需要特权用户.

我也不是 100% 不会泄漏一点,你会想深入研究的.COM 对象是引用计数的,所以 defer 应该非常适合那里(前提是该方法不是疯狂长时间运行)但 go-ole 可能有一些我没有注意到的魔法.p>

I would like to run WMI queries from Go. There are ways to call DLL functions from Go. My understanding is that there must be some DLL somewhere which, with the correct call, will return some data I can parse and use. I'd prefer to avoid calling into C or C++, especially since I would guess those are wrappers over the Windows API itself.

I've examined the output of dumpbin.exe /exports c:windowssystem32wmi.dll, and the following entry looks promising:

WmiQueryAllDataA (forwarded to wmiclnt.WmiQueryAllDataA)

However I'm not sure what to do from here. What arguments does this function take? What does it return? Searching for WmiQueryAllDataA is not helpful. And that name only appears in a comment of c:program files (x86)windows kits8.1includesharedwmistr.h, but with no function signature.

Are there better methods? Is there another DLL? Am I missing something? Should I just use a C wrapper?

Running a WMI query in Linqpad with .NET Reflector shows the use of WmiNetUtilsHelper:ExecQueryWmi (and a _f version), but neither have a viewable implementation.

Update: use the github.com/StackExchange/wmi package which uses the solution in the accepted answer.

解决方案

Welcome to the wonderful world of COM, Object Oriented Programming in C from when C++ was "a young upstart".

On github mattn has thrown together a little wrapper in Go, which I used to throw together a quick example program. "This repository was created for experimentation and should be considered unstable." instills all sorts of confidence.

I'm leaving out a lot of error checking. Trust me when I say, you'll want to add it back.

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())
    }
}

The real meat is the call to ExecQuery, I happen to grab Win32_Process from the available classes because it's easy to understand and print.

On my machine, this prints:

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

I'm not running it elevated or with UAC disabled, but some WMI providers are gonna require a privileged user.

I'm also not 100% that this won't leak a little, you'll want to dig into that. COM objects are reference counted, so defer should be a pretty good fit there (provided the method isn't crazy long running) but go-ole may have some magic inside I didn't notice.

这篇关于从 Go 查询 WMI的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆