Obtener lista de dispositivos USB conectados

92

¿Cómo puedo obtener una lista de todos los dispositivos USB conectados en una computadora con Windows?

Robert
fuente

Respuestas:

119

Agregue una referencia a System.Management para su proyecto, luego intente algo como esto:

namespace ConsoleApplication1
{
  using System;
  using System.Collections.Generic;
  using System.Management; // need to add System.Management to your project references.

  class Program
  {
    static void Main(string[] args)
    {
      var usbDevices = GetUSBDevices();

      foreach (var usbDevice in usbDevices)
      {
        Console.WriteLine("Device ID: {0}, PNP Device ID: {1}, Description: {2}",
            usbDevice.DeviceID, usbDevice.PnpDeviceID, usbDevice.Description);
      }

      Console.Read();
    }

    static List<USBDeviceInfo> GetUSBDevices()
    {
      List<USBDeviceInfo> devices = new List<USBDeviceInfo>();

      ManagementObjectCollection collection;
      using (var searcher = new ManagementObjectSearcher(@"Select * From Win32_USBHub"))
        collection = searcher.Get();      

      foreach (var device in collection)
      {
        devices.Add(new USBDeviceInfo(
        (string)device.GetPropertyValue("DeviceID"),
        (string)device.GetPropertyValue("PNPDeviceID"),
        (string)device.GetPropertyValue("Description")
        ));
      }

      collection.Dispose();
      return devices;
    }
  }

  class USBDeviceInfo
  {
    public USBDeviceInfo(string deviceID, string pnpDeviceID, string description)
    {
      this.DeviceID = deviceID;
      this.PnpDeviceID = pnpDeviceID;
      this.Description = description;
    }
    public string DeviceID { get; private set; }
    public string PnpDeviceID { get; private set; }
    public string Description { get; private set; }
  }
}
Adel Hazzah
fuente
14
¿Hay alguna forma de recuperar también el nombre descriptivo del dispositivo? Por ejemplo, cuando entro en las propiedades de mi memoria USB, veo "Dispositivo USB Kingston DataTraveler 2.0".
Robert
1
¿Cuál es la diferencia entre DeviceID y PNPDeviceID?
Shimmy Weitzhandler
1
Cuando ejecuto el programa anterior, obtengo mis discos duros USB, mi teclado y mouse, pero no obtengo mi cámara USB, mi USB A / D. ¿Por qué no aparecen todos mis dispositivos USB?
Curt
8
se debe consultar "Win32_USBControllerDevice" y no "Win32_USBHub" para recibir la lista de todos los dispositivos USB. Luego use la propiedad "Dependiente" para obtener la cadena de dirección del dispositivo.
Nedko
1
esta búsqueda me lleva 8 segundos. ¿Existe alguna posibilidad de sujetar las cosas?
Daniel
45

Sé que estoy respondiendo a una pregunta anterior, pero acabo de realizar este mismo ejercicio y encontré un poco más de información, que creo que contribuirá mucho a la discusión y ayudará a cualquier otra persona que encuentre esta pregunta y vea dónde está las respuestas existentes se quedan cortas.

La respuesta aceptada es cercana y se puede corregir usando el comentario de Nedko . Una comprensión más detallada de las clases WMI involucradas ayuda a completar el cuadro.

Win32_USBHubdevuelve solo concentradores USB . Eso parece obvio en retrospectiva, pero la discusión anterior lo pasa por alto. No incluye todos los dispositivos USB posibles, solo aquellos que pueden (en teoría, al menos) actuar como un concentrador para dispositivos adicionales. Falta algunos dispositivos que no son concentradores (en particular, partes de dispositivos compuestos).

Win32_PnPEntityincluye todos los dispositivos USB y cientos de dispositivos que no son USB. El consejo de Russel Gantman de usar una búsqueda de cláusula WHERE Win32_PnPEntitypara un DeviceID que comience con "USB%" para filtrar la lista es útil pero un poco incompleto; echa de menos los dispositivos bluetooth, algunas impresoras / servidores de impresión, y ratones y teclados compatibles con HID. He visto "USB \%", "USBSTOR \%", "USBPRINT \%", "BTH \%", "SWD \%" y "HID \%". Win32_PnPEntitySin embargo, es una buena referencia "maestra" para buscar información una vez que tenga el PNPDeviceID de otras fuentes.

Lo que encontré fue que la mejor manera de enumerar los dispositivos USB fue consultar Win32_USBControllerDevice. Si bien no brinda información detallada para los dispositivos, enumera completamente sus dispositivos USB y le brinda un par de PNPDeviceIDs antecedente / dependiente para cada dispositivo USB (incluidos concentradores, dispositivos que no son concentradores y dispositivos compatibles con HID) en su sistema. Cada dependiente devuelto por la consulta será un dispositivo USB. El Antecedente será el Controlador al que está asignado, uno de los Controladores USB devueltos por la consulta Win32_USBController.

