USB Device Managment
-
USB Devices on Windows can be tricky, while generally you'll think they are plug-and-play compatible (and this is true in many cases), not every use case ensures that a USB device is ready to be removed or ejected. Hopefully this chapter will assist with remediating some false alerts that can occur from people simply pulling a USB device from a system, namely USB Storage Devices.
While Windows is generally good about avoiding corrupted file systems on USB Devices, the management and monitoring tools used have limited capacity to differentiate between a "real" issue on a system drive, or a false alert on a USB drive.
While the bulk of this chapter is going to be about disabling or enabling USB Drives programmatically, this same process can be used for any device on any Windows System with a little effort.
As outlined in this chapter's header we will outline how to identify a USB Device programmatically. In the examples below we'll be using USB Storage devices (thumbdrives); two actually to demonstrate what is occurring.
To start we need to know what devices we're working with and their InstanceID, this can be performed through Device Manager (devmgmt.msc) or through PowerShell, or Windows Explorer.
Since I like to do things that are easily repeatable (on a schedule through PowerShell or command line script) I'll be doing this with an Administrative PowerShell Session.
Get-PnpDevice -class 'USB' -FriendlyName 'USB Mass Storage Device' -Status OK | ft InstanceID,Status,Class,FriendlyName | Out-String -Width 160
Now what does the above do? It searches through all devices attached to the current system and filters based on the device class 'USB', the FriendlyName 'USB Mass Storage Device' and the Status of 'OK'. It then filters out just those details and expands the out-string to 160 characters so the information isn't truncated.
If you wish to play with the settings of this, by all means go ahead and remove | ft InstanceID | or change the Out-String line or completely remove the | out-string -Width 160 section and see how the output changes; or any other option within the pipes.
Continuing with the command from the above, in this example it shows InstanceID, Status, Class and FriendlyName of 2 USB Drives.
InstanceId Status Class FriendlyName ---------- ------ ----- ------------ USB\VID_1B1C&PID_1A06\AA1TD4DI0B5WBKJG OK USB USB Mass Storage Device USB\VID_154B&PID_00AD\AA520F2080000086 OK USB USB Mass Storage Device
With the above details we can tell that we have 2 USB Mass Storage Devices connected to this system, and what their unique InstanceID's are, that they are "OK" - means online and usable etc.
From here we can verify this information from within Device Manager (devmgmt.msc) or by launching My Computer, finding the external USB devices listed, right clicking one, Properties, Hardware Tab, Properties, Details and lastly going to "Last Known Parent".
Here we've confirmed that "Drive-2 (G:)" is in fact the second drive from PowerShell above but through the GUI.
USB\VID_154B&PID_00AD\AA520F2080000086 OK USB USB Mass Storage Device
Since we're using Device Manager (from powershell) the Property name is different when compared to "My Computer" and uses the Device instance path. This is likely due to poor Microsoft programmers not being on the same page, but that is neither here nor there... continuing onwards....
If you know the device manufacturer you can further verify this by looking at the Bus Relations property and see what manufacturer is listed. The "Manufacturer" property is often a generic label such as "Compatible USB storage device" and can be reviewed, but shouldn't be relied on.
Since we know this is the device that we want to disable, we can now proceed to disable the device in preparation of removal.
-
Changing a USB Device's Status
Continuing onward from the previous page, we'll now continue to manipulate this USB Drive, in particular we're going to disable the device so it can be unplugged without risking possible disk corruption.
There are actually a few ways to do this, but for reasons this approach is being used. At the end of this page will be an Alternative Approach to "Properly Eject" a USB Drive with some explanations as to why it's not the approach we're using here.
Disabling a device with PowerShell is actually very simple once you know what the InstanceID is, we'll be using the Disable-PnPDevice cmdlet, the InstanceID and an Automatic flag so we aren't prompted for confirmation (so this can be scripted).
This must be run from an Administrative PowerShell Session.
Text in iTALICS is variable based on your device(s) and needs to be adjusted to match your scenario.
Disable-PnPDevice -InstanceID '*USB\VID_154B&PID_00AD\AA520F2080000086*' -A;
Our "G:" Drive USB Storage will be disabled from Device Manager so it can be removed without risking anything still being read or written to it.
Enabling your USB Drive with PowerShell
Conversely, enabling the device is just as simple by changing Disable-PnPDevice to Enable-PnPDevice...Enable-PnPDevice -InstanceID '*USB\VID_154B&PID_00AD\AA520F2080000086*' -A;
Use Cases of the Above
The above operations are incredibly useful when you have to rotate USB drives or devices on a schedule, but often times have persons who aren't always able to swap the device or don't have access to log into the system in question and can't safely "Eject".What this does is disable the USB Device (USB Drive in our case) so all read/write operations are stopped, allows the device to be enabled without needing someone to physically reconnect the USB drive by removing and plugging it in again and ensure that no "Disk corruption" errors occur because the device use has been halted.
The above approach fixes the issue of needing to provide someone access to your server console to simply swap a USB drive, as well as allows you to ensure that a USB Drive is enabled and functional to ensure backups can continue.
The Alternative Approach...
This approach is a bit more unforgiving, in that the drive will be ejected with the "Safe to remove" notification which is wonderful, but this approach has ramifications that require remote hands to resolve - namely if no one actually swaps the drive..
$driveEject = New-Object -comObject Shell.Application $driveEject.Namespace(17).ParseName("E:").InvokeVerb("Eject")
So what does the above do? It will properly eject the USB Drive which has the Volume letter of "E:" which then will allow the disk to be removed from the system without having to work with Device Manager.
What doesn't this do?
Once a USB drive is ejected either with the above or "Right-click Eject", the only way to connect the device to the system again is to physically pull the device and plug it back in. I've yet to find a way to replicate the connection process that occurs automatically when a USB Drive is connected to a system.
So the alternative approach here should be used with caution as you'll need someone to physically reconnect the drive if its ejected, but not replaced.
-
Scenario and Solution
Combining what we've learned in this chapter we can safely disable a USB Disk Drive, and enable the same drive later on.
Scenario: A drive needs to be swapped for weekly rotation, the customer has four USB drives; Week 1, Week 2, Week 3 and Week 4. Susan the receptionist forgot to swap the drive on Friday at 5PM before leaving for the day; or she doesn't have access to the server to login and eject the disk drive. You need to ensure the drive is cleanly "removed" from the system and second that a drive is available prior to the start of the next backup.
Solution: Create two Scheduled Tasks which run individual PowerShell scripts, one to disable the USB Drive(s) and another to enable the USB Drive(s).
The reasoning behind disabling the drive is to ensure that all data operations are stopped before the device is pulled, preventing potential disk corruption issues.
The reasoning behind enabling the drive is to ensure that if Susan forgets to swap the drive, the device will be enabled and backups won't fail.
Put it all together. . . .
# This will disable these specific USB Device IDs # We're assuming we don't know what device will be attached at any give point so we "disable" all possibilities Disable-PnPDevice -InstanceID 'USB\VID_1B1C&PID_1A06\AA1TD4DI0B5WBKJG' -A; Disable-PnPDevice -InstanceID 'USB\VID_154B&PID_00AD\AA520F2080000086' -A;
In another PowerShell script we enable the same USB devices.
# This will enable these specific USB Device IDs # We're assuming we don't know what device will be attached at any give point so we "enable" all possibilities Enable-PnPDevice -InstanceID 'USB\VID_1B1C&PID_1A06\AA1TD4DI0B5WBKJG' -A; Enable-PnPDevice -InstanceID 'USB\VID_154B&PID_00AD\AA520F2080000086' -A;
What happens if a device is actually swapped, nothing as the device InstanceID are disabled. So it's critical that the devices be enabled prior to the start of the next backup.
Demo this by disabling any USB drive on your computer, and removing it and replugging it with devmgmt.msc open. The device will remain disabled until you enable it.
The above can then be scheduled to run from Task Scheduler to first, disable any devices after backups should be complete, and secondly, enable any devices after a swap should have occurred.
Challenges: The biggest challenge here is knowing or gathering the InstanceID's of each drive that may be a part of such a rotation, the second challenge is making sure that Susan doesn't swap the drives Earlier or Later than the schedule allows.
Early and the device isn't disabled (possibly causing false alerts), Late and a backup may be running (causing backup failures).
While this doesn't resolve every scenario, it covers many of the cases that can occur and cause possible headaches.
Again it's critical we enable all previously disabled devices as these changes disable automatic mounting
-
-
@irj just reserving the space
-
Not that it’s really all that important - it’s a comment.
“Denable”
-
@gjacobse I was wondering what denable was lol... good eye.
Corrected it
-
@dustinb3403 We have a big problem in this scenario.
On windows server 2012 it doesn't work, what can I do?
-
@zsvendo said in USB Device Managment:
@dustinb3403 We have a big problem in this scenario.
On windows server 2012 it doesn't work, what can I do?
Which part doesn't work? Also if you're not running at least 2012 R2 I don't want to help.
-
@dustinb3403 Windows server 2012 R2 does not have the PnPDevice is a module, so it doesn't work
-
@zsvendo said in USB Device Managment:
@dustinb3403 Windows server 2012 R2 does not have the PnPDevice is a module, so it doesn't work
Okay, so your powershell version needs to be updated, can you run
(Get-Host).Version
to update you'll likely need to update .net as well. -
@dustinb3403 It's not powershell but modules.
I've upgraded to 5.1 but this PnpDevie module option doesn't have for 2012 R2 -
@zsvendo said in USB Device Managment:
@dustinb3403 It's not powershell but modules.
I've upgraded to 5.1 but this PnpDevie module option doesn't have for 2012 R2If 2012 r2 doesn't include it you'll need to use the WMI version.
I don't have the exact process off hand but will take a look.
-
@zsvendo Try the below and adjust the above to work for your environment.
Get-WMIObject -Class Win32_PnPEntity | where {$_.Name -Like "USB*"} | Ft Name, Description, Manufacturer, DeviceID
Should do what's needed based on my testing, granted Windows 10 but this is the legacy approach.
Edited the command to include the DeviceID (not screenshotted) but should work
-
@dustinb3403 This command you sent me worked, I just need to see how to disable USB, you know?
-
@zsvendo said in USB Device Managment:
@dustinb3403 This command you sent me worked, I just need to see how to disable USB, you know?
I don't off hand, its one of the reasons I didn't want to support an older OS. I did have this process sorted out previously as I came across the same issue but scrapped the documentation since it was decided that "it wasn't worth bothering"
-
@dustinb3403 because the servers are licensed I can't change it to a more current one.
But PnpDevice is the best -
@dustinb3403 I even managed to make devcon.exe disable USB
but I wanted with this command you sent