You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 22:10:00