wmi获取禁用网卡的mac地址

wmi获取禁用网卡的mac地址

  • 最近遇到一个性能问题,我们的软件启动需要验证License,验证License需要获取网卡的mac地址(无论是禁用的还是启用的)。之前的做法是运行一个进程执行 chcp 437&&powershell Get-NetAdapter
    • 这相当于先开启一个cmd 执行 chcp 437 ,然后在cmd再启动 powershell 执行 Get-NetAdapter
    • 此操作相当耗时,基本上要耗时2秒以上,这对于软件启动来说是不可接受的
    • 所以就研究了 powershell执行的 Get-NetAdapter 底层是如何实现的,是否可以在 C# 中直接复刻实现以达到减少耗时的目的。

为什么采用启动powershell的方式去获取网卡的mac地址

  • 常用的获取网卡地址的方式

    1. NetworkInterface.GetAllNetworkInterfaces获取不到禁用的网卡信息

      csharp 复制代码
      var list = NetworkInterface.GetAllNetworkInterfaces();
      foreach (var item in list)
      {
          var name = item.Name;
          var address = item.GetPhysicalAddress();
          Debug.WriteLine($"name: {name}, mac: {address}");
      }
    2. 使用wmi方式获取 Win32_NetworkAdapter获取不到禁用网卡的Mac地址

      csharp 复制代码
      using (var search = new ManagementObjectSearcher("select * from Win32_NetworkAdapter where PhysicalAdapter = TRUE"))
      {
          foreach(ManagementObject item in search.Get())
          {
              string name = item["Name"]?.ToString();
              string address = item["MACAddress"]?.ToString();
              Debug.WriteLine($"name: {name}, mac: {address}");
          }
      }
  • 基于以上两种常用的方式都无法获取到禁用网卡的信息,故最后采用绕远路的方法:启动powershell执行 get-netadapter

powershell的 get-netadapter底层做了些什么?

  • 经过查阅资料,get-netadapter 其实是调用了 Get-CimInstance -Namespace root/StandardCimv2 -ClassName MSFT_NetAdapter
  • 于是兴冲冲的打开 powershell 执行了以上命令,结果输出的内容很多,与 get-netadapter 输出的内容大相径庭。
  • 但是在执行完一遍get-netadapter之后,再次运行 Get-CimInstance 命令,发现输出内容确实一致
    • 这里问了chatgpt,说是get-adapter 会做一些初始化的操作,如果先执行 get-ciminstance (在没有初始化的前提下),会输出一些不正确的内容。
  • get-ciminstance 命令其实就是调用的 wmi

什么是wmi

  • wmi: windows management instruments windows管理规范,提供了系统信息访问的api

  • 一句话总结:wmi=windows的系统级数据库,你可以通过wql语句查看和控制系统

  • 那cim又是什么东西?

    • wmi是基于 cim 实现的,common infomation model, 意思就是将系统资源抽象成类
    • 我们可以通过查询语句去访问这些资源类对象的信息
  • 微软将系统资源抽象成类,把这些类放在不同的命名空间下(默认的命名空间为root\CIMV2),并且将类的名称添加了前缀,具体划分规则如下

    类名前缀 来源 典型命名空间 举例
    Win32_ 传统 WMI 类(早期,兼容旧系统) root\CIMV2 Win32_Process, Win32_NetworkAdapter
    MSFT_ 新一代 CIM 类(基于 PowerShell 和 DMTF 标准) root\StandardCimv2 MSFT_NetAdapter, MSFT_Disk, MSFT_NetIPAddress
    CIM_ 标准 DMTF(跨平台)类 root\CIMV2 CIM_LogicalDisk, CIM_ComputerSystem
    自定义(厂商名) 第三方 / OEM 驱动提供 root\WMIroot\<vendor> Intel_SMBIOSData, Dell_BIOSProvider
  • windows界面的设备管理器有一部分的实现就是基于 wmi

类名 描述
Win32_Process 表示系统中的一个进程
Win32_Service 表示一个 Windows 服务
MSFT_NetAdapter 表示一个网络适配器
Win32_LogicalDisk 表示一个逻辑磁盘(C盘、D盘等)

如何使用wmi呢?

  • powershell
    • 访问 Win32_NetworkAdapter类对象: get-ciminstance -classname win32_networkadapter
  • C#: 上面已经讲过

解决方案

  • 既然已经知道powershell的命令get-netadapter 底层是 Get-CimInstance -Namespace root/StandardCimv2 -ClassName MSFT_NetAdapter,那么我们就可以应用到c#上
csharp 复制代码
using (var search = new ManagementObjectSearcher("root/standardcimv2", "select * from msft_netadapter"))
{
    foreach (ManagementObject item in search.Get())
    {
        string name = item["Name"]?.ToString();
        string address = item["MacAddress"]?.ToString();
        Debug.WriteLine($"name: {name}, mac: {address}");
    }
}
  • 但是!!!运行报错了 ,提示没有 MacAddress这个字段,又是经过了一番尝试,发现原来这里是 PermanentAddress,可能是powershell 为了显示的更准确,自行改了字段的名称

扩展

走的歪路:使用c++调用wmi获取系统信息

  • 之前做了很多尝试依旧不得入门,无法在C#中获取到禁用网卡的mac地址,于是转而让chatgpt给个c++的方案,虽然给的代码很多编译报错,运行报错,最后终于运行起来一次(连续运行第二次就崩溃),好歹成功获取到了,也就是这里发现读取的是 PermanentAddress 字段,而不是 MacAddress,最终找到了在C#中的正确方案。
    • 在得到正确方案后,也就没有再研究c++方案为什么运行第二次就会崩溃的问题,空下来再说(自我安慰,基本上是不会再去看那段代码了)
相关推荐
李宥小哥2 小时前
行为型设计模式2
windows·设计模式
vortex54 小时前
RDP 启用多用户会话(当前用户无感知)
windows·网络安全·渗透测试
私人珍藏库9 小时前
WiFi密码B破器-密码查看器、可跑字典-免费无广
windows·wifi·工具
淮北49417 小时前
windows11配置wsl安装ubuntu20.04
windows·学习·ubuntu·wsl
shykevin19 小时前
uni-app x开发商城系统,商品列表点击跳转至商品详情页
windows·uni-app
std8602121 小时前
微软解除 Win11 限制,“毛玻璃”效果将无处不在
windows
csdn_aspnet21 小时前
如何在 Mac、Ubuntu、CentOS、Windows 上安装 MySQL 客户端
linux·windows·mysql·macos·centos
24kHT21 小时前
conda以及Jupyter notebook的使用
windows·jupyter·conda
alphaTao1 天前
LeetCode 每日一题 2025/11/3-2025/11/9
windows·leetcode