Uzyskaj listę podłączonych urządzeń USB

93

Jak mogę uzyskać listę wszystkich podłączonych urządzeń USB na komputerze z systemem Windows?

Robert
źródło

Odpowiedzi:

122

Dodaj odniesienie do System.Management dla swojego projektu, a następnie spróbuj czegoś takiego:

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
źródło
14
Czy istnieje sposób na odzyskanie przyjaznej nazwy urządzenia? Na przykład, gdy przeglądam właściwości mojej pamięci USB, widzę „Urządzenie USB Kingston DataTraveler 2.0”.
Robert
2
Jaka jest różnica między DeviceID i PNPDeviceID?
Shimmy Weitzhandler
1
Po uruchomieniu powyższego programu otrzymuję dyski twarde USB, klawiaturę i mysz, ale nie mam kamery USB ani USB A / D. Dlaczego nie pojawiają się wszystkie moje urządzenia USB?
Curt,
8
należy zapytać „Win32_USBControllerDevice”, a nie „Win32_USBHub”, aby otrzymać listę wszystkich urządzeń USB. Następnie użyj właściwości „Dependent”, aby uzyskać ciąg adresu urządzenia.
Nedko
1
@ppumkin Win32_USBHubzawiera tylko koncentratory USB, a nie wszystkie urządzenia, więc brakuje niektórych urządzeń. @nedko ma rację, ponieważ Win32_USBControllerDeviceaby pobrać wszystkie urządzenia , musisz pobrać właściwość Dependent .
Daniel Widdis,
45

Wiem, że odpowiadam na stare pytanie, ale właśnie przeszedłem przez to samo ćwiczenie i znalazłem trochę więcej informacji, które moim zdaniem wniosą dużo do dyskusji i pomogą każdemu, kto znajdzie to pytanie i zobaczy, gdzie istniejące odpowiedzi są niewystarczające.

Odpowiedź akceptowana jest blisko i można skorygować za pomocą komentarz Nedko jest do niego. Bardziej szczegółowe zrozumienie zaangażowanych klas WMI pomoże uzupełnić obraz.

Win32_USBHubzwraca tylko koncentratory USB . Z perspektywy czasu wydaje się to oczywiste, ale w powyższej dyskusji tego nie ma. Nie obejmuje wszystkich możliwych urządzeń USB, a jedynie te, które mogą (przynajmniej w teorii) pełnić rolę koncentratora dla dodatkowych urządzeń. Pomija niektóre urządzenia, które nie są koncentratorami (szczególnie części urządzeń kompozytowych).

Win32_PnPEntityobejmuje wszystkie urządzenia USB i setki innych urządzeń innych niż USB. Porada Russela Gantmana dotycząca używania klauzuli WHERE do wyszukiwania Win32_PnPEntityidentyfikatora urządzenia zaczynającego się od „USB%” do filtrowania listy jest pomocna, ale nieco niepełna; pomija urządzenia Bluetooth, niektóre drukarki / serwery druku oraz myszy i klawiatury zgodne z HID. Widziałem „USB \%”, „USBSTOR \%”, „USBPRINT \%”, „BTH \%”, „SWD \%” i „HID \%”. Win32_PnPEntityjest jednak dobrym "głównym" odniesieniem do wyszukiwania informacji, gdy już jesteś w posiadaniu PNPDeviceID z innych źródeł.

To, co znalazłem, było najlepszym sposobem wyliczenia urządzeń USB, było zapytanie Win32_USBControllerDevice. Chociaż nie podaje szczegółowych informacji o urządzeniach, całkowicie wylicza urządzenia USB i podaje parę poprzedników / zależnych PNPDeviceIDdla każdego urządzenia USB (w tym koncentratorów, urządzeń innych niż koncentratory i urządzeń zgodnych z HID) na twoim system. Każdy element zależny zwrócony z zapytania będzie urządzeniem USB. Poprzednikiem będzie kontroler, do którego jest przypisany, jeden z kontrolerów USB zwróconych przez zapytanie Win32_USBController.

