Blog Archives

PowerShell: Getting the Disk Drive from a Volume or Mount Point

So this is way harder than I thought it would be.

If you take a look at the WMI class for Win32_MountPoint

You’ll notice there is a remark there that says:

There may not be any way to search from Win32_MountPoint to get to the associated Win32_DiskDrive

Which also applies to the Volume.

That sends you over to this blog post which talks about a win32 api call via DeviceIoControl and I managed to find decent info on and also this blog post here which basically gives some VB code for it.

So after taking all that in, I was able to write a simple C# snippet that you can toss in PS to query for a Volume

Add-Type -TypeDefinition @"
using System;
using Microsoft.Win32.SafeHandles;
using System.IO;
using System.Runtime.InteropServices;

public class GetDisk
 private const uint IoctlVolumeGetVolumeDiskExtents = 0x560000;

 public struct DiskExtent
 public int DiskNumber;
 public Int64 StartingOffset;
 public Int64 ExtentLength;

 public struct DiskExtents
 public int numberOfExtents;
 public DiskExtent first;

 [DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
 private static extern SafeFileHandle CreateFile(
 string lpFileName,
 [MarshalAs(UnmanagedType.U4)] FileAccess dwDesiredAccess,
 [MarshalAs(UnmanagedType.U4)] FileShare dwShareMode,
 IntPtr lpSecurityAttributes,
 [MarshalAs(UnmanagedType.U4)] FileMode dwCreationDisposition,
 [MarshalAs(UnmanagedType.U4)] FileAttributes dwFlagsAndAttributes,
 IntPtr hTemplateFile);

 [DllImport("Kernel32.dll", SetLastError = false, CharSet = CharSet.Auto)]
 private static extern bool DeviceIoControl(
 SafeFileHandle hDevice,
 uint IoControlCode,
 [MarshalAs(UnmanagedType.AsAny)] [In] object InBuffer,
 uint nInBufferSize,
 ref DiskExtents OutBuffer,
 int nOutBufferSize,
 ref uint pBytesReturned,
 IntPtr Overlapped

 public static string GetPhysicalDriveString(string path)
 //clean path up
 path = path.TrimEnd('\\');
 if (!path.StartsWith(@"\\.\"))
 path = @"\\.\" + path;

 SafeFileHandle shwnd = CreateFile(path, FileAccess.Read, FileShare.Read | FileShare.Write, IntPtr.Zero, FileMode.Open, 0,
 if (shwnd.IsInvalid)
 Exception e = Marshal.GetExceptionForHR(Marshal.GetLastWin32Error());

 var bytesReturned = new uint();
 var de1 = new DiskExtents();
 bool result = DeviceIoControl(shwnd, IoctlVolumeGetVolumeDiskExtents, IntPtr.Zero, 0, ref de1,
 Marshal.SizeOf(de1), ref bytesReturned, IntPtr.Zero);
 return @"\\.\PhysicalDrive" + de1.first.DiskNumber;
 return null;


This will allow you to call this static method to get its Disk path, so you can do something like this.

$DeviceID = [GetDisk]::GetPhysicalDriveString('c:\')
gwmi win32_diskdrive | ? { $_.deviceid -eq $DeviceID}

Now you say, but Justin, this isnt working for a mount point path!? Which is true, but we can work around that.

We can use the Win32_MountPoint class to figure this out, or, you can use this cmdlet Get-MountPointData which basically parses the class for you. Really all you need to do is get the Volume DeviceID, which looks something like this.


So we can take that and search on it like so.


NOTE: This must be run as admin, since we’re hitting the disk subsystem (kernel)


Using WMI to link a Disk Volume to a Physical Disk with PowerShell

Recently someone asked how to map a disk volume to a physical disk. At first I figured this would be real easy and just involve two WMI calls. Come to find out, it’s not that easy, but not impossible.

$diskdrive = gwmi win32_diskdrive

foreach($drive in $diskdrive)


out-host -InputObject "`nDrive: deviceid-$($drive.deviceid.substring(4)) Model - $($drive.model)"


$partitions = gwmi -Query "ASSOCIATORS OF {Win32_DiskDrive.DeviceID=`"$($drive.DeviceID.replace('\','\\'))`"} WHERE AssocClass = Win32_DiskDriveToDiskPartition"

foreach($part in $partitions)


Out-Host -InputObject "`tPartition: $($"

$vols = gwmi -Query "ASSOCIATORS OF {Win32_DiskPartition.DeviceID=`"$($part.DeviceID)`"} WHERE AssocClass = Win32_LogicalDiskToPartition"

foreach($vol in $vols)


out-host -InputObject "`t`t$($"




Not too bad, but could be better. There is a GetRelated method that PowerShell tack on to WMI objects which should allow you to do the Associate stuff with PowerShell rather than writing WMI queries but I havent figured that out.