CentOS下Go语言实现远程Windows主机WMI监控及编译报错咨询
错误原因
github.com/StackExchange/wmi库的构建约束仅允许在Windows平台编译,因为它依赖Windows系统原生的WMI组件,所以在CentOS(Linux)环境下编译会触发build constraints exclude all Go files错误。
解决方案:使用跨平台WMI远程库
在Linux上远程查询Windows WMI,需要使用支持DCOM/RPC协议的跨平台Go库,推荐基于github.com/go-ole/go-ole实现,以下是具体步骤:
1. 安装系统与Go依赖
# CentOS安装DCOM/RPC相关系统依赖 sudo yum install -y pkgconfig libuuid-devel libgpg-error-devel # 安装Go依赖包 go get github.com/go-ole/go-ole go get github.com/go-ole/go-ole/oleutil
2. 修正后的实现代码
package main import ( "fmt" "log" "strconv" "github.com/go-ole/go-ole" "github.com/go-ole/go-ole/oleutil" ) // Win32_Processor CPU信息结构体 type Win32_Processor struct { Name string NumberOfCores uint32 } // Win32_LogicalDisk 磁盘信息结构体 type Win32_LogicalDisk struct { Name string Size uint64 FreeSpace uint64 } // Win32_OperatingSystem 内存信息结构体 type Win32_OperatingSystem struct { TotalVisibleMemorySize uint64 FreePhysicalMemory uint64 } func main() { // 初始化OLE库 err := ole.CoInitializeEx(0, ole.COINIT_APARTMENTTHREADED|ole.COINIT_SPEED_OVER_MEMORY) if err != nil { log.Fatalf("初始化OLE失败: %v", err) } defer ole.CoUninitialize() // 远程Windows主机配置 host := "172.16.2.2" username := "xyz" password := "1234567" // 构建远程WMI连接字符串 connStr := fmt.Sprintf(`\\%s\root\cimv2`, host) // 设置认证信息 security := ole.NewSecurity() err = security.SetUsernamePassword(username, password, "") if err != nil { log.Fatalf("设置认证信息失败: %v", err) } defer security.Release() // 获取WMI服务对象 service, err := oleutil.CreateObject("WbemScripting.SWbemLocator") if err != nil { log.Fatalf("创建WbemLocator对象失败: %v", err) } defer service.Release() locator, err := service.QueryInterface(ole.IID_IDispatch) if err != nil { log.Fatalf("获取IDispatch接口失败: %v", err) } defer locator.Release() wmiService, err := oleutil.CallMethod(locator, "ConnectServer", connStr, "", "", "", "", "", 0, security) if err != nil { log.Fatalf("连接远程WMI服务失败: %v", err) } defer wmiService.ToIDispatch().Release() // 查询CPU信息 fmt.Println("CPU信息:") cpuResults, err := oleutil.CallMethod(wmiService.ToIDispatch(), "ExecQuery", "SELECT Name, NumberOfCores FROM Win32_Processor") if err != nil { log.Fatalf("查询CPU信息失败: %v", err) } defer cpuResults.ToIDispatch().Release() cpuEnum, err := cpuResults.ToIDispatch().QueryInterface(ole.IID_IEnumVARIANT) if err != nil { log.Fatalf("获取CPU枚举器失败: %v", err) } defer cpuEnum.Release() for { var variant ole.VARIANT fetched, err := cpuEnum.Next(1, &variant, nil) if err != nil || fetched == 0 { break } defer variant.Clear() cpuDisp := variant.ToIDispatch() defer cpuDisp.Release() name, _ := oleutil.GetProperty(cpuDisp, "Name") defer name.Clear() coreCount, _ := oleutil.GetProperty(cpuDisp, "NumberOfCores") defer coreCount.Clear() coreUint, _ := strconv.ParseUint(fmt.Sprintf("%v", coreCount.Value()), 10, 32) fmt.Printf(" - 型号: %s, 核心数: %d\n", name.Value(), coreUint) } // 查询磁盘信息 fmt.Println("\n磁盘使用情况:") diskResults, err := oleutil.CallMethod(wmiService.ToIDispatch(), "ExecQuery", "SELECT Name, Size, FreeSpace FROM Win32_LogicalDisk WHERE DriveType=3") if err != nil { log.Fatalf("查询磁盘信息失败: %v", err) } defer diskResults.ToIDispatch().Release() diskEnum, err := diskResults.ToIDispatch().QueryInterface(ole.IID_IEnumVARIANT) if err != nil { log.Fatalf("获取磁盘枚举器失败: %v", err) } defer diskEnum.Release() for { var variant ole.VARIANT fetched, err := diskEnum.Next(1, &variant, nil) if err != nil || fetched == 0 { break } defer variant.Clear() diskDisp := variant.ToIDispatch() defer diskDisp.Release() name, _ := oleutil.GetProperty(diskDisp, "Name") defer name.Clear() size, _ := oleutil.GetProperty(diskDisp, "Size") defer size.Clear() freeSpace, _ := oleutil.GetProperty(diskDisp, "FreeSpace") defer freeSpace.Clear() sizeUint, _ := strconv.ParseUint(fmt.Sprintf("%v", size.Value()), 10, 64) freeUint, _ := strconv.ParseUint(fmt.Sprintf("%v", freeSpace.Value()), 10, 64) fmt.Printf(" - 盘符: %s, 总容量: %.2f GB, 剩余容量: %.2f GB\n", name.Value(), float64(sizeUint)/(1024*1024*1024), float64(freeUint)/(1024*1024*1024)) } // 查询内存信息 fmt.Println("\n内存信息:") memResults, err := oleutil.CallMethod(wmiService.ToIDispatch(), "ExecQuery", "SELECT TotalVisibleMemorySize, FreePhysicalMemory FROM Win32_OperatingSystem") if err != nil { log.Fatalf("查询内存信息失败: %v", err) } defer memResults.ToIDispatch().Release() memEnum, err := memResults.ToIDispatch().QueryInterface(ole.IID_IEnumVARIANT) if err != nil { log.Fatalf("获取内存枚举器失败: %v", err) } defer memEnum.Release() for { var variant ole.VARIANT fetched, err := memEnum.Next(1, &variant, nil) if err != nil || fetched == 0 { break } defer variant.Clear() memDisp := variant.ToIDispatch() defer memDisp.Release() totalMem, _ := oleutil.GetProperty(memDisp, "TotalVisibleMemorySize") defer totalMem.Clear() freeMem, _ := oleutil.GetProperty(memDisp, "FreePhysicalMemory") defer freeMem.Clear() totalUint, _ := strconv.ParseUint(fmt.Sprintf("%v", totalMem.Value()), 10, 64) freeUint, _ := strconv.ParseUint(fmt.Sprintf("%v", freeMem.Value()), 10, 64) fmt.Printf(" - 总容量: %.2f GB, 剩余容量: %.2f GB\n", float64(totalUint)/(1024*1024), float64(freeUint)/(1024*1024)) } }
3. 编译运行
在CentOS环境下直接执行:
go run main.go
注意事项
- 确保远程Windows主机的
Windows Management Instrumentation服务正常运行 - 防火墙需允许RPC通信(默认端口135及动态端口范围)
- 所用Windows账号需具备WMI查询权限(管理员权限优先)
内容的提问来源于stack exchange,提问作者M.K.S
相关产品推荐
相关产品推荐

