Jump to content

[Need Help] Get PNP Device ID for USB Drive


Recommended Posts

I was looking at MadBoy's code and figured that it would take a long time to query a large number of drives. So I've modified MadBoy's code so that the PNP Device ID for all drives are returned in an array. Array returned is dimensioned as 3 slots (Drive Letter, PNP Device ID, Interface Type) per number of drives returned. Here's the code:

#include <Array.au3>
#include <String.au3>

$test = _DriveGetDeviceIDList()
_ArrayDisplay( $Test )

Func _DriveGetDeviceIDList( $strComputer = "." )
    local $Arr[27][3], $i = 1, $colItems, $j, $Antecedent, $Dependent
    const $wbemFlagReturnImmediately = 0x10, $wbemFlagForwardOnly = 0x20
    
 ; Get the disk/partition number for the logical drives attached to machine:
    $objWMIService = ObjGet("winmgmts:\\" & $strComputer & "\root\CIMV2")
    $colItems = $objWMIService.ExecQuery("SELECT * FROM Win32_LogicalDiskToPartition", "WQL", _
        $wbemFlagReturnImmediately + $wbemFlagForwardOnly)
    For $objItem In $colItems
        $Antecedent = _StringBetween($objItem.Antecedent, '"', '"')
        $Dependent = _StringBetween($objItem.Dependent, '"', '"')
        $Arr[$i][0] = $Dependent[0]
        $Arr[$i][1] = $Antecedent[0]
        $i = $i + 1
    Next
    ReDim $Arr[$i][3]
    $Arr[0][0] = $i - 1
    
 ; Associate physical drive with disk/partition number in array:
    $colItems = $objWMIService.ExecQuery("SELECT * FROM Win32_DiskDriveToDiskPartition", "WQL", _
        $wbemFlagReturnImmediately + $wbemFlagForwardOnly)
    For $objItem In $colItems
        $Antecedent = _StringBetween($objItem.Antecedent, '"', '"')
        $Dependent = _StringBetween($objItem.Dependent, '"', '"')
        $drive_physical = StringTrimLeft($Antecedent[0], StringInStr($Antecedent[0], "\", 1, -1))
        for $j = 1 to $i - 1
            If $Dependent[0] = $Arr[$j][1] then $Arr[$j][1] = $drive_physical
        next
    Next

 ; Associate PNP device ID with physical drives in array:
    $colItems = $objWMIService.ExecQuery("SELECT * FROM Win32_DiskDrive", "WQL", _
        $wbemFlagReturnImmediately + $wbemFlagForwardOnly)
    For $objItem In $colItems
        $DeviceID = StringTrimLeft($objItem.DeviceID, StringInStr($objItem.DeviceID, "\", 1, -1))
        for $j = 1 to $i - 1
            if $DeviceID = $Arr[$j][1] then 
                $Arr[$j][1] = $objItem.PNPDeviceID
                $Arr[$j][2] = $objItem.InterfaceType
            endif
        next
    Next
    return $Arr
EndFunc;==> _DriveGetDeviceIDList

The device differentation that I am doing can take place that the $Arr[$j][2] assignment statement.

Edited by Dougiefresh
Link to comment
Share on other sites

Ok, I was fiddling with the code, trying to get rid of the floppy drive grind everytime that the script is run. I replaced the first 5 (or so) lines of the above post with the following code:

Func _DriveGetDeviceIDList( $strComputer = "." )
    local $Arr[27][3], $i = 1, $colItems, $j, $Antecedent, $Dependent, $Filter = ""
    const $wbemFlagReturnImmediately = 0x10, $wbemFlagForwardOnly = 0x20
    const $DL = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
    
; Let's filter out the floppy drives first:
    for $j = 1 to 26
        $Drv = StringMid( $DL, $j, 1 ) & ":"
        if DriveGetType( $Drv ) <> "REMOVABLE" then ContinueLoop
        $usbdev = RegRead( "HKLM\SYSTEM\MountedDevices", "\DosDevices\" & $Drv )
        $usbdev = _HexToString( StringReplace( $usbdev, "00", "" ) )
        if StringInStr( $usbdev, "STORAGE#RemovableMedia" ) = 0 then _
            $Filter = $Filter & _IIf( $Filter = "", " WHERE ", " and " ) & "DeviceID <> '" & $Drv & "'"
    next
    
; Get the disk/partition number for the logical drives attached to machine:
    $objWMIService = ObjGet("winmgmts:\\" & $strComputer & "\root\CIMV2")
    $colItems = $objWMIService.ExecQuery("SELECT * FROM Win32_LogicalDiskToPartition" & $Filter, _
        "WQL", $wbemFlagReturnImmediately + $wbemFlagForwardOnly)
If I insert that code, nothing is returned in the array. I know that the non-USB floppy drive I have is properly detected as drive A: (haven't tested a USB drive). What am I doing wrong here? Edited by Dougiefresh
Link to comment
Share on other sites

Fiddled with the code some more and found a way to kill the second floppy grind. Here's the code:

Func _DriveGetDeviceIDList()
; Find floppy drives for the script:
;====================================================================================
    local $UsbDev, $Filt1 = "", $Filt2 = "", $Floppy = ""
    local $Drv = DriveGetDrive( "REMOVABLE" )
    if @error = 0 then
        for $j = 1 to $Drv[0]
            $usbdev = RegRead( $MOUNT, "\DosDevices\" & $Drv[ $j ] )
            $usbdev = _HexToString( StringReplace( $usbdev, "00", "" ) )
            if StringInStr( $usbdev, "STORAGE#RemovableMedia" ) = 0 then $Floppy = $Floppy & "|" & $Drv[ $j ]
        next
        if $Floppy <> "" Then
;Draft the $Filt1 variable here....
            $Filt2 = "WHERE " & StringReplace( $Floppy, "|", "' And DeviceID <> '" )
            $Filt2 = StringReplace( $Filt2, "WHERE ' And", "WHERE" ) & "'"
        Endif
    endif

; Get PNP Device IDs for all drives:
;====================================================================================
    global $PNP[27][3]
    local $i = 1, $colItems, $j, $Antecedent, $Dependent
    const $wbemFlagReturnImmediately = 0x10, $wbemFlagForwardOnly = 0x20, $strComputer = "."
    
; Get the disk/partition number for the logical drives attached to machine:
    $objWMIService = ObjGet("winmgmts:\\" & $strComputer & "\root\CIMV2")
    $colItems = $objWMIService.ExecQuery("SELECT * FROM Win32_LogicalDiskToPartition" & $Filt1, _
        "WQL", $wbemFlagReturnImmediately + $wbemFlagForwardOnly)
    For $objItem In $colItems
        $Antecedent = _StringBetween($objItem.Antecedent, '"', '"')
        $Dependent = _StringBetween($objItem.Dependent, '"', '"')
        $PNP[$i][0] = $Dependent[0]
        $PNP[$i][1] = $Antecedent[0]
        $i = $i + 1
    Next
    ReDim $PNP[$i][3]
    $PNP[0][0] = $i - 1
    
; Associate physical drive with disk/partition number in array:
    $colItems = $objWMIService.ExecQuery("SELECT * FROM Win32_DiskDriveToDiskPartition", "WQL", _
        $wbemFlagReturnImmediately + $wbemFlagForwardOnly)
    For $objItem In $colItems
        $Antecedent = _StringBetween($objItem.Antecedent, '"', '"')
        $Dependent = _StringBetween($objItem.Dependent, '"', '"')
        $drive_physical = StringTrimLeft($Antecedent[0], StringInStr($Antecedent[0], "\", 1, -1))
        for $j = 1 to $i - 1
            if $Dependent[0] = $PNP[$j][1] then $PNP[$j][1] = $drive_physical
        next
    Next

; Associate PNP device ID with physical drives in array:
    $colItems = $objWMIService.ExecQuery("SELECT * FROM Win32_DiskDrive " & $Filt2, "WQL", _
        $wbemFlagReturnImmediately + $wbemFlagForwardOnly)
    For $objItem In $colItems
        $DeviceID = StringTrimLeft($objItem.DeviceID, StringInStr($objItem.DeviceID, "\", 1, -1))
        for $j = 1 to $i - 1
            if $DeviceID = $PNP[$j][1] then 
                $PNP[$j][1] = $objItem.PNPDeviceID
                $PNP[$j][2] = $objItem.InterfaceType
            endif
        next
    Next
    return $PNP
EndFunc
I can't figure out how to draft the $FILT1 variable to get rid of 1st floppy grind.

EDIT: Oh, yeah. Here's how I can pull the PNP Device ID or Interface type for any drive from the array easily:

Func _GetPNP( $Drv, $Element = 1 )
    for $i = 1 to $PNP[0][0]
        if $Drv = $PNP[ $i ][0] then return $PNP[ $i ][ $Element ]
    Next
    return ""
EndFunc
By default, it returns the PNP Device ID. By specifying 2 for the element, it will return the interface type. If the drive doesn't exist in the array, it returns an empty string. Edited by Dougiefresh
Link to comment
Share on other sites

Got rid of first floppy grind. Here's the original code:

if $Floppy <> "" Then
;Draft the $Filt1 variable here....
            $Filt2 = "WHERE " & StringReplace( $Floppy, "|", "' And DeviceID <> '" )
            $Filt2 = StringReplace( $Filt2, "WHERE ' And", "WHERE" ) & "'"
        Endif
    endif
and here's what to replace it with:
if $Floppy <> "" Then
            $Filt1 = """' and Dependent='\\\\.\\root\\cimv2:Win32_LogicalDisk.DeviceID<>"""
            $Filt1 = "WHERE " & StringReplace( $Floppy, "|", $Filt1 ) & """'"
            $Filt1 = StringReplace( $Filt1, "WHERE ""' And", "WHERE" )
            $Filt2 = "WHERE " & StringReplace( $Floppy, "|", "' And DeviceID <> '" )
            $Filt2 = StringReplace( $Filt2, "WHERE ' And", "WHERE" ) & "'"
        Endif

This solves my last problem with this.

Edited by Dougiefresh
Link to comment
Share on other sites

@dougiefresh

There is probably something in here that you can use. AFAIK it won't even look at the floppies.

$wbemFlagReturnImmediately = 0x10
$wbemFlagForwardOnly = 0x20
$colItems = ""
$strComputer = "localhost"

$Output=""
$Output &= "Computer: " & $strComputer  & @CRLF
$Output &= "==========================================" & @CRLF
$objWMIService = ObjGet("winmgmts:\\" & $strComputer & "\root\CIMV2")
$colItems = $objWMIService.ExecQuery("SELECT * FROM Win32_DiskDrive", "WQL", _
                                          $wbemFlagReturnImmediately + $wbemFlagForwardOnly)

If IsObj($colItems) then
   For $objItem In $colItems
      $Output &= "Availability: " & $objItem.Availability & @CRLF
      $Output &= "BytesPerSector: " & $objItem.BytesPerSector & @CRLF
      $strCapabilities = $objItem.Capabilities(0)
      $Output &= "Capabilities: " & $strCapabilities & @CRLF
      $strCapabilityDescriptions = $objItem.CapabilityDescriptions(0)
      $Output &= "CapabilityDescriptions: " & $strCapabilityDescriptions & @CRLF
      $Output &= "Caption: " & $objItem.Caption & @CRLF
      $Output &= "CompressionMethod: " & $objItem.CompressionMethod & @CRLF
      $Output &= "ConfigManagerErrorCode: " & $objItem.ConfigManagerErrorCode & @CRLF
      $Output &= "ConfigManagerUserConfig: " & $objItem.ConfigManagerUserConfig & @CRLF
      $Output &= "CreationClassName: " & $objItem.CreationClassName & @CRLF
      $Output &= "DefaultBlockSize: " & $objItem.DefaultBlockSize & @CRLF
      $Output &= "Description: " & $objItem.Description & @CRLF
      $Output &= "DeviceID: " & $objItem.DeviceID & @CRLF
      $Output &= "ErrorCleared: " & $objItem.ErrorCleared & @CRLF
      $Output &= "ErrorDescription: " & $objItem.ErrorDescription & @CRLF
      $Output &= "ErrorMethodology: " & $objItem.ErrorMethodology & @CRLF
      $Output &= "Index: " & $objItem.Index & @CRLF
      $Output &= "InstallDate: " & WMIDateStringToDate($objItem.InstallDate) & @CRLF
      $Output &= "InterfaceType: " & $objItem.InterfaceType & @CRLF
      $Output &= "LastErrorCode: " & $objItem.LastErrorCode & @CRLF
      $Output &= "Manufacturer: " & $objItem.Manufacturer & @CRLF
      $Output &= "MaxBlockSize: " & $objItem.MaxBlockSize & @CRLF
      $Output &= "MaxMediaSize: " & $objItem.MaxMediaSize & @CRLF
      $Output &= "MediaLoaded: " & $objItem.MediaLoaded & @CRLF
      $Output &= "MediaType: " & $objItem.MediaType & @CRLF
      $Output &= "MinBlockSize: " & $objItem.MinBlockSize & @CRLF
      $Output &= "Model: " & $objItem.Model & @CRLF
      $Output &= "Name: " & $objItem.Name & @CRLF
      $Output &= "NeedsCleaning: " & $objItem.NeedsCleaning & @CRLF
      $Output &= "NumberOfMediaSupported: " & $objItem.NumberOfMediaSupported & @CRLF
      $Output &= "Partitions: " & $objItem.Partitions & @CRLF
      $Output &= "PNPDeviceID: " & $objItem.PNPDeviceID & @CRLF
      $strPowerManagementCapabilities = $objItem.PowerManagementCapabilities(0)
      $Output &= "PowerManagementCapabilities: " & $strPowerManagementCapabilities & @CRLF
      $Output &= "PowerManagementSupported: " & $objItem.PowerManagementSupported & @CRLF
      $Output &= "SCSIBus: " & $objItem.SCSIBus & @CRLF
      $Output &= "SCSILogicalUnit: " & $objItem.SCSILogicalUnit & @CRLF
      $Output &= "SCSIPort: " & $objItem.SCSIPort & @CRLF
      $Output &= "SCSITargetId: " & $objItem.SCSITargetId & @CRLF
      $Output &= "SectorsPerTrack: " & $objItem.SectorsPerTrack & @CRLF
      $Output &= "Signature: " & $objItem.Signature & @CRLF
      $Output &= "Size: " & $objItem.Size & @CRLF
      $Output &= "Status: " & $objItem.Status & @CRLF
      $Output &= "StatusInfo: " & $objItem.StatusInfo & @CRLF
      $Output &= "SystemCreationClassName: " & $objItem.SystemCreationClassName & @CRLF
      $Output &= "SystemName: " & $objItem.SystemName & @CRLF
      $Output &= "TotalCylinders: " & $objItem.TotalCylinders & @CRLF
      $Output &= "TotalHeads: " & $objItem.TotalHeads & @CRLF
      $Output &= "TotalSectors: " & $objItem.TotalSectors & @CRLF
      $Output &= "TotalTracks: " & $objItem.TotalTracks & @CRLF
      $Output &= "TracksPerCylinder: " & $objItem.TracksPerCylinder & @CRLF
      if Msgbox(1,"WMI Output",$Output) = 2 then ExitLoop
      $Output=""
   Next
Else
   Msgbox(0,"WMI Output","No WMI Objects Found for class: " & "Win32_DiskDrive" )
Endif


Func WMIDateStringToDate($dtmDate)

    Return (StringMid($dtmDate, 5, 2) & "/" & _
    StringMid($dtmDate, 7, 2) & "/" & StringLeft($dtmDate, 4) _
    & " " & StringMid($dtmDate, 9, 2) & ":" & StringMid($dtmDate, 11, 2) & ":" & StringMid($dtmDate,13, 2))
EndFunc

George

Question about decompiling code? Read the decompiling FAQ and don't bother posting the question in the forums.

Be sure to read and follow the forum rules. -AKA the AutoIt Reading and Comprehension Skills test.***

The PCRE (Regular Expression) ToolKit for AutoIT - (Updated Oct 20, 2011 ver:3.0.1.13) - Please update your current version before filing any bug reports. The installer now includes both 32 and 64 bit versions. No change in version number.

Visit my Blog .. currently not active but it will soon be resplendent with news and views. Also please remove any links you may have to my website. it is soon to be closed and replaced with something else.

"Old age and treachery will always overcome youth and skill!"

Link to comment
Share on other sites

Actually, for the "SELECT * FROM Win32_DiskDrive" section of code, I've already got the code not to look at the floppy. That's where the "$Filt2" variable comes in. It's actually built earlier in the function, so that all detected floppy drives are covered in the list of drives not to look at.

The problem I'm having is with the "SELECT * FROM Win32_LogicalDiskToPartition" section of code. I can't seem to find any way to prevent the code from causing the floppy drive to activate (or grind). I was hoping to use something similar to the "SELECT * FROM Win32_DiskDrive" code, but everything I've tried to exclude the floppy drives in the search has met without success. If you could look at 2 posts ago (and 3 or 4 posts with full code for function) and solve this problem, it would be most appreciated! I'll continue looking for a solution...

EDIT: Edited post because "$FILT1" is used for first search (Win32_LogicalDiskToPartition), "$FILT2" for the second search (Win32_DiskDrive). Sorry about that!

Edited by Dougiefresh
Link to comment
Share on other sites

Interesting because the code I gave you causes no drive activity on my floppy drive at all.

George

Question about decompiling code? Read the decompiling FAQ and don't bother posting the question in the forums.

Be sure to read and follow the forum rules. -AKA the AutoIt Reading and Comprehension Skills test.***

The PCRE (Regular Expression) ToolKit for AutoIT - (Updated Oct 20, 2011 ver:3.0.1.13) - Please update your current version before filing any bug reports. The installer now includes both 32 and 64 bit versions. No change in version number.

Visit my Blog .. currently not active but it will soon be resplendent with news and views. Also please remove any links you may have to my website. it is soon to be closed and replaced with something else.

"Old age and treachery will always overcome youth and skill!"

Link to comment
Share on other sites

Interesting because the code I gave you causes no drive activity on my floppy drive at all.

GEOSoft the problem is that your code as itself isn't enought to get PnpDeviceID from drive letter. I had to use a lot of others wmi calls to get this right.

My little company: Evotec (PL version: Evotec)

Link to comment
Share on other sites

GEOSoft, the code you provided doesn't cause a floppy drive access either. I looked at my code and yours, and I don't see any difference between the two (mine without the filter). Mine causes floppy drive access, yours doesn't. No clue why... Madboy is right, though. Your code doesn't return PNP device IDs.

Madboy, any ideas on how to solve this little issue?

Link to comment
Share on other sites

GEOSoft, the code you provided doesn't cause a floppy drive access either. I looked at my code and yours, and I don't see any difference between the two (mine without the filter). Mine causes floppy drive access, yours doesn't. No clue why... Madboy is right, though. Your code doesn't return PNP device IDs.

Madboy, any ideas on how to solve this little issue?

It returns PNPDeviceID but you can't call it by Drive letter.

$Output &= "PNPDeviceID: " & $objItem.PNPDeviceID & @CRLF

George

Question about decompiling code? Read the decompiling FAQ and don't bother posting the question in the forums.

Be sure to read and follow the forum rules. -AKA the AutoIt Reading and Comprehension Skills test.***

The PCRE (Regular Expression) ToolKit for AutoIT - (Updated Oct 20, 2011 ver:3.0.1.13) - Please update your current version before filing any bug reports. The installer now includes both 32 and 64 bit versions. No change in version number.

Visit my Blog .. currently not active but it will soon be resplendent with news and views. Also please remove any links you may have to my website. it is soon to be closed and replaced with something else.

"Old age and treachery will always overcome youth and skill!"

Link to comment
Share on other sites

It returns PNPDeviceID but you can't call it by Drive letter.

You're right. I missed the PNPDeviceID line in your code.

I need to associate a drive letter with a PNP device ID. The modified MadDog post found here does using 3 WMI queries, but it grinds the floppy drive. The second WMI query doesn't (probably by design). The third WMI query gets the PNP Device ID from WMI, like your code does GEOSoft. I've already got a filter for that (Win32_DiskDrive) WMI query.

The first WMI query uses Win32_LogicalDriveToPartition. How do I modify this so that the query doesn't check the floppy drive?

Link to comment
Share on other sites

  • 3 weeks later...

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...