How Can I Determine When a Removable Drive Gets Connected?
Hey, Scripting Guy! How can I determine when a USB flash drive gets connected?
Hey, PS. OK, we admit it: the Scripting Guys are lazy. (Especially on a Friday, which is the day when we have to write our Monday column.) There might be a way to monitor specifically for the insertion of a USB flash drive; however, we couldn’t find one, at least not right away. Admittedly, we probably could have looked a bit harder; however, we decided instead to write a script that tells you when any removable drive gets connected (or disconnected) from a machine. We like to think that this way we’re providing you with additional value and flexibility.
Hey, we didn’t say we really were providing you with additional value and flexibility. We just like to think that we are.
Actually, this is kind of a handy little script. And it has the added benefit of running on any version of Windows. (Originally we toyed with the notion of using the Win32_VolumeChangeEvent class to accomplish this task, but that particular WMI class is found only on Windows XP or greater.)
Here’s what the code looks like:
strComputer = “.” Set objWMIService = GetObject(“winmgmts:\\” & strComputer & “\root\cimv2”)
Set colEvents = objWMIService.ExecNotificationQuery _ (“Select * From __InstanceOperationEvent Within 10 Where ” _ & “TargetInstance isa ‘Win32_LogicalDisk'”)
Do While True Set objEvent = colEvents.NextEvent If objEvent.TargetInstance.DriveType = 2 Then Select Case objEvent.Path_.Class Case “__InstanceCreationEvent” Wscript.Echo “Drive ” & objEvent.TargetInstance.DeviceId & _ ” has been added.” Case “__InstanceDeletionEvent” Wscript.Echo “Drive ” & objEvent.TargetInstance.DeviceId & _ ” has been removed.” End Select End If Loop
And yes, this is similar to the screensaver monitoring script we showed you the other day. We like to think that reusing the same script day-after-day provides you with additional value and flexibility. (Although mostly it just ensures that we don’t have to work very hard.)
This script starts off by connecting to the WMI service on the local computer. We then issue this query:
Set colEvents = objWMIService.ExecNotificationQuery _ (“Select * From __InstanceOperationEvent Within 10 Where ” _ & “TargetInstance ISA ‘Win32_LogicalDisk'”)
What’s going on here? Well, here we’re using the ExecNotificationQuery method to subscribe to a particular set of WMI events. What WMI events? (Boy, you have a lot of questions, don’t you?) In this case we want to be notified any time changes are made to an instance of the Win32_LogicalDisk class; as you’ll see momentarily, those changes will include creating a new instance of the class (i.e., adding a removable drive) and deleting an existing instance of the class (i.e., removing a removable drive). The Within 10 simply means we’re going to check every 10 seconds to see whether any of the Win32_LogicalDisk instances have changed.
And yes, that means if you insert a removable drive and then remove it 6 seconds later we might never know about it. If that’s a problem, then change 10 to a smaller number. You can also change 10 to a higher number. For example, change 10 to 60 and your check will occur every 60 seconds rather than every 10 seconds.
See? We even built added value and flexibility into the code itself!
After that we set up one of those crazy Do loops designed to run forever:
Do While True
And then we encounter this line of code:
Set objEvent = colEvents.NextEvent
As we noted in the previous column, this line of code causes the script to “block;” that simply means the script will pause on this line until there’s a change to the Win32_LogicalDisk class. That change (which could be the creation of a new instance or the deletion/modification of an existing instance) will then cause the script to execute the remaining lines of code in the Do loop.
Good question: what exactly do those remaining lines of code do? Well, first we check to see if the drive that generated the event happens to be a removable drive (a DriveType of 2 as far as WMI is concerned):
If objEvent.TargetInstance.DriveType = 2 Then
If the DriveType is not 2, then we just loop around and wait for the next event to occur. If the DriveType is 2 then we use a Select Case block to determine which type of event occurred. We can do that by determining the Class of the event:
Select Case objEvent.Path_.Class
Why do we do that? Two reasons: First, we aren’t interested in any changes to existing instances. For example, we don’t care if the amount of free drive space has changed on drive C. If you look at the Select Case code you’ll notice we don’t bother checking for the __InstanceModificationEvent. Why not? Because we don’t care about the __InstanceModificationEvent (the event type generated when an existing instance is modified in some way).
Second, we want to draw a distinction between the __InstanceCreationEvent (which tells us a new drive has been created) and the __InstanceDeletionEvent (which tells us an existing drive has been deleted). By identifying the event type we can echo back a different (and appropriate) message. For example, here’s the code that determines whether a new drive was created and, if so, echoes back a message to that effect:
Case “__InstanceCreationEvent” Wscript.Echo “Drive ” & objEvent.TargetInstance.DeviceId & _ ” has been added.”
And here’s the code that tells us whether an existing drive has been deleted:
Case “__InstanceDeletionEvent” Wscript.Echo “Drive ” & objEvent.TargetInstance.DeviceId & _ ” has been removed.”
Once we’ve echoed the appropriate message we loop around and wait for the next event to occur. By default the script will run forever, or at least until you terminate the script process. Whichever comes first.
Like we said, it’s not exactly what you asked for, but it should do the job. Oh, and don’t forget the additional value and flexibility. That should more than make up for the fact that we didn’t really answer your question. (We like to think we answered a question. Just not your question.)