Obtenir la liste des périphériques USB connectés

92

Comment puis-je obtenir une liste de tous les périphériques USB connectés sur un ordinateur Windows?

Robert
la source

Réponses:

119

Ajoutez une référence à System.Management pour votre projet, puis essayez quelque chose comme ceci:

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
la source
14
Existe-t-il également un moyen de récupérer le nom convivial de l'appareil? Par exemple, lorsque je vais dans les propriétés de ma clé USB, je vois "Kingston DataTraveler 2.0 USB Device".
Robert
1
Quelle est la différence entre DeviceID et PNPDeviceID?
Shimmy Weitzhandler
1
Lorsque j'exécute le programme ci-dessus, je reçois mes disques durs USB, mon clavier et ma souris, mais je ne reçois pas ma caméra USB, mon USB A / D. Pourquoi tous mes périphériques USB ne s'affichent-ils pas?
Curt
8
il doit être interrogé "Win32_USBControllerDevice" et non "Win32_USBHub" afin de recevoir la liste de tous les périphériques USB. Ensuite, utilisez la propriété "Dependent" pour obtenir la chaîne d'adresse du périphérique.
Nedko
1
cette recherche prend 8 secondes pour moi. Y a-t-il une possibilité de fixer les choses?
daniel
45

Je sais que je réponds à une vieille question, mais je viens de faire le même exercice et j'ai trouvé un peu plus d'informations, qui, je pense, contribueront beaucoup à la discussion et aideront toute autre personne qui trouve cette question et voit où le les réponses existantes sont insuffisantes.

La réponse acceptée est proche et peut être corrigée en utilisant le commentaire de Nedko . Une compréhension plus détaillée des classes WMI impliquées permet de compléter le tableau.

Win32_USBHubrenvoie uniquement les concentrateurs USB . Cela semble évident avec le recul, mais la discussion ci-dessus manque. Il n'inclut pas tous les périphériques USB possibles, seulement ceux qui peuvent (au moins en théorie) servir de hub pour des périphériques supplémentaires. Il manque certains appareils qui ne sont pas des concentrateurs (en particulier des parties d'appareils composites).

Win32_PnPEntityinclut tous les périphériques USB et des centaines d'autres périphériques non USB. Le conseil de Russel Gantman d'utiliser une clause WHERE recherche Win32_PnPEntityun DeviceID commençant par "USB%" pour filtrer la liste est utile mais légèrement incomplet; il manque des périphériques Bluetooth, certaines imprimantes / serveurs d'impression et des souris et claviers compatibles HID. J'ai vu "USB \%", "USBSTOR \%", "USBPRINT \%", "BTH \%", "SWD \%" et "HID \%". Win32_PnPEntityest, cependant, une bonne référence "principale" pour rechercher des informations une fois que vous êtes en possession du PNPDeviceID provenant d'autres sources.

Ce que j'ai trouvé, c'est que le meilleur moyen d'énumérer les périphériques USB était d'interroger Win32_USBControllerDevice. Bien qu'il ne donne pas d'informations détaillées sur les périphériques, il énumère complètement vos périphériques USB et vous donne une paire de PNPDeviceIDs Antécédent / Dépendant pour chaque périphérique USB (y compris les concentrateurs, les périphériques non-Hub et les périphériques compatibles HID) sur votre système. Chaque Dépendant renvoyé par la requête sera un périphérique USB. L'antécédent sera le contrôleur auquel il est assigné, l'un des contrôleurs USB renvoyé par l'interrogation Win32_USBController.

En prime, il semble que sous le capot, WMI parcourt l' arborescence des périphériques en répondant à la Win32_USBControllerDevicerequête, de sorte que l'ordre dans lequel ces résultats sont renvoyés peut aider à identifier les relations parent / enfant. (Ceci n'est pas documenté et n'est donc qu'une supposition; utilisez CM_Get_Parent (ou Child + Sibling ) de l'API SetupDi pour des résultats définitifs.) En tant qu'option de l'API SetupDi, il semble que pour tous les périphériques répertoriés sous Win32_USBHubils peuvent être recherchés dans le registre (at HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\ + PNPDeviceID) et aura un paramètre ParentIdPrefixqui sera le préfixe du dernier champ dans le PNPDeviceID de ses enfants, donc cela pourrait également être utilisé dans une correspondance générique pour filtrer la Win32_PnPEntityrequête.