Jako bonus wydaje się, że pod maską WMI przechodzi po drzewie urządzeń podczas odpowiadania na Win32_USBControllerDevicezapytanie, więc kolejność, w jakiej te wyniki są zwracane, może pomóc w identyfikacji relacji rodzic / dziecko. (To nie jest udokumentowany, a zatem jest tylko przypuszczenie, korzystać z SetupDi API CM_Get_Parent (lub dziecko + Sibling .) Dla ostatecznych wyników) Jako opcja do SetupDi API, wydaje się, że na liście wszystkie urządzenia pod Win32_USBHubmogą być spojrzał w górę w rejestrze (at HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\ + PNPDeviceID) i będzie miał parametr, ParentIdPrefixktóry będzie prefiksem ostatniego pola w PNPDeviceID jego dzieci, więc można go również użyć w dopasowaniu wieloznacznym do filtrowania Win32_PnPEntityzapytania.

W swojej aplikacji wykonałem następujące czynności:

  • (Opcjonalnie) Win32_PnPEntityWyszukano i zapisano wyniki w mapie klucz-wartość (z PNPDeviceID jako kluczem) w celu późniejszego pobrania. Jest to opcjonalne, jeśli chcesz później wykonywać indywidualne zapytania.
  • Zapytałem Win32_USBControllerDeviceo ostateczną listę urządzeń USB w moim systemie (wszystkie zależne) i wyodrębniłem ich identyfikatory PNPDeviceID. Poszedłem dalej, w oparciu o kolejność podążającą za drzewem urządzeń, aby przypisać urządzenia do głównego koncentratora (pierwsze zwrócone urządzenie, a nie kontroler) i zbudowałem drzewo na podstawie parentIdPrefix. Kolejność zwracania zapytania, która odpowiada wyliczeniu drzewa urządzeń za pośrednictwem SetupDi, to każdy koncentrator główny (dla którego poprzednik identyfikuje kontroler), po którym następuje iteracja urządzeń pod nim, np. W moim systemie:
    • Główny koncentrator pierwszego kontrolera
    • Główny koncentrator drugiego kontrolera
      • Pierwszy koncentrator pod głównym koncentratorem drugiego kontrolera (ma parentIdPrefix)
        • Pierwsze urządzenie złożone w pierwszym koncentratorze pod głównym koncentratorem drugiego kontrolera (PNPDeviceID pasuje powyżej ParentIdPrefix koncentratora; ma własny ParentIdPrefix)
          • Część urządzenia HID urządzenia kompozytowego (identyfikator PNPDeviceID jest zgodny z ustawieniem ParentIDPrefix urządzenia kompozytowego)
        • Drugie urządzenie znajduje się pod pierwszym koncentratorem pod głównym koncentratorem drugiego kontrolera
          • Urządzenie HID Część urządzenia kompozytowego
      • Drugi koncentrator pod głównym koncentratorem drugiego kontrolera
        • Pierwsze urządzenie pod drugim koncentratorem pod głównym koncentratorem drugiego kontrolera
      • Trzeci koncentrator pod głównym koncentratorem drugiego kontrolera
      • itp.
  • Zapytany Win32_USBController. To dało mi szczegółowe informacje o identyfikatorach PNPDeviceID moich kontrolerów, które znajdują się na górze drzewa urządzeń (które były poprzednikami poprzedniego zapytania). Korzystając z drzewa uzyskanego w poprzednim kroku, rekurencyjnie iterowano po jego elementach podrzędnych (koncentratorach głównych) i ich elementach podrzędnych (inne koncentratory) oraz ich elementach podrzędnych (urządzenia inne niż koncentratory i urządzenia kompozytowe) oraz ich dzieci itp.
    • Pobrano szczegółowe informacje o każdym urządzeniu w moim drzewie, odwołując się do mapy przechowywanej w pierwszym kroku. (Opcjonalnie można pominąć pierwszy krok i zapytać Win32_PnPEntityindywidualnie, używając PNPDeviceId, aby uzyskać informacje na tym etapie; prawdopodobnie kompromis między procesorem a pamięcią określający, która kolejność jest lepsza).

Podsumowując, elementy Win32USBControllerDevicezależne to pełna lista urządzeń USB w systemie (innych niż same kontrolery, które są poprzednikami w tym samym zapytaniu) i poprzez porównanie tych PNPDeviceIdpar z informacjami z rejestru i innych wymienionych zapytań, można skonstruować szczegółowy obraz.

Daniel Widdis
źródło
Gdyby jeden miał podłączone 4 identyczne skanery, jak rozróżniłbyś, który byłby, gdyby był używany na przykład w 4 różnych operacjach?
widok z góry
2
@topshot Identyfikator PNPDeviceID jest unikalny, o ile jest połączony. Nie byłoby sposobu, aby stwierdzić, czy odłączyłeś jeden, a później podłączyłeś drugi, identyczny. Ten identyfikator jest również odsyłany w innych obszarach, aby miejmy nadzieję zidentyfikować, która operacja jest używana.
Daniel Widdis
3
Gdyby urządzenia miały wbudowane numery seryjne, można by je rozróżniać (taki jest cel numerów seryjnych). Numer seryjny jest używany jako „identyfikator instancji” PnP. Jeśli urządzenie nie zawiera numeru seryjnego, to identyfikator instancji jest zasadniczo ścieżką przez drzewo urządzeń od katalogu głównego do urządzenia (i zawiera znaki „&”)
Brian
W ramach rozwiązania awaryjnego zawsze obserwuje się listę urządzeń oraz odłącza i ponownie podłącza, obserwując zmiany.
Technophile
14

Aby zobaczyć interesujące mnie urządzenia, wymieniłem Win32_USBHubje Win32_PnPEntityw kodzie Adela Hazzaha na podstawie tego postu . To działa dla mnie:

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
źródło
To działało świetnie. Aby ułatwić określenie, które urządzenie właśnie podłączyłeś, zapisz je tak, aby działało z przerwami, zapisz wpisy do słownika i zgłoś wszelkie dodatki od ostatniego uruchomienia.
nixkuroi
8

Adel Hazzah za odpowiedź daje kod działa, Daniel Widdis użytkownika i Nedko za komentarze wspomnieć, że trzeba zapytać Win32_USBControllerDevice i używać podległych własności i Daniela odpowiedź daje wiele szczegółów bez kodu.

Oto synteza powyższej dyskusji, aby zapewnić działający kod, który zawiera listę bezpośrednio dostępnych właściwości urządzeń PNP wszystkich podłączonych urządzeń USB:

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

    }

}

Jeśli chcesz, musisz dodać obsługę wyjątków. Zapoznaj się z odpowiedzią Daniela, jeśli chcesz dowiedzieć się, jak wygląda drzewo urządzeń i tym podobne.

Tydaeus
źródło
5

To znacznie prostszy przykład dla osób poszukujących tylko wymiennych dysków USB.

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
źródło
2
Powróci dyskietkę, a także, prawdopodobnie czytniki kart USB możliwe Zip, Jazz, i napędy Orb
Mad Myche
To idealne rozwiązanie dla osób, które chcą po prostu dopasować przyjazną nazwę USB. Używam tego przykładu do tworzenia kopii zapasowych danych, a ponieważ zmienia się litera dysku, muszę poszukać nazwy (tutaj dysk.VolumeLabel)
Bio42
4

Jeśli zmienisz ManagementObjectSearcher na następujące:

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

Tak więc „GetUSBDevices () wygląda tak”

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

}

Twoje wyniki będą ograniczone do urządzeń USB (w przeciwieństwie do wszystkich typów w twoim systemie)

Russell Gantman
źródło
1
Klauzula Where wyszukująca identyfikatory urządzeń zaczynające się od USB pomija niektóre elementy. Lepiej jest iterować elementy zależne „Win32_USBControllerDevice”
Daniel Widdis,
2

Ten wątek może być przydatny. A oto projekt kodu google ilustrujący to (to P / wywołuje do setupapi.dll).

Darin Dimitrov
źródło
Czy masz pojęcie, dlaczego klasa ObjectQuery nie ma odwołania, mimo że używam System.Management?
Robert,
@Robert czy dodałeś referencję do projektu? Możesz to zrobić, klikając prawym przyciskiem myszy Referencje w swoim projekcie> Dodaj odniesienie ...> Wyszukaj i sprawdź 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
źródło
co to object valuerobi?
newbieguy
Zapoznaj się z innymi dostępnymi właściwościami na dysku i zapisz ich wartość w wartości obiektu
JxDarkAngel