4

I'm trying to utilize WMI via PowerShell to run through SAN storage on remote servers to grab the Windows disk management volume label.

The only way I've found to do this is to correlate the volume device id (\\?\Volume{34243...} with the physical disk device ID (\\.\PHYSICALDRIVE01).

However, I haven't been able to find out how to link those two fields together. Is this possible with WMI?

Ansgar Wiechers
  • 193,178
  • 25
  • 254
  • 328
Galvatron
  • 59
  • 1
  • 2
  • It will not work in all cases, but ... if the volume does not have a drive letter, assign it to it (the Win32_volume.DriveLetter property is writable), then use Win32_LogicalDiskToPartition or Win32_DiskDriveToDiskPartition and finally remove the drive letter. This is only a suggestion and please do not test this solution on production systems. – Paweł Piwowar May 06 '21 at 10:34

2 Answers2

2

For volumes that were assigned a drive letter you can correlate disks and volumes like this:

Get-WmiObject Win32_DiskDrive | ForEach-Object {
  $disk = $_
  $partitions = "ASSOCIATORS OF " +
                "{Win32_DiskDrive.DeviceID='$($disk.DeviceID)'} " +
                "WHERE AssocClass = Win32_DiskDriveToDiskPartition"
  Get-WmiObject -Query $partitions | ForEach-Object {
    $partition = $_
    $drives = "ASSOCIATORS OF " +
              "{Win32_DiskPartition.DeviceID='$($partition.DeviceID)'} " +
              "WHERE AssocClass = Win32_LogicalDiskToPartition"
    Get-WmiObject -Query $drives | ForEach-Object {
      $driveLetter = $_.DeviceID
      $fltr        = "DriveLetter='$driveLetter'"
      New-Object -Type PSCustomObject -Property @{
        Disk        = $disk.DeviceID
        DriveLetter = $driveLetter
        VolumeName  = $_.VolumeName
        VolumeID    = Get-WmiObject -Class Win32_Volume -Filter $fltr |
                      Select-Object -Expand DeviceID
      }
    }
  }
}

Otherwise it doesn't seem possible with WMI.

On Windows 8/Server 2012 or newer you could use the Get-Partition cmdlet, though:

Get-Partition | Select-Object DiskNumber, DriveLetter, @{n='VolumeID';e={
  $_.AccessPaths | Where-Object { $_ -like '\\?\volume*' }
}}
Ansgar Wiechers
  • 193,178
  • 25
  • 254
  • 328
  • The server in question is 2008 R2 and there are a few drive letters, but several reparse points. Thus, my initial comment about the partition class not being the link to bridge the other classes together. – Galvatron Mar 10 '16 at 00:49
  • See the referenced article. – Ansgar Wiechers Mar 10 '16 at 08:15
0

I have done a script that collects the most important stuff from volume and disk WMI. its used with getting information from a Remote Desktop server where a lot of disks are mounted but can be hard to find who is using which disk. its using AD to query the user and connect it with the SID to find the file path. so its a matter of first collecting all the data from the different disk commands and then combine the outputs. the most important command to bind disk data with volume data is the get-partition that shows deviceid

Function Get-VHDMount {

[cmdletbinding()]

Param(
  [Parameter(Position=0,ValueFromPipeline=$True)]
  [ValidateNotNullorEmpty()] 
  [OBJECT[]]$Computername,
  [STRING]$RDSPATH = '\\rdsprofiles'
)
    foreach ($computer in $Computername) {

        $RDSItems      = (Get-ChildItem $RDSPATH -Recurse -Filter *.vhdx)
        $VolumeInfo    = invoke-command -ComputerName $computer -scriptblock  {Get-Volume | select *}
        $VHDMountInfo  = Get-WmiObject Win32_Volume -ComputerName $computer |where Label -eq 'user Disk' 
        $partitioninfo = invoke-command -ComputerName $computer -scriptblock  {Get-Partition | Select-Object DiskNumber, @{n='VolumeID';e={$_.AccessPaths | Where-Object { $_ -like '\\?\volume*' }}}}

        foreach ($VHDmount in $VHDMountInfo) {
            $adinfo = Get-ADUser ($VHDmount.name | Split-Path -Leaf)

            [PSCUSTOMOBJECT]@{
                Computername = $computer
                username     = $VHDmount.name | Split-Path -Leaf
                displayname  = $adinfo.name
                SID          = $adinfo.SID
                deviceid     = $VHDmount.deviceid
                capacity     = ([MATH]::ROUND(($VHDmount.capacity) / 1gb))
                HealthStatus = ($VolumeInfo | where ObjectId -eq ($VHDmount.deviceid)).HealthStatus
                DiskNumber   = ($partitioninfo | where Volumeid -eq ($VHDmount.deviceid)).DiskNumber
                Path         = ($RDSItems | where fullname -like "*$($adinfo.SID)*").FullName
            }
        }
    }
}
Mock
  • 1
  • 1