Windows – How to List Every \Device\Harddiskvolume

bcddiskpartwindows

I've tried Diskpart commands like "list" "volume" (no it's not that at all), "disk" and "partition"; but it still don't work.

\Device\Harddiskvolume0 seems to not be used, since \Device\Harddiskvolume1 means the first Windows' partition (aka "System Reserved") and \Device\Harddiskvolume2 is for C:.

So the question is: How to list every \Device\Harddiskvolume in Windows' 7 installation disk (for BCD editing) ?

Best Answer

I adapted @merle's answer by using the approach documented on MSDN.

It shows drives:

  • without drive letters
  • mounted to a folder
  • with drive letters

Sample output:

DriveLetter                    DevicePath               VolumeName                                       
-----------                    ----------               ----------                                       
                               \Device\HarddiskVolume5  \\?\Volume{a2b4c6d8-0000-0000-00000100000000000}\
E:\                            \Device\HarddiskVolume9  \\?\Volume{a2b4c6d8-1234-1234-1234-123456789abc}\
C:\Mounted\My-Folder-Mount\    \Device\HarddiskVolume13 \\?\Volume{a2b4c6d8-1234-1234-1234-123456789abc}\

PowerShell script:

$signature = @'
[DllImport("kernel32.dll", SetLastError=true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool GetVolumePathNamesForVolumeNameW([MarshalAs(UnmanagedType.LPWStr)] string lpszVolumeName,
        [MarshalAs(UnmanagedType.LPWStr)] [Out] StringBuilder lpszVolumeNamePaths, uint cchBuferLength, 
        ref UInt32 lpcchReturnLength);

[DllImport("kernel32.dll", SetLastError = true)]
public static extern IntPtr FindFirstVolume([Out] StringBuilder lpszVolumeName,
   uint cchBufferLength);

[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool FindNextVolume(IntPtr hFindVolume, [Out] StringBuilder lpszVolumeName, uint cchBufferLength);

[DllImport("kernel32.dll", SetLastError = true)]
public static extern uint QueryDosDevice(string lpDeviceName, StringBuilder lpTargetPath, int ucchMax);

'@;
Add-Type -MemberDefinition $signature -Name Win32Utils -Namespace PInvoke -Using PInvoke,System.Text;

[UInt32] $lpcchReturnLength = 0;
[UInt32] $Max = 65535
$sbVolumeName = New-Object System.Text.StringBuilder($Max, $Max)
$sbPathName = New-Object System.Text.StringBuilder($Max, $Max)
$sbMountPoint = New-Object System.Text.StringBuilder($Max, $Max)
[IntPtr] $volumeHandle = [PInvoke.Win32Utils]::FindFirstVolume($sbVolumeName, $Max)
do {
    $volume = $sbVolumeName.toString()
    $unused = [PInvoke.Win32Utils]::GetVolumePathNamesForVolumeNameW($volume, $sbMountPoint, $Max, [Ref] $lpcchReturnLength);
    $ReturnLength = [PInvoke.Win32Utils]::QueryDosDevice($volume.Substring(4, $volume.Length - 1 - 4), $sbPathName, [UInt32] $Max);
    if ($ReturnLength) {
           $DriveMapping = @{
               DriveLetter = $sbMountPoint.toString()
               VolumeName = $volume
               DevicePath = $sbPathName.ToString()
           }

           Write-Output (New-Object PSObject -Property $DriveMapping)
       }
       else {
           Write-Output "No mountpoint found for: " + $volume
       } 
} while ([PInvoke.Win32Utils]::FindNextVolume([IntPtr] $volumeHandle, $sbVolumeName, $Max));
Related Question