Como beneficio adicional, parece que, bajo el capó, WMI recorre el árbol de dispositivos cuando responde a la Win32_USBControllerDeviceconsulta, por lo que el orden en el que se devuelven estos resultados puede ayudar a identificar las relaciones entre padres e hijos. (Esto no está documentado y, por lo tanto, es solo una suposición; use CM_Get_Parent (o Child + Sibling ) de la API de SetupDi para obtener resultados definitivos). Como una opción para la API de SetupDi, parece que para todos los dispositivos enumerados a continuación Win32_USBHubse pueden buscar en el registro (at HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\ + PNPDeviceID) y tendrá un parámetro ParentIdPrefixque será el prefijo del último campo en el PNPDeviceID de sus hijos, por lo que también podría usarse en una coincidencia comodín para filtrar la Win32_PnPEntityconsulta.

En mi aplicación, hice lo siguiente:

  • (Opcional) Consulta Win32_PnPEntityy almacena los resultados en un mapa clave-valor (con PNPDeviceID como clave) para su posterior recuperación. Esto es opcional si desea realizar consultas individuales más adelante.
  • Busqué Win32_USBControllerDeviceuna lista definitiva de dispositivos USB en mi sistema (todos los dependientes) y extraje los PNPDeviceIDs de estos. Fui más allá, en función del orden que sigue el árbol de dispositivos, para asignar dispositivos al concentrador raíz (el primer dispositivo devuelto, en lugar del controlador) y construí un árbol basado en parentIdPrefix. El orden que devuelve la consulta, que coincide con la enumeración del árbol de dispositivos a través de SetupDi, es cada concentrador raíz (para quien el Antecedente identifica al controlador), seguido de una iteración de los dispositivos debajo de él, por ejemplo, en mi sistema:
    • Concentrador raíz del primer controlador
    • Concentrador raíz del segundo controlador
      • Primer concentrador debajo del concentrador raíz del segundo controlador (tiene parentIdPrefix)
        • Primer dispositivo compuesto debajo del primer concentrador debajo del concentrador raíz del segundo controlador (PNPDeviceID coincide con el ParentIdPrefix anterior del concentrador; tiene su propio ParentIdPrefix)
          • Dispositivo HID parte del dispositivo compuesto (PNPDeviceID coincide con el prefijo ParentIDPrefix del dispositivo compuesto)
        • Segundo dispositivo debajo del primer concentrador debajo del concentrador raíz del segundo controlador
          • Dispositivo HID parte del dispositivo compuesto
      • Segundo concentrador debajo del concentrador raíz del segundo controlador
        • Primer dispositivo debajo del segundo concentrador debajo del concentrador raíz del segundo controlador
      • Tercer concentrador debajo del concentrador raíz del segundo controlador
      • etc.
  • Consultado Win32_USBController. Esto me dio la información detallada de los PNPDeviceID de mis controladores que están en la parte superior del árbol de dispositivos (que eran los antecedentes de la consulta anterior). Utilizando el árbol derivado en el paso anterior, itera de forma recursiva sobre sus hijos (los concentradores raíz) y sus hijos (los otros concentradores) y sus hijos (dispositivos no concentradores y dispositivos compuestos) y sus hijos, etc.
    • Recuperé los detalles de cada dispositivo en mi árbol haciendo referencia al mapa almacenado en el primer paso. (Opcionalmente, uno podría omitir el primer paso y consultar Win32_PnPEntityindividualmente usando el PNPDeviceId para obtener la información en este paso; probablemente una compensación entre CPU y memoria determina qué orden es mejor).

En resumen, los Win32USBControllerDevicedependientes son una lista completa de dispositivos USB en un sistema (además de los propios controladores, que son los antecedentes en esa misma consulta), y al cruzar estos PNPDeviceIdpares con información del registro y de las otras consultas mencionadas, se puede construir una imagen detallada.

Daniel Widdis
fuente
Si uno tuviera 4 escáneres idénticos conectados, ¿cómo distinguiría cuál es cuál si se usaran en 4 operaciones diferentes, por ejemplo?
topshot
2
@topshot El PNPDeviceID es único siempre que esté conectado. No habría forma de saber si desconectó uno y conectó otro idéntico más tarde. Este ID también tiene referencias cruzadas en otras áreas para, con suerte, identificar qué operación se utiliza.
Daniel Widdis
3
Si los dispositivos tuvieran números de serie incorporados, entonces los dispositivos podrían diferenciarse (ese es el propósito de los números de serie). El número de serie se utiliza como "ID de instancia" de PnP. Si el dispositivo no contiene un número de serie, entonces el ID de instancia es esencialmente la ruta a través del árbol del dispositivo desde la raíz hasta el dispositivo (y contiene los caracteres '&')
Brian
Como alternativa, siempre hay que observar la lista de dispositivos y desconectar y volver a conectar mientras se observan los cambios.
Technophile
14