Dans ma candidature, j'ai fait ce qui suit:

  • (Facultatif) Interrogé Win32_PnPEntityet stocké les résultats dans une mappe clé-valeur (avec PNPDeviceID comme clé) pour une récupération ultérieure. Ceci est facultatif si vous souhaitez effectuer des requêtes individuelles ultérieurement.
  • Interrogé Win32_USBControllerDevicepour une liste définitive des périphériques USB sur mon système (toutes les personnes à charge) et extrait les PNPDeviceID de ceux-ci. Je suis allé plus loin, en fonction de l'ordre suivant l'arborescence des périphériques, pour attribuer des périphériques au hub racine (le premier périphérique est retourné, plutôt que le contrôleur) et j'ai construit une arborescence basée sur le parentIdPrefix. L'ordre renvoyé par la requête, qui correspond à l'énumération de l'arborescence des périphériques via SetupDi, correspond à chaque hub racine (pour lequel l'Antecedent identifie le contrôleur), suivi d'une itération des périphériques sous celui-ci, par exemple sur mon système:
    • Hub racine du premier contrôleur
    • Hub racine du deuxième contrôleur
      • Premier hub sous le hub racine du deuxième contrôleur (a parentIdPrefix)
        • Premier périphérique composite sous le premier concentrateur sous le concentrateur racine du deuxième contrôleur (PNPDeviceID correspond au-dessus du ParentIdPrefix du concentrateur; a son propre ParentIdPrefix)
          • Appareil HID faisant partie du périphérique composite (PNPDeviceID correspond au-dessus du ParentIDPrefix du périphérique composite)
        • Deuxième appareil sous le premier concentrateur sous le concentrateur racine du deuxième contrôleur
          • Appareil HID faisant partie de l'appareil composite
      • Deuxième hub sous le hub racine du second contrôleur
        • Premier appareil sous le deuxième concentrateur sous le concentrateur racine du deuxième contrôleur
      • Troisième hub sous le hub racine du deuxième contrôleur
      • etc.
  • Interrogé Win32_USBController. Cela m'a donné les informations détaillées des PNPDeviceID de mes contrôleurs qui se trouvent en haut de l'arborescence des périphériques (qui étaient les antécédents de la requête précédente). Utilisation de l'arborescence dérivée à l'étape précédente, itérée de manière récursive sur ses enfants (les hubs racine) et leurs enfants (les autres hubs) et leurs enfants (appareils non hubs et appareils composites) et leurs enfants, etc.
    • Récupération des détails de chaque appareil dans mon arbre en référençant la carte stockée dans la première étape. (Facultativement, on peut sauter la première étape et interroger Win32_PnPEntityindividuellement en utilisant le PNPDeviceId pour obtenir les informations à cette étape; probablement un compromis CPU / mémoire déterminant quel ordre est le meilleur.)

En résumé, les personnes à Win32USBControllerDevicecharge sont une liste complète des périphériques USB sur un système (autres que les contrôleurs eux-mêmes, qui sont les antécédents dans cette même requête), et en croisant ces PNPDeviceIdpaires avec des informations du registre et des autres requêtes mentionnées, une image détaillée peut être construite.

Daniel Widdis
la source
Si l'on avait 4 scanners identiques connectés, comment distingueriez-vous lequel était lequel s'ils étaient utilisés à 4 opérations différentes, par exemple?
topshot
2
@topshot Le PNPDeviceID est unique tant qu'il est connecté. Il n'y aurait aucun moyen de savoir si vous en avez déconnecté un et connecté un deuxième identique plus tard. Cet ID est également référencé dans d'autres domaines pour identifier, espérons-le, quelle opération est utilisée.
Daniel Widdis du
3
Si les appareils avaient des numéros de série intégrés, les appareils pourraient être différenciés (c'est le but des numéros de série). Le numéro de série est utilisé comme "ID d'instance" PnP. Si l'appareil ne contient pas de numéro de série, l'ID d'instance est essentiellement le chemin à travers l'arborescence des appareils de la racine à l'appareil (et contient les caractères «&»)
Brian
En tant que solution de secours, il y a toujours l'observation de la liste des appareils et le débranchement et le rebranchement tout en surveillant les changements.
Technophile
14

Pour voir les appareils qui m'intéressaient, j'avais remplacé Win32_USBHubpar Win32_PnPEntitydans le code d'Adel Hazzah, basé sur ce post . Cela fonctionne pour moi:

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; }
  }
}
ocroquette
la source
Cela a très bien fonctionné. Pour faciliter la détermination du périphérique que vous venez de brancher, écrivez-le pour qu'il s'exécute à intervalles réguliers, écrivez les entrées dans un dictionnaire et signalez tout ajout depuis la dernière fois que vous l'avez exécuté.
nixkuroi
7

La réponse d' Adel Hazzah donne un code de travail, les commentaires de Daniel Widdis et Nedko mentionnent que vous devez interroger Win32_USBControllerDevice et utiliser sa propriété Dependent, et la réponse de Daniel donne beaucoup de détails sans code.

Voici une synthèse de la discussion ci-dessus pour fournir un code de travail qui répertorie les propriétés de périphérique PNP directement accessibles de tous les périphériques USB connectés:

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

    }

}

Vous devrez ajouter la gestion des exceptions si vous le souhaitez. Consultez la réponse de Daniel si vous voulez comprendre l'arborescence des appareils et autres.

Tydaeus
la source
5

Il s'agit d'un exemple beaucoup plus simple pour les personnes qui recherchent uniquement des lecteurs USB amovibles.

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
la source
2
Renvoie également une disquette, probablement des lecteurs de cartes USB, des lecteurs Zip, Jazz et Orb possibles
Mad Myche
C'est la solution idéale pour les personnes souhaitant simplement faire correspondre le nom convivial d'une clé USB. J'utilise cet exemple pour la sauvegarde des données et comme la lettre du lecteur change, je dois rechercher le nom (ici drive.VolumeLabel)
Bio42
3

Si vous modifiez ManagementObjectSearcher comme suit:

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

Donc, le "GetUSBDevices () ressemble à ceci"

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

}

Vos résultats seront limités aux périphériques USB (par opposition à tous les types sur votre système)

Russell Gantman
la source
1
La clause where recherchant les DeviceID commençant par USB manque certains éléments. Il est préférable d'itérer les personnes à charge de "Win32_USBControllerDevice"
Daniel Widdis
2

Vous pouvez trouver ce fil utile. Et voici un projet de code google illustrant cela (il P / Invokes setupapi.dll).

Darin Dimitrov
la source
Avez-vous une idée de la raison pour laquelle la classe ObjectQuery n'a pas de référence même si j'utilise System.Management?
Robert
@Robert avez-vous ajouté la référence au projet? Vous pouvez le faire en cliquant avec le bouton droit sur Références dans votre projet> Ajouter une référence ...> Rechercher et vérifier System.Management> OK.
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
la source
qu'est-ce que object valueça fait?
newbieguy
Faites un tour des autres propriétés disponibles sur le disque et enregistrez sa valeur dans la valeur d'objet
JxDarkAngel