How Can I Determine When a Removable Drive Gets Connected?

How Can I Determine When a Removable Drive Gets Connected?

  • Comments 3
  • Likes
Hey, Scripting Guy! Question

Hey, Scripting Guy! How can I determine when a USB flash drive gets connected?

-- PS

SpacerHey, Scripting Guy! AnswerScript Center

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.)

Your comment has been posted.   Close
Thank you, your comment requires moderation so it may take a while to appear.   Close
Leave a Comment
  • very nice ,thanks

    ineed help with this script( ps script)

    it work perfectly with win 7

    but i need it with win xp

    the script:

    *******************

    #Requires -version 2.0

    set-executionpolicy remotesigned

    Register-WmiEvent -Class win32_VolumeChangeEvent -SourceIdentifier volumeChange

    write-host (get-date -format s) " Beginning script..."

    do{

    $newEvent = Wait-Event -SourceIdentifier volumeChange

    $eventType = $newEvent.SourceEventArgs.NewEvent.EventType

    $eventTypeName = switch($eventType)

    {

    1 {"Configuration changed"}

    2 {"Device arrival"}

    3 {"Device removal"}

    4 {"docking"}

    }

    write-host (get-date -format s) " Event detected = " $eventTypeName

    if ($eventType -eq 2)

    {

    $driveLetter = $newEvent.SourceEventArgs.NewEvent.DriveName

    $driveLabel = ([wmi]"Win32_LogicalDisk='$driveLetter'").VolumeName

    write-host (get-date -format s) " Drive name = " $driveLetter

    write-host (get-date -format s) " Drive label = " $driveLabel

    # Execute process if drive matches specified condition(s)

    if ($driveLetter -eq 'H:')

    {

    write-host (get-date -format s) " Starting task in 3 seconds..."

    start-sleep -seconds 3

    start-process "c:\windows\system32\launch.bat"

    }

    }

    Remove-Event -SourceIdentifier volumeChange

    } while (1-eq1) #Loop until next event

    Unregister-Event -SourceIdentifier volumeChange

    **********************************

    this scrip doing :

    auto detect any removable disk or flash memory

    then check that drive letter

    then check if that drive letter matched thgat letter whom i but it

    if that it run bat file

    then close

    plz help me or make new script to do same task on win xp

    thanks v.much

  • Instead of window appearing how can I have this script write and event entry in windows event log?

  • @Cavrel you can certainly write to the event log. There are two ways in VBScript to do this, one is to use the event provider from WMI, but it is a bit cumbersome. The easy way is to use the logevent method from the wshshell object. There are several articles that talk about this on the Hey Scripting Guy blog.