Para ver los dispositivos que me interesaban, reemplacé Win32_USBHubpor Win32_PnPEntityen el código de Adel Hazzah, basado en esta publicación . Esto funciona para mi:

namespace ConsoleApplication1
{
  using System;
  using System.Collections.Generic;
  using System.Management; // need to add System.Management to your project references.

  class Program
  {
    static void Main(string[] args)
    {
      var usbDevices = GetUSBDevices();

      foreach (var usbDevice in usbDevices)
      {
        Console.WriteLine("Device ID: {0}, PNP Device ID: {1}, Description: {2}",
            usbDevice.DeviceID, usbDevice.PnpDeviceID, usbDevice.Description);
      }

      Console.Read();
    }

    static List<USBDeviceInfo> GetUSBDevices()
    {
      List<USBDeviceInfo> devices = new List<USBDeviceInfo>();

      ManagementObjectCollection collection;
      using (var searcher = new ManagementObjectSearcher(@"Select * From Win32_PnPEntity"))
        collection = searcher.Get();      

      foreach (var device in collection)
      {
        devices.Add(new USBDeviceInfo(
        (string)device.GetPropertyValue("DeviceID"),
        (string)device.GetPropertyValue("PNPDeviceID"),
        (string)device.GetPropertyValue("Description")
        ));
      }

      collection.Dispose();
      return devices;
    }
  }

  class USBDeviceInfo
  {
    public USBDeviceInfo(string deviceID, string pnpDeviceID, string description)
    {
      this.DeviceID = deviceID;
      this.PnpDeviceID = pnpDeviceID;
      this.Description = description;
    }
    public string DeviceID { get; private set; }
    public string PnpDeviceID { get; private set; }
    public string Description { get; private set; }
  }
}
ocroqueta
fuente
Esto funcionó muy bien. Para facilitar la determinación del dispositivo que acaba de enchufar, escríbalo para que se ejecute en un intervalo, escriba las entradas en un diccionario e informe cualquier adición de la última vez que lo ejecutó.
nixkuroi
7

La respuesta de Adel Hazzah proporciona un código de trabajo, los comentarios de Daniel Widdis y Nedko mencionan que debe consultar Win32_USBControllerDevice y usar su propiedad Dependiente, y la respuesta de Daniel brinda muchos detalles sin código.

Aquí hay una síntesis de la discusión anterior para proporcionar un código de trabajo que enumere las propiedades del dispositivo PNP directamente accesibles de todos los dispositivos USB conectados:

using System;
using System.Collections.Generic;
using System.Management; // reference required

namespace cSharpUtilities
{
    class UsbBrowser
    {

        public static void PrintUsbDevices()
        {
            IList<ManagementBaseObject> usbDevices = GetUsbDevices();

            foreach (ManagementBaseObject usbDevice in usbDevices)
            {
                Console.WriteLine("----- DEVICE -----");
                foreach (var property in usbDevice.Properties)
                {
                    Console.WriteLine(string.Format("{0}: {1}", property.Name, property.Value));
                }
                Console.WriteLine("------------------");
            }
        }

        public static IList<ManagementBaseObject> GetUsbDevices()
        {
            IList<string> usbDeviceAddresses = LookUpUsbDeviceAddresses();

            List<ManagementBaseObject> usbDevices = new List<ManagementBaseObject>();

            foreach (string usbDeviceAddress in usbDeviceAddresses)
            {
                // query MI for the PNP device info
                // address must be escaped to be used in the query; luckily, the form we extracted previously is already escaped
                ManagementObjectCollection curMoc = QueryMi("Select * from Win32_PnPEntity where PNPDeviceID = " + usbDeviceAddress);
                foreach (ManagementBaseObject device in curMoc)
                {
                    usbDevices.Add(device);
                }
            }

            return usbDevices;
        }

        public static IList<string> LookUpUsbDeviceAddresses()
        {
            // this query gets the addressing information for connected USB devices
            ManagementObjectCollection usbDeviceAddressInfo = QueryMi(@"Select * from Win32_USBControllerDevice");

            List<string> usbDeviceAddresses = new List<string>();

            foreach(var device in usbDeviceAddressInfo)
            {
                string curPnpAddress = (string)device.GetPropertyValue("Dependent");
                // split out the address portion of the data; note that this includes escaped backslashes and quotes
                curPnpAddress = curPnpAddress.Split(new String[] { "DeviceID=" }, 2, StringSplitOptions.None)[1];

                usbDeviceAddresses.Add(curPnpAddress);
            }

            return usbDeviceAddresses;
        }

