So this is way harder than I thought it would be.
If you take a look at the WMI class for Win32_MountPoint
https://msdn.microsoft.com/en-us/library/aa394205%28v=vs.85%29.aspx
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 PInvoke.net 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; [StructLayout(LayoutKind.Sequential)] public struct DiskExtent { public int DiskNumber; public Int64 StartingOffset; public Int64 ExtentLength; } [StructLayout(LayoutKind.Sequential)] 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, IntPtr.Zero); if (shwnd.IsInvalid) { //Marshal.ThrowExceptionForHR(Marshal.GetLastWin32Error()); 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); shwnd.Close(); if(result) 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.
Volume{ccbca757-b6c9-11e4-8275-448a5ba2d884}
So we can take that and search on it like so.
[GetDisk]::GetPhysicalDriveString('Volume{78498ddf-9a97-11e4-8252-806e6f6e6963}')
NOTE: This must be run as admin, since we’re hitting the disk subsystem (kernel)
Enjoy!