Small app/script that will warn if an (external) drive is not connected


I found this one, which is more succinct:
The Windows 7 Event Log and USB Device Tracking
Nice find.
I'd still have the UI script enumerate a static table for the Device -> Drive / Volume Name mappings, so the executed task doesn't delay on startup querying this data. Especially if you had a USB hub failure, and like 6 devices got disconnected at once.
Static mappings might not be the best solution, as things like drive letters and volume names can tend to be somewhat ephemeric sometimes. By contrast, Device Instance ID and Parent ID for USBSTOR devices will typically remain invariable, which is why the modified Powershell script that I earlier posted relies on the InstanceID for each device to retrieve the Parent ID and display that as an additional column.
There's a trick which I've forgotten, where you write an extended Task XML so your event's data gets directly passed as a variable,
Here: Windows: Passing parameters to event triggered schedule tasks
and the script collapses to a simple table lookup. My current tradeoff is a background watcher saves on startup time, and is near instantaneous but I have to worry about duplicated processes. With a task trigger, I'd have to worry about keeping startup time low as possible.
One possible approach to avoid the relatively slow loading/running of a Powershell script is to let the task run wscript.exe in lieu of powershell.exe, and specify a VBScript with the added parameters to go from there, like, make it handle the entire action purely in VBScript code maybe. You could also decide to let your 'first-time initialization/configuration/setup' part of your script run the C# compiler that is part of the .NET Framework that, in turn, is part of Windows 11 by default. Here's an old example batchfile that I wrote to compile one of my simple C# programming experiments into an exe file that, once it has been successfully compiled, can be run by the scheduled task (or better yet... can be run by the VBScript wrapper that is run by this task, passing through the parameters).
Batch:
@ECHO OFF
FOR /F "tokens=* USEBACKQ" %%F IN (`REG QUERY "HKLM\SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full" /v InstallPath`) DO SET InstallPath=%%F
SET InstallPath=%InstallPath:*REG_SZ =%
FOR /F "tokens=* Eol= " %%F IN ("%InstallPath%") DO SET "InstallPath=%%F"
IF EXIST "%InstallPath%csc.exe" (ECHO ON) ELSE (ECHO ERROR - Missing csc.exe & GOTO end)
"%InstallPath%csc.exe" /out:"%~dp0\SnippingMax.exe" /target:winexe "%~dp0\SnippingMax.cs" /lib:%InstallPath%WPF /r:UIAutomationTypes.dll,UIAutomationClient.dll
:end
@ECHO Press any key to close this command window . . . & PAUSE >NUL
 

My Computers

System One System Two

  • OS
    11 Home
    Computer type
    Laptop
    Manufacturer/Model
    Asus TUF Gaming (2024)
    CPU
    i7 13650HX
    Memory
    16GB DDR5
    Graphics Card(s)
    GeForce RTX 4060 Mobile
    Sound Card
    Eastern Electric MiniMax DAC Supreme; Emotiva UMC-200; Astell & Kern AK240
    Monitor(s) Displays
    Sony Bravia XR-55X90J
    Screen Resolution
    3840×2160
    Hard Drives
    512GB SSD internal
    37TB external
    PSU
    Li-ion
    Cooling
    2× Arc Flow Fans, 4× exhaust vents, 5× heatpipes
    Keyboard
    Logitech K800
    Mouse
    Logitech G402
    Internet Speed
    20Mbit/s up, 250Mbit/s down
    Browser
    FF
  • Operating System
    11 Home
    Computer type
    Laptop
    Manufacturer/Model
    Medion S15450
    CPU
    i5 1135G7
    Memory
    16GB DDR4
    Graphics card(s)
    Intel Iris Xe
    Sound Card
    Eastern Electric MiniMax DAC Supreme; Emotiva UMC-200; Astell & Kern AK240
    Monitor(s) Displays
    Sony Bravia XR-55X90J
    Screen Resolution
    3840×2160
    Hard Drives
    2TB SSD internal
    37TB external
    PSU
    Li-ion
    Mouse
    Logitech G402
    Keyboard
    Logitech K800
    Internet Speed
    20Mbit/s up, 250Mbit/s down
    Browser
    FF
But you're missing the point... The PS session which invokes binary.exe, by itself triggers a screen flash. I don't care about hiding binary.exe.
the last comment i just posted is a command it doesn't produce any window with >nul at the end as shown, which the only reason I mention it. :wink: I figured you could use it since you're under the impression it wont work, this way will, no need to point task scheduler to a script

you are correct, and I mistaken
 

My Computer

System One

  • OS
    PE
Bob,

Yes, it's a difficult subject.
You play around in cmd / PS windows to get it behaving as you want but only to find that Task scheduler goes & displays a window anyway.


All the best,
Denis
 

My Computer

System One

  • OS
    Windows 11 Home x64 Version 23H2 Build 22631.3447
I followed @hdmi's directions, by switching from a Register-WMIEvent call to the scheduled task's event trigger. This lead to some good and bad points.

1. For USB removable drives, watching Microsoft-Windows-DriverFrameworks-UserMode/Operational, and Event ID 2100 & minor=23 is a reliable way to detect unplugged drives.

2. The most efficient way to pass the device identifier, is to write a scheduled task XML and export the @instance data field.
Code:
    <Triggers>
        <EventTrigger>
            <Enabled>true</Enabled>
            <Subscription>&lt;QueryList&gt;&lt;Query Id="0" Path="Microsoft-Windows-DriverFrameworks-UserMode/Operational"&gt;&lt;Select Path="Microsoft-Windows-DriverFrameworks-UserMode/Operational"&gt;*[System[Provider[@Name='Microsoft-Windows-DriverFrameworks-UserMode'] and EventID=2100]] and*[UserData[UMDFHostDeviceRequest[Request[@minor='23']]]]&lt;/Select&gt;&lt;/Query&gt;&lt;/QueryList&gt;</Subscription>
            <ValueQueries>
                <Value name="instance">Event/UserData/UMDFHostDeviceRequest/@instance</Value>
            </ValueQueries>
        </EventTrigger>
    </Triggers>

Now it can be passed to our VBS script.
Code:
    <Actions Context="Author">
        <Exec>
            <Command>wscript</Command>
            <Arguments>"C:\Users\GARLIN\AppData\Local\USB_Drive_Monitor_Task.vbs" "$(instance)"</Arguments>
        </Exec>
    </Actions>

3. The parent script continues to write a short VBS script, mostly to preserve the existing Drive & Volume Name mappings.
Code:
strDeviceID = WScript.Arguments.Item(0)

Select Case strDeviceID
    Case "WPDBUSENUMROOT\UMB\2&37C186B&0&STORAGE#VOLUME#_??_USBSTOR#DISK&VEN_CORSAIR&PROD_VOYAGER&REV_0.00#0000000000000000&0#"
        strMessage = "D: [CORSAIR] was disconnected. "
    Case Else
        WScript.Quit
End Select

CreateObject("WScript.Shell").Popup strMessage & now, 86400, "USB Drive Monitor"

This approach is cleaner in that Task Scheduler is responsible for watching new events, and no background task is required. But there's a HUGE problem. DriverFrameworks-UserMode facility is only good for USB removable drive events. This does nothing for non-removable USB HDD's. You could look under Microsoft-Windows-Kernel-PnP/Diagnostic, but Task Scheduler doesn't support triggers based on any diagnostic logs.

I feel that's an unacceptable loss of functionality from the original script. Register-WMIEvent gets me access to event data which is otherwise unavailable. In a practical sense, that's a major drawback. But here's the final script if anyone's interested in the coding.

1709701007343.png
 

Attachments

  • USB_Drive_Monitor_v2.bat
    11.4 KB · Views: 2

My Computer

System One

  • OS
    Windows 7
You could look under Microsoft-Windows-Kernel-PnP/Diagnostic, but Task Scheduler doesn't support triggers based on any diagnostic logs.
For me, it does. See my post #23, the example XPath event query I gave uses the diagnostic log Microsoft-Windows-Partition/Diagnostic. (I just verified that it works.) You just need to make sure to specify the Path attribute of the Select tag and also specify Provider Name in the XPath. Else, Task Scheduler rejects it with an error message dialog. (The Path attribute of the Query tag gets added automatically by Task Scheduler when it accepts your XML code.) You can also put multiple Select tags BTW.

<Query Id="0" Path="……">
<Select Path="……">…………</Select>
<Select Path="……">…………</Select>
</Query>
 

My Computers

System One System Two

  • OS
    11 Home
    Computer type
    Laptop
    Manufacturer/Model
    Asus TUF Gaming (2024)
    CPU
    i7 13650HX
    Memory
    16GB DDR5
    Graphics Card(s)
    GeForce RTX 4060 Mobile
    Sound Card
    Eastern Electric MiniMax DAC Supreme; Emotiva UMC-200; Astell & Kern AK240
    Monitor(s) Displays
    Sony Bravia XR-55X90J
    Screen Resolution
    3840×2160
    Hard Drives
    512GB SSD internal
    37TB external
    PSU
    Li-ion
    Cooling
    2× Arc Flow Fans, 4× exhaust vents, 5× heatpipes
    Keyboard
    Logitech K800
    Mouse
    Logitech G402
    Internet Speed
    20Mbit/s up, 250Mbit/s down
    Browser
    FF
  • Operating System
    11 Home
    Computer type
    Laptop
    Manufacturer/Model
    Medion S15450
    CPU
    i5 1135G7
    Memory
    16GB DDR4
    Graphics card(s)
    Intel Iris Xe
    Sound Card
    Eastern Electric MiniMax DAC Supreme; Emotiva UMC-200; Astell & Kern AK240
    Monitor(s) Displays
    Sony Bravia XR-55X90J
    Screen Resolution
    3840×2160
    Hard Drives
    2TB SSD internal
    37TB external
    PSU
    Li-ion
    Mouse
    Logitech G402
    Keyboard
    Logitech K800
    Internet Speed
    20Mbit/s up, 250Mbit/s down
    Browser
    FF
After a break, I had time to rewrite my previous script to look for Microsoft-Windows-Partition/Diagnostic Event 1006, whenever it reports a device's Capacity is equal to 0 bytes. This trigger works on all USB devices, including removable drives and normal HDD's.

The new script creates an Event-based scheduled task, and keeps running across reboots until the task is removed. Each notification popup is now clearly marked with an alert icon, and defaults to having input focus (not hidden by another window). The UI layout has been cleaned up to fit the display font. I've also included a touched up version of the older script (which used Register-WMI), in case anyone's interested in comparing the two notification models.

Both scripts work equally well, but USB_Drive_Monitor.bat is the preferred version.

I'm done, unless anyone reports a bug. Thanks to @hdmi for his help!
 

Attachments

  • USB_Drive_Monitor.bat
    11.5 KB · Views: 1
  • USB_Drive_Monitor_RegisterWMI.bat
    10.2 KB · Views: 1

My Computer

System One

  • OS
    Windows 7
Back
Top Bottom