        // run a query against Windows Management Infrastructure (MI) and return the resulting collection
        public static ManagementObjectCollection QueryMi(string query)
        {
            ManagementObjectSearcher managementObjectSearcher = new ManagementObjectSearcher(query);
            ManagementObjectCollection result = managementObjectSearcher.Get();

            managementObjectSearcher.Dispose();
            return result;
        }

    }

}

Deberá agregar el manejo de excepciones si lo desea. Consulte la respuesta de Daniel si desea averiguar el árbol de dispositivos y demás.

Tydaeus
fuente
5

Este es un ejemplo mucho más simple para las personas que solo buscan unidades USB extraíbles.

using System.IO;

foreach (DriveInfo drive in DriveInfo.GetDrives())
{
    if (drive.DriveType == DriveType.Removable)
    {
        Console.WriteLine(string.Format("({0}) {1}", drive.Name.Replace("\\",""), drive.VolumeLabel));
    }
}
Baddack
fuente
2
También devolverá un disquete, probablemente lectores de tarjetas USB, posibles unidades Zip, Jazz y Orb
Mad Myche
Esta es la solución ideal para las personas que solo desean hacer coincidir el nombre descriptivo de un USB. Utilizo este ejemplo para la copia de seguridad de datos y, dado que la letra de la unidad cambia, necesito buscar el nombre (aquí drive.VolumeLabel)
Bio42
3

Si cambia ManagementObjectSearcher a lo siguiente:

ManagementObjectSearcher searcher = 
       new ManagementObjectSearcher("root\\CIMV2", 
       @"SELECT * FROM Win32_PnPEntity where DeviceID Like ""USB%"""); 

Entonces, "GetUSBDevices () se ve así"

static List<USBDeviceInfo> GetUSBDevices()
{
  List<USBDeviceInfo> devices = new List<USBDeviceInfo>();

  ManagementObjectCollection collection;
  using (var searcher = new ManagementObjectSearcher(@"SELECT * FROM Win32_PnPEntity where DeviceID Like ""USB%"""))
    collection = searcher.Get();      

  foreach (var device in collection)
  {
    devices.Add(new USBDeviceInfo(
    (string)device.GetPropertyValue("DeviceID"),
    (string)device.GetPropertyValue("PNPDeviceID"),
    (string)device.GetPropertyValue("Description")
    ));
  }

  collection.Dispose();
  return devices;
}

}

Sus resultados se limitarán a dispositivos USB (a diferencia de todos los tipos de su sistema)

Russell Gantman
fuente
1
La cláusula where que busca los ID de dispositivo que comienzan con USB omite algunos elementos. Es mejor iterar los dependientes de "Win32_USBControllerDevice"
Daniel Widdis
2

Puede encontrar este hilo útil. Y aquí hay un proyecto de código de Google que ejemplifica esto (P / Invoca en setupapi.dll).

Darin Dimitrov
fuente
¿Tiene alguna idea de por qué la clase ObjectQuery no tiene una referencia aunque estoy usando System.Management?
Robert
@Robert, ¿has añadido la referencia al proyecto? Puede hacer esto haciendo clic derecho en Referencias en su proyecto> Agregar referencia ...> Buscar y verificar System.Management> Aceptar.
Ernest
0
  lstResult.Clear();
  foreach (ManagementObject drive in new ManagementObjectSearcher("select * from Win32_DiskDrive where InterfaceType='USB'").Get())
  {
       foreach (ManagementObject partition in new ManagementObjectSearcher("ASSOCIATORS OF {Win32_DiskDrive.DeviceID='" + drive["DeviceID"] + "'} WHERE AssocClass = Win32_DiskDriveToDiskPartition").Get())
       {
            foreach (ManagementObject disk in new ManagementObjectSearcher("ASSOCIATORS OF {Win32_DiskPartition.DeviceID='" + partition["DeviceID"] + "'} WHERE AssocClass = Win32_LogicalDiskToPartition").Get())
            {
                  foreach (var item in disk.Properties)
                  {
                       object value = disk.GetPropertyValue(item.Name);
                  }
                  string valor = disk["Name"].ToString();
                  lstResult.Add(valor);
                  }
             }
        }
   }
JxDarkAngel
fuente
que hace eso object value?
novato
Haga un recorrido por las otras propiedades disponibles en el disco y guarde su valor en el valor del objeto
JxDarkAngel