How Can I Correlate Logical Drives and Physical Disks?

How Can I Correlate Logical Drives and Physical Disks?

  • Comments 7
  • Likes
Hey, Scripting Guy! Question

Hey, Scripting Guy! How can I correlate logical drives and physical disks?

-- LB

SpacerHey, Scripting Guy! AnswerScript Center

Hey, LB. We’ll make a deal with you: we’ll show you a script that can tell you which logical drives are found on which physical disks, and you promise not to say, “Wait, I don’t understand how this script works.” To tell you the truth, we’re not so sure that we understand how the script works, either. As you’ll see it’s a bit wacky, to say the least.

The problem is that there is no simple, straightforward way to retrieve the logical disks associated with a given physical disk. Instead, we have to use a couple of association classes (Win32_DiskDriveToDiskPartition and Win32_LogicalDiskToPartition) to figure out the relationship between logical drives and disks. There’s nothing wrong with doing this, except that association classes can be extremely confusing, and the code required to use them can be even more confusing. If you’re a relative newcomer to scripting, this might be a time when you just use the code without trying too terribly hard to understand it all.

Here’s the script:

strComputer = "."
Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")

Set colDiskDrives = objWMIService.ExecQuery("SELECT * FROM Win32_DiskDrive")
 
For Each objDrive In colDiskDrives
    Wscript.Echo "Physical Disk: " & objDrive.Caption & " -- " & objDrive.DeviceID 
    strDeviceID = Replace(objDrive.DeviceID, "\", "\\")
    Set colPartitions = objWMIService.ExecQuery _
        ("ASSOCIATORS OF {Win32_DiskDrive.DeviceID=""" & _
            strDeviceID & """} WHERE AssocClass = " & _
                "Win32_DiskDriveToDiskPartition")
 
    For Each objPartition In colPartitions
        Wscript.Echo "Disk Partition: " & objPartition.DeviceID
        Set colLogicalDisks = objWMIService.ExecQuery _
            ("ASSOCIATORS OF {Win32_DiskPartition.DeviceID=""" & _
                objPartition.DeviceID & """} WHERE AssocClass = " & _
                    "Win32_LogicalDiskToPartition")
 
        For Each objLogicalDisk In colLogicalDisks
            Wscript.Echo "Logical Disk: " & objLogicalDisk.DeviceID
        Next
        Wscript.Echo
    Next
    Wscript.Echo
Next

We told you it was weird-looking, didn’t we? It actually starts off innocently enough: we simply connect to the WMI service and then use the ExecQuery method to retrieve a collection of all the physical disk drives installed on a computer. We create a For Each loop to loop through the collection of disk drives and echo the values of the Caption and DeviceID properties.

Now it starts to get a little wild. The DeviceID - which uniquely identifies each disk drive - will have a value like this: \\.\PHYSICALDRIVE0. We’re going to use this value in a query, so we have to “escape” each \ with a second \. (Why? Because a single \ is a reserved character in WMI.) That’s what this line of code does:

strDeviceID = Replace(objDrive.DeviceID, "\", "\\")

After we do that we can then use this query to return all the disk partitions associated with the first physical disk drive on the computer:

Set colPartitions = objWMIService.ExecQuery _
    ("ASSOCIATORS OF {Win32_DiskDrive.DeviceID=""" & _
        strDeviceID & """} WHERE AssocClass = " & _
            "Win32_DiskDriveToDiskPartition")

Believe it or not we’re making progress now; after all, we now have a collection of all the disk partitions found on the first drive. With the partitions in hand we set up a second For Each loop to iterate through these partitions; for each partition in the collection we then use this query to retrieve all of the logical drives found on those partitions:

Set colLogicalDisks = objWMIService.ExecQuery _
    ("ASSOCIATORS OF {Win32_DiskPartition.DeviceID=""" & _
        objPartition.DeviceID & """} WHERE AssocClass = " & _
            "Win32_LogicalDiskToPartition")

All that’s left now is to set up a third For Each loop, this one to echo back all the logical disks found on the first partition of the first physical disk:

For Each objLogicalDisk In colLogicalDisks
    Wscript.Echo "Logical Disk: " & objLogicalDisk.DeviceID
Next

We loop around and repeat the process for all the remaining partitions on disk 1, then loop back even further and repeat the process for any additional disk drives found on the computer. When you’re all done, you’ll get back a report similar to this:

Physical Disk: IC25N040ATMR04-0 -- \\.\PHYSICALDRIVE0
Disk Partition: Disk #0, Partition #0

Disk Partition: Disk #0, Partition #1
Logical Disk: C:

Disk Parititon: Disk #0, Partition #2
Logical Disk: D:

Physical Disk: Memory Stick Slot -- \\.\PHYSICALDRIVE1

As you can see, the first disk has three partitions and two logical drives: drives C and D. The second disk has no partitions or logical drives. (What, you think Microsoft would give the Scripting Guys computers that actually had two disk drives in them?)

Like we said, if you don’t follow all this, don’t worry about it. No one knows how hot dogs are made, either, and the truth is, you probably don’t want to know. Just slap some mustard and relish on the thing and enjoy. The same thing applies to this script (although possibly without the mustard and relish).

Your comment has been posted.   Close
Thank you, your comment requires moderation so it may take a while to appear.   Close
Leave a Comment
  • The reason for the weirdness is filesystems can span more than one partition due to the software raid present in some versions of windows.

  • Is it possible to add some lines to retrieve the information from command "diskpart list disk" and also freespace on logical disks??

    thanks

  • This is great, but it isn't showing logical disks that are mounted with mount paths instead of drive letters.  Is there a fix for this?

    Thanks

  • Does not work in PE 3 (with WMI component installed - all other WMI commands that I need work fine in PE).

    Works fine when run directly in Win7.

    In particular the following code returns 0 in the collection for some reason:

    Set colPartitions = objWMIService.ExecQuery _

       ("ASSOCIATORS OF {Win32_DiskDrive.DeviceID=""" & _

           strDeviceID & """} WHERE AssocClass = " & _

               "Win32_DiskDriveToDiskPartition")

    msgbox colParitions.Count

    Result = 0 in PE (Win 7 returns the correct number of partitions for the disk).

    All other parts work (i.e getting the PHYSICALDISK number).

    Not sure if I'm missing something.

  • This DOES NOT work under WinPE. I tried many things and couldn't get it to work!!!

  • My code: VBScript

    Dim query
    Dim objWMI
    Dim diskDrives
    Dim diskDrive
    Dim partitions
    Dim partition ' will contain the drive & partition numbers
    Dim logicalDisks
    Dim logicalDisk ' will contain the drive letter

    Set objWMI = GetObject("winmgmts:\\.\root\cimv2")
    Set diskDrives = objWMI.ExecQuery("SELECT * FROM Win32_DiskDrive") ' First get out the physical drives
    For Each diskDrive In diskDrives
    query = "ASSOCIATORS OF {Win32_DiskDrive.DeviceID='" + diskDrive.DeviceID + "'} WHERE AssocClass = Win32_DiskDriveToDiskPartition" ' link the physical drives to the partitions
    Set partitions = objWMI.ExecQuery(query)
    For Each partition In partitions
    query = "ASSOCIATORS OF {Win32_DiskPartition.DeviceID='" + partition.DeviceID + "'} WHERE AssocClass = Win32_LogicalDiskToPartition" ' link the partitions to the logical disks
    Set logicalDisks = objWMI.ExecQuery (query)
    For Each logicalDisk In logicalDisks
    Wscript.Echo logicalDisk.DeviceID & " - " & partition.Caption & " - " & logicalDisk.FreeSpace
    Next
    Next
    Next

  • ...Another way

    Set Win32_LogicalDisk = .ExecQuery("Select * From Win32_LogicalDisk WHERE DriveType = 3")

    For Each objItem in Win32_LogicalDisk
    With GetObject("winmgmts:\\" & strComputer & "\root\cimv2").ExecQuery("ASSOCIATORS OF {Win32_LogicalDisk.DeviceID='" & objItem.DeviceID & "'} WHERE ResultClass=Win32_DiskPartition").ItemIndex(0)
    With GetObject("winmgmts:\\" & strComputer & "\root\cimv2").ExecQuery("ASSOCIATORS OF {Win32_DiskPartition.DeviceID='" & .DeviceID & "'} WHERE ResultClass=Win32_DiskDrive").ItemIndex(0)
    Wscript.Echo "Boot Disk: " & .Model
    End With
    End With
    Next