Search code examples
c#wmiwindows-10

WMI not working after upgrading to Windows 10


I had been using the code below for a console application in Visual Studio on Windows 8 to return the description and device ID of connected serial devices. I was using a modified version of this in an application I'm creating to automatically detect the COM port of an Arduino. It no longer returns anything since I've done a fresh install with Windows 10. I have a USB to serial AVR programmer that still shows up using this code however. I checked the registry and the Arduino is listed in SERIALCOMM, the Arduino is showing as 'USB Serial Port (COM6)' under 'Ports (COM & LPT)' in Device Manager and I can program the Arduino using the Arduino software. I have no idea why it isn't working any more.

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

It might also be relevant that while trying to find a solution I found the following implementation to find port names using MSSerial_PortName and I got an Access Denied error.

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

Solution

  • Ok, I think I see the issue now (I will add a new answer, but won't replace the old in case someone finds the information useful).

    Win32_SerialPort only detects hardware serial ports (e.g. RS232). Win32_PnPEntity identifies plug-and-play devices including hardware and virtual serial ports (e.g. COM port created by the FTDI driver).

    To use Win32_PnPEntity to identify a driver requires a little extra work. The following code identifies all COM ports on the system and produces a list of said ports. From this list, you may identify the appropriate COM port number to create your SerialPort object.

    // 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;
    }