26

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

ᄂ ᄀ
  • 4,187
X.LINK
  • 2,448

7 Answers7

19

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

phuclv
  • 30,396
  • 15
  • 136
  • 260
phant0m
  • 240
10

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:

phuclv
  • 30,396
  • 15
  • 136
  • 260
merle
  • 131
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

X.LINK
  • 2,448
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.

thex
  • 311
  • 3
  • 8
1

Those are Windows Object Manager device names for disk volumes. If you are okay with installing NtObjectManager PowerShell module, then listing them is as simple as:

ls NtObject:\Device | ? {$_.Name -match 'HarddiskVolume'}

You can find corresponding drive letters via something like

Get-Volume | % { ($_.DriveLetter) ? (Get-NtSymbolicLink "\??\$($_.DriveLetter):") : $Null }

If installing additional module is not an option, more universal solution would be to use Win32 API directly (QueryDosDevice).

Short version:

$Kernel32 = Add-Type -Name 'Kernel32' -Namespace '' -PassThru -MemberDefinition @"
    [DllImport("kernel32")]
    public static extern int QueryDosDevice(string name, System.Text.StringBuilder path, int pathMaxLength);
"@

$DevicePath = New-Object System.Text.StringBuilder(255) $GetDevicePath = {$Kernel32::QueryDosDevice( ` $_.UniqueId.TrimStart('\?').TrimEnd(''), $DevicePath, $DevicePath.Capacity) | Out-Null; $DevicePath}

Get-Volume | ft DriveLetter, FileSystemLabel, @{n='DevicePath';e=$GetDevicePath}, UniqueId

More verbose and error-prone version:

$Kernel32 = Add-Type -Name 'Kernel32' -Namespace '' -PassThru -MemberDefinition @"
    [DllImport("kernel32", SetLastError = true)]
    public static extern int QueryDosDevice(string name, System.Text.StringBuilder path, int pathMaxLength);
"@

$DevicePath = New-Object System.Text.StringBuilder(255) Get-Volume | % { if ($.UniqueId -match '(Volume{.*})') { $VolumeName = $Matches[1] } else { Write-Host "Unable to lookup volume name in '$($.UniqueId)'" Return } $ReturnLength = $Kernel32::QueryDosDevice($VolumeName, $DevicePath, $DevicePath.Capacity) if ($ReturnLength) { [PSCustomObject]@{ DriveLetter = $.DriveLetter Label = $.FileSystemLabel FileSystem = $.FileSystem "Size (GB)" = $.Size / 1GB "Free (GB)" = $.SizeRemaining / 1GB DevicePath = $DevicePath.ToString() Id = $.UniqueId } } else { $errorCode = [System.Runtime.InteropServices.Marshal]::GetLastPInvokeError() Write-Host "Unable to query DOS device by '$VolumeName'." (New-Object System.ComponentModel.Win32Exception($errorCode)).Message } } | ? { $_.DevicePath } | Sort-Object DevicePath | ft

ᄂ ᄀ
  • 4,187
0

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.

ᄂ ᄀ
  • 4,187
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
Run5k
  • 16,463
  • 24
  • 53
  • 67