How Can I Determine Which USB Devices are Connected to a Computer?
Hey, Scripting Guy! How can I determine which USB devices are connected to a computer?
Hey, WM. If you watch a lot of TV – um, not that the Scripting Guys do; we spend our spare time reading the works of Shakespeare, solving differential equations, and otherwise tending to our many intellectual pursuits. As we’ve been told, however, any time there’s a major crisis on a TV show one of the main characters grabs a bullhorn and tries to calm the crowd. “Stay calm!” he or she tells everyone. “There’s no reason to be alarmed. Everything’s going to be just fine.”
There are times when we Scripting Guys wish we had a bullhorn, and this is one of them. Can you determine which USB devices are connected to a computer? Yes, although you might start to panic a bit when you see how you have to do this. Stay calm. There’s no reason to be alarmed.
You’re right: we should have our own TV show, shouldn’t we?
The problem we have here is that there isn’t a Dynamic class devoted to USB devices: you can’t return a collection of USB devices the same way you can use Win32_Services to return a collection of all the services on a computer. Instead, you have to use a WMI Association class (Win32_USBControllerDevice) that associates a USB controller with a USB device. With that information you can identify the dependent entity in the association (which happens to be the device associated with a USB controller) and can then query the Win32_PNPEntity to get information about the device itself. (Unfortunately, Win32_USBControllerDevice returns nothing about the device except the somewhat-cryptic device ID.)
Confused? Don’t feel bad; we’re not 100% sure we understand it. So let’s make a deal: why don’t we show you the script, and then you can decide for yourself if you want to tackle the explanation of how the script works:
strComputer = “.”
Set objWMIService = GetObject(“winmgmts:\\” & strComputer & “\root\cimv2”) Set colDevices = objWMIService.ExecQuery _ (“Select * From Win32_USBControllerDevice”)
For Each objDevice in colDevices strDeviceName = objDevice.Dependent strQuotes = Chr(34) strDeviceName = Replace(strDeviceName, strQuotes, “”) arrDeviceNames = Split(strDeviceName, “=”) strDeviceName = arrDeviceNames(1) Set colUSBDevices = objWMIService.ExecQuery _ (“Select * From Win32_PnPEntity Where DeviceID = ‘” & strDeviceName & “‘”) For Each objUSBDevice in colUSBDevices Wscript.Echo objUSBDevice.Description Next Next
Oh, good: you’re still with us. As you can see, the script starts off by querying the Win32_USBControllerDevice; this returns a collection of all the USB controllers and the devices currently associated with them. That’s the good news. The bad news is this: we need to isolate the dependent entity for each item in the collection, an entity that represents a USB device. Why is that bad news? Well, it’s bad news because the Dependent property value is going to look something like this:
Yuck. What we need to do is somehow isolate the actual device ID; in this case, USB\\VID_045E&PID_0029\\5&236EE205&0&2. When we have that value, we can then query the Win32_PNPEntity class for information about the device.
So how do we isolate the device ID? Well, there are probably a million different ways to do this; we chose one we thought was reasonably easy to follow. (Which ought to give you some indication of what the other methods were like.)
We begin by storing the value of the Dependent property in a variable named strDeviceName. We then use the VBScript Replace function to remove the double quotes – which we indicate by using Chr(34) – from the string. That leaves us with a value that looks like this:
Believe it or not, removing those double quotes puts us on the home stretch. If you examine the remaining value closely, you’ll notice that it’s basically divided into two parts, with the two parts separated by an equal sign. On the left of the equal sign we have the WMI path to the class and property; on the right of the equal sign we have the device ID. Why does that matter to us? Because now we can use the VBScript Split function to split the value on the equal sign, and create an array consisting of two items. Item 1 will be the WMI path, and item 2 will be – bingo! – the device ID. These two lines of code create the array, and then assign the value of item 2 in our array (the device ID) to the variable strDeviceName:
arrDeviceNames = Split(strDeviceName, “=”) strDeviceName = arrDeviceNames(1)
We now have the device ID for the first USB device connected to the computer. With the device ID in hand we can query the Win32_PNPEntity class for information about the USB device that’s been assigned that device ID. That’s what we do here:
Set colUSBDevices = objWMIService.ExecQuery _ (“Select * From Win32_PnPEntity Where DeviceID = ‘” & strDeviceName & “‘”)
This query will return information about the actual device itself. In this script we do nothing more than echo back the value of the Description property for each device, although we could just as easily echo back values for any of the properties found in the Win32_PNPEntity class. We then loop around and repeat this process for each item in the Win32_USBControllerDevice collection.
When we run the script we’ll get back information similar to this (depending, of course, on the devices currently connected to the computer):
USB Root Hub Microsoft USB IntelliMouse Web Microsoft USB IntelliMouse Web USB Mass Storage Device Disk drive Generic volume USB Root Hub USB Root Hub
It’s not perfect; USB Mass Storage Device, Disk drive, and Generic volume all refer to the same USB keychain drive. But at least it gives you some idea of what devices are (or are not) attached to a computer.
Just like we said: No reason to be alarmed. Everything is just fine.