【问题标题】:WMI not working after upgrading to Windows 10升级到 Windows 10 后 WMI 无法正常工作
【发布时间】:2023-08-17 08:55:01
【问题描述】:

我一直在使用下面的代码在 Windows 8 上的 Visual Studio 中的控制台应用程序中返回连接的串行设备的描述和设备 ID。我在我正在创建的应用程序中使用它的修改版本来自动检测 Arduino 的 COM 端口。自从我使用 Windows 10 进行全新安装后,它不再返回任何内容。我有一个 USB 转串行 AVR 编程器,但是仍然使用此代码显示。我检查了注册表,Arduino 列在 SERIALCOMM 中,Arduino 在设备管理器的“端口(COM 和 LPT)”下显示为“USB 串行端口(COM6)”,我可以使用 Arduino 软件对 Arduino 进行编程。我不知道为什么它不再工作了。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Management;
using System.IO.Ports;
using System.Diagnostics;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main() 
        {


            ManagementScope connectionScope = new ManagementScope();
            SelectQuery serialQuery = new SelectQuery("SELECT * FROM Win32_SerialPort");
            ManagementObjectSearcher searcher = new ManagementObjectSearcher(connectionScope, serialQuery);

            try
            {
                foreach (ManagementObject item in searcher.Get())
                {
                    string desc = item["Description"].ToString();
                    string deviceId = item["DeviceID"].ToString();

                    Console.WriteLine(desc);
                    Console.WriteLine(deviceId);
                }
            }
            catch (ManagementException e)
            {
                Console.WriteLine(e.Message);
            }

            Console.ReadKey();
        }
    }
}

这也可能是相关的,在尝试找到解决方案时,我发现了以下实现来使用 MSSerial_PortName 查找端口名称,但出现访问被拒绝错误。

using System;
using System.Management;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main() 
        {
            try
            {
                ManagementObjectSearcher MOSearcher = new ManagementObjectSearcher("root\\WMI", "SELECT * FROM MSSerial_PortName");

                foreach (ManagementObject MOject in MOSearcher.Get())
                {
                    Console.WriteLine(MOject["PortName"]); 
                }
            }
            catch (ManagementException me)
            {
                Console.WriteLine("An error occurred while querying for WMI data: " + me.Message);
            }
            Console.ReadKey();
        }
    }
}

【问题讨论】:

  • 听起来像是身份验证问题。将 ConnectionOptions 实例传递给您的 ManagementScope 构造函数,定义您的 Authentication 和 Impersonation 属性。
  • 谢谢@Juderb 我只是在我自己的机器上本地使用它,我尝试了你的建议,我将 ImpersonationLevel 设置为 Impersonate (这是它运行的唯一级别),我尝试了所有AuthenticationLevel 的不同选项和代码仍然只能找到我的 USB 到串行 AVR 程序员,而不是我的 Arduinos。将 AuthenticationLevel 和 ImpersonationLevel 添加到我发布的使用 MSSerial_PortName 的第二个代码块没有任何区别,我仍然得到拒绝访问(模拟和身份验证级别的所有不同组合)。
  • 默认用户无法访问系统设备!需要以管理员身份运行共享库或设备...
  • @dsgdfg 我正在使用管理员帐户(或者我是否特别必须以管理员身份运行控制台应用程序?)并且当此代码适用于我的 Arduino 时,我还在 Windows 8 上使用管理员帐户。由于它适用于一个串行设备但不适用于另一个串行设备,这让我认为它可能与权限或身份验证无关。

标签: c# wmi windows-10


【解决方案1】:

好的,我想我现在看到了问题(我会添加一个新答案,但不会替换旧答案,以防有人发现该信息有用)。

Win32_SerialPort 仅检测硬件串行端口(例如 RS232)。 Win32_PnPEntity 识别即插即用设备,包括硬件和虚拟串行端口(例如由 FTDI 驱动程序创建的 COM 端口)。

使用Win32_PnPEntity 来识别驱动程序需要一些额外的工作。以下代码识别系统上的所有 COM 端口并生成所述端口的列表。从这个列表中,您可以确定合适的 COM 端口号来创建您的 SerialPort 对象。

// Class to contain the port info.
public class PortInfo
{
  public string Name;
  public string Description;
}

// Method to prepare the WMI query connection options.
public static ConnectionOptions PrepareOptions ( )
{
  ConnectionOptions options = new ConnectionOptions ( );
  options . Impersonation = ImpersonationLevel . Impersonate;
  options . Authentication = AuthenticationLevel . Default;
  options . EnablePrivileges = true;
  return options;
}

// Method to prepare WMI query management scope.
public static ManagementScope PrepareScope ( string machineName , ConnectionOptions options , string path  )
{
  ManagementScope scope = new ManagementScope ( );
  scope . Path = new ManagementPath ( @"\\" + machineName + path );
  scope . Options = options;
  scope . Connect ( );
  return scope;
}

// Method to retrieve the list of all COM ports.
public static List<PortInfo> FindComPorts ( )
{
  List<PortInfo> portList = new List<PortInfo> ( );
  ConnectionOptions options = PrepareOptions ( );
  ManagementScope scope = PrepareScope ( Environment . MachineName , options , @"\root\CIMV2" );

  // Prepare the query and searcher objects.
  ObjectQuery objectQuery = new ObjectQuery ( "SELECT * FROM Win32_PnPEntity WHERE ConfigManagerErrorCode = 0" );
  ManagementObjectSearcher portSearcher = new ManagementObjectSearcher ( scope , objectQuery );

  using ( portSearcher )
  {
    string caption = null;
    // Invoke the searcher and search through each management object for a COM port.
    foreach ( ManagementObject currentObject in portSearcher . Get ( ) )
    {
      if ( currentObject != null )
      {
        object currentObjectCaption = currentObject [ "Caption" ];
        if ( currentObjectCaption != null )
        {
          caption = currentObjectCaption . ToString ( );
          if ( caption . Contains ( "(COM" ) )
          {
            PortInfo portInfo = new PortInfo ( );
            portInfo . Name = caption . Substring ( caption . LastIndexOf ( "(COM" ) ) . Replace ( "(" , string . Empty ) . Replace ( ")" , string . Empty );
            portInfo . Description = caption;
            portList . Add ( portInfo );
          }
        }
      }
    }
  }
  return portList;
}

【讨论】:

  • 太好了,很高兴听到它!令人惊讶的是,使用 WMI 进行的练习如此复杂。
  • 我冒昧地修正了代码中的几个错别字:options 的字段是错误的。
【解决方案2】:

您的 Windows 8 用户配置文件可能包含完整的管理员权限,而您的 Windows 10 用户配置文件是标准用户。由于您的 Windows 10 用户配置文件是标准用户,因此您必须调整一些访问权限。

  1. 运行Computer Management 实用程序。

  2. 转到Computer Management &gt; Services and Applications &gt; WMI Control

  3. 转到Actions &gt; WMI Control &gt; More Actions &gt; Properties 打开WMI Control Properties 窗口。

  4. Security 标签下,选择Root,然后按Security

  5. Security for Root 对话框中,选择您的用户名或您所属的组。选择Allow for Permissions &gt; Execute Methods。点击OK关闭对话框。

  6. CIMV2重复上一步。

  7. 尝试使用这些新权限再次运行。

【讨论】:

  • 我尝试了您的建议,但仍然无法正常工作。当使用 Win32_SerialPort(而不是 MSSerial_PortName)时,它可以找到我的 USB AVR 编程器,但找不到我的 Arduino,这一事实让我认为这不是与权限相关的问题。有趣的是,正如我所提到的,它适用于使用编程器制造商 (Pololu) 的驱动程序安装的 USB AVR 编程器,不适用于我的 Arduino 和我拥有的 USB 到串行适配器,两者都安装为“ USB 串行端口”,制造商列为 FTDI(他们在这些设备上制造 USB 转串行 IC)。
  • @thoward,试试我的第二个答案。这就是我在全自动显微镜系统和 III 类医疗设备中的几个组件使用的方法(即在正确实施时它很强大)。
【解决方案3】:

比 Juderb 小一点的解决方案

    public static List<string> FindComPorts()
    {
        using (var searcher = new ManagementObjectSearcher("SELECT * FROM Win32_PnPEntity WHERE ConfigManagerErrorCode = 0"))
        {
            return searcher.Get().OfType<ManagementBaseObject>()
                .Select(port => Regex.Match(port["Caption"].ToString(), @"\((COM\d*)\)"))
                .Where(match => match.Groups.Count >= 2)
                .Select(match => match.Groups[1].Value).ToList();
        }
    }

在win7 + win10上测试过。顺便说一句,您可以根据需要向正则表达式添加额外的搜索条件(或者只是添加一个新的 Where 子句)

【讨论】:

  • 比我原来的解决方案干净得多。
最近更新 更多