18

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) ?

6 Answers 6

13

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));
1
  • 2
    Nice! A few other useful outputs to add might be the FileSystemLabel (aka FriendlyName), Size, and perhaps the corresponding disk and partition numbers. For my hacky one-off purposes, I just tacked these two lines on to the end of your script, so I could manually match the Volume GUIDs. Get-Volume | Select DriveLetter, FileSystemLabel, FileSystemType, Size, Path | Format-Table -Autosize and with a new line Get-Partition | Select DiskNumber, PartitionNumber, AccessPaths, Size | Sort-Object -Property DiskNumber, PartitionNumber | Format-Table -Autosize Apr 29, 2020 at 22:23
9

Found a powershell script that lists the mounted volumes:

# Biuild System Assembly in order to call Kernel32:QueryDosDevice. 
   $DynAssembly = New-Object System.Reflection.AssemblyName('SysUtils')
   $AssemblyBuilder = [AppDomain]::CurrentDomain.DefineDynamicAssembly($DynAssembly, [Reflection.Emit.AssemblyBuilderAccess]::Run)
   $ModuleBuilder = $AssemblyBuilder.DefineDynamicModule('SysUtils', $False)

   # Define [Kernel32]::QueryDosDevice method
   $TypeBuilder = $ModuleBuilder.DefineType('Kernel32', 'Public, Class')
   $PInvokeMethod = $TypeBuilder.DefinePInvokeMethod('QueryDosDevice', 'kernel32.dll', ([Reflection.MethodAttributes]::Public -bor [Reflection.MethodAttributes]::Static), [Reflection.CallingConventions]::Standard, [UInt32], [Type[]]@([String], [Text.StringBuilder], [UInt32]), [Runtime.InteropServices.CallingConvention]::Winapi, [Runtime.InteropServices.CharSet]::Auto)
   $DllImportConstructor = [Runtime.InteropServices.DllImportAttribute].GetConstructor(@([String]))
   $SetLastError = [Runtime.InteropServices.DllImportAttribute].GetField('SetLastError')
   $SetLastErrorCustomAttribute = New-Object Reflection.Emit.CustomAttributeBuilder($DllImportConstructor, @('kernel32.dll'), [Reflection.FieldInfo[]]@($SetLastError), @($true))
   $PInvokeMethod.SetCustomAttribute($SetLastErrorCustomAttribute)
   $Kernel32 = $TypeBuilder.CreateType()

   $Max = 65536
   $StringBuilder = New-Object System.Text.StringBuilder($Max)

   Get-WmiObject Win32_Volume | ? { $_.DriveLetter } | % {
       $ReturnLength = $Kernel32::QueryDosDevice($_.DriveLetter, $StringBuilder, $Max)

       if ($ReturnLength)
       {
           $DriveMapping = @{
               DriveLetter = $_.DriveLetter
               DevicePath = $StringBuilder.ToString()
           }

           New-Object PSObject -Property $DriveMapping
       }
   }

Source: http://www.morgantechspace.com/2014/11/Get-Volume-Path-from-Drive-Name-using-Powershell.html

Output looks like this:

DevicePath               DriveLetter
----------               -----------
\Device\HarddiskVolume2  F:         
\Device\HarddiskVolume7  J:         
\Device\HarddiskVolume10 D:         
\Device\HarddiskVolume12 E:         
\Device\HarddiskVolume5  C:    
2
  • 1
    Unfortunately, this does not list the volumes that aren't mounted under a drive letter.
    – phant0m
    Feb 1, 2019 at 15:07
  • Here is my adapted script that shows all drives, no matter whether folder mounted or no drive letter at all: superuser.com/a/1401025/59487
    – phant0m
    Dec 2, 2019 at 11:06
5

The reason I couldn't get things done is that HarddiskVolume doesn't reflect Diskpart volumes -which only lists every Windows readable volumes-.

In fact, it works with every partitions available on the disk -even the non-Windows ones-, by order they appear like in Linux's Gparted.

E.g, if you have an sda4 before sda3, this latter will show as is -sda4 then sda3- (HarddiskVolume4 then HarddiskVolume3).

So, it means that HarddiskVolume0 mainly don't exist in BCD.

The commands that helped me to understand that are:

mountvol /L

bootsect /nt60 all /force   ->   Be careful with that one !!!

These links also helped me:

Finally, if you have a spare Windows, just run DriveLetterView to see how Windows works with HarddiskVolume.

Note: The HarddiskVolume is a WMI/COM notation

1
  • If you can install 3rd party tools, DriveLetterView from the venerable Nirsoft, as mentioned here, is by far the easiest, in this humble tech's opinion. Gives you disk numbers and volume numbers, volume drive letters, and everything else (vendor, disk name, volume name, disk space, etc) all in one nice easy view, saveable to disk. Dec 23, 2020 at 4:17
5

The easiest way without installing anything and tinkering with Powershell scripts might be System Information Viewer a portable Windows application. This app is great because it provides nearly every information about your machine / hardware. It not only offers a read out of hard drive related data rather nearly everything about your device can be found. Moreover it's very lightweight but TBH a bit confusing structured.

Finally, how do you find drive information? Under Volumes ▼ there is the option Volume List that will give you an overview of all \Device\HarddiskvolumeXX present on your computer. Additionally you get drive letter and GUID of your partitions.

To list all \Device\HarddiskVolumeXX including those that are not mounted under any drive letter per physical driver together with the disk number (like seen in Windows Disk Management). Open the Volumes ▼ dropdown and choose Disk Mapping.

I also want to highlight the option Drives which displays \.\PhysicalDriveXX, path, unit and controller IDs. The listing under Drive Mapping might also be quite useful.

2
  • @phant0m I took your proposed edit and integrated it to some degree into the post even as it was rejected by the mods. I find the information added useful, however I kept the original structuring and just added new paragraph instead.
    – thex
    Feb 5, 2019 at 11:27
  • @phant0m "This edit was intended to address the author of the post and makes no sense as an edit. It should have been written as a comment or an answer."
    – thex
    Mar 23, 2019 at 10:30
0

An easier way to do it is as written below. I've also customized a couple of the columns.

Please run the below in PowerShell:

Get-CimInstance win32_volume -ComputerName "Enter Your Computer Name, or Multiple Computer Names" | select @{n="ComputerName";e={$_.PSComputerName}},DriveLetter,@{n="Capacity(GB)";e={$_.Capacity / 1gb -as [int]}},@{n="Free(GB)";e={$_.FreeSpace / 1gb -as [int]}} | ft -AutoSize
1
  • This is for PowerShell v3 only, user specified for Windows 7 which doesn't come with v3 by default.
    – JasonXA
    Mar 29, 2019 at 4:38
-1

If you want just to find out where your system BCD store is take a look at \REGISTRY\MACHINE\BCD00000000 value in HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\hivelist registry key. Yes, its location can differ from \Device\HardDiskVolume1 even if it is on the 1st partition of the 1st physical disk.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.