thoward
thoward

Reputation: 369

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

Upvotes: 4

Views: 10459

Answers (3)

Wouter Schut
Wouter Schut

Reputation: 927

A bit smaller solution than 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();
        }
    }

Tested this on win7 + win10. Btw, you can add extra search criteria to the regex if you want (or just add a new Where clause)

Upvotes: 1

Juderb
Juderb

Reputation: 735

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

Upvotes: 4

Juderb
Juderb

Reputation: 735

Your Windows 8 user profile probably included full administrator privileges while your Windows 10 user profile is a standard user. Because your Windows 10 user profile is a standard user, you must adjust some access permissions.

  1. Run the Computer Management utility.

  2. Go to Computer Management > Services and Applications > WMI Control.

  3. Go to Actions > WMI Control > More Actions > Properties to open the WMI Control Properties window.

  4. Under the Security tab, select Root, then press Security.

  5. In the Security for Root dialog, select your username or the group you belong to. Select Allow for Permissions > Execute Methods. Click OK to close the dialog.

  6. Repeat the previous step for CIMV2.

  7. Try running again with these new permissions.

Computer Management Utility WMI Control Properties for Root WMI Control Properties for CIMV2 Security Options for Root

Upvotes: 1

Related Questions