Matching OS Drive Letters to VM Disks is definitely something each VMware admin has wanted at some point or another. Unfortunately, it is not the easiest of tasks. Using a suggestion I found in one of the forum posts that the solution might be a combination of two different scripts referenced here and here, I decided to try it out.

After combining and editing the scripts a bit it seems to work really well for me, although I am sure individual results may vary. Anyway here is the script…

 


$DiskInfo= @()
$Vm = "vmname"

$i=0


$disks=Get-VM $vm| Get-HardDisk -DiskType "RawPhysical","RawVirtual"
$logtopart=Get-WmiObject -Class Win32_LogicalDiskToPartition -computername $VM 
$disktopart=Get-WmiObject Win32_DiskDriveToDiskPartition -computername $VM 
$logical=get-wmiobject win32_logicaldisk -computername $Vm
$volume=get-wmiobject win32_volume -computername $Vm
$partition=get-wmiobject win32_diskpartition -computername $Vm
if (($VmView = Get-View -ViewType VirtualMachine -Filter @{"Name" = $Vm})) {
    $WinDisks = Get-WmiObject -Class Win32_DiskDrive -ComputerName $VmView.Name
    foreach ($VirtualSCSIController in ($VMView.Config.Hardware.Device | where {$_.DeviceInfo.Label -match "SCSI Controller"})) {
        foreach ($VirtualDiskDevice in ($VMView.Config.Hardware.Device | where {$_.ControllerKey -eq $VirtualSCSIController.Key})) {
            $VirtualDisk = "" | Select SCSIController, DiskName, SCSI_Id, DiskFile,  DiskSize, WindowsDisk, NAA,drive, volumename
            $VirtualDisk.SCSIController = $VirtualSCSIController.DeviceInfo.Label
            $VirtualDisk.DiskName = $VirtualDiskDevice.DeviceInfo.Label
            $VirtualDisk.SCSI_Id = "$($VirtualSCSIController.BusNumber) : $($VirtualDiskDevice.UnitNumber)"
            $VirtualDisk.DiskFile = $VirtualDiskDevice.Backing.FileName
            $VirtualDisk.DiskSize = $VirtualDiskDevice.CapacityInKB * 1KB / 1GB
            $virtualdisk.naa=$disks|? {$_.name -like $VirtualDiskDevice.DeviceInfo.Label}|select -expand scsicanonicalname




            # Match disks based on SCSI ID
            $DiskMatch = $WinDisks | ?{($_.SCSIPort -2 ) -eq $VirtualSCSIController.BusNumber -and $_.SCSITargetID -eq $VirtualDiskDevice.UnitNumber}
            if ($DiskMatch){
                $VirtualDisk.WindowsDisk = "Disk $($DiskMatch.Index)"
            $i++
            }
            else {Write-Host "No matching Windows disk found for SCSI id $($VirtualDisk.SCSI_Id)"}
            

            $matchdisktopar=$disktopart|Where {$_.Antecedent -eq $diskmatch.__Path}
             $matchlogtopart=$logtopart| Where {$_.Antecedent -eq $matchdisktopar.Dependent}
             $logicalmatch=$logical| where {$_.path.path -eq $matchlogtopart.dependent}
             $VirtualDisk.volumename=$logicalmatch.volumename
             $virtualdisk.drive=$logicalmatch.deviceid


             $DiskInfo += $VirtualDisk
        }
    }
    $DiskInfo | Out-GridView
}
else {Write-Host "VM $Vm Not Found"}

A couple things to note, you obviously need WMI open on the target windows machine, and the permissions to perform WMI calls against said machine.

Here is how it looks once completed.

 

 

The NAA is blank because none of these disks are RDMs, otherwise, NAA would be populated as well. Also for some reason it is not grabbing the C drive….might have to look at that.

 

Regardless it is pretty handy to have in the back pocket when you need it.

 

Let me know what you think


9 Comments

Luke · April 27, 2017 at 12:43 pm

This is a great script. Where you ever able to actually find a way to use the line “$volume=get-wmiobject win32_volume -computername $Vm” to match the volume name with the disks?

cengizulusahin · December 19, 2017 at 10:53 am

The script doesn’t produce accurate results with VMs which have multiple SCSI controllers, tried with a VM which has 3 SCSI controllers, output was incorrect. Not sure if the script can be altered to fix this issue.

Marian · June 27, 2018 at 1:18 am

Just a specification

to work with Win10 or Win Server 2016, -2 needs to be changed to -0 in

$DiskMatch = $WinDisks | ?{($_.SCSIPort -2 ) -eq $VirtualSCSIController.BusNumber -and $_.SCSITargetID -eq $VirtualDiskDevice.UnitNumber}

Colten Krauter · August 22, 2018 at 8:14 am

First, thanks so much for writing this! I had no idea that we could use the SCSI_Id to match drives like that, but it works like a charm.

The reason the C: drive was not being found was that the line
$matchdisktopar=$disktopart|Where {$_.Antecedent -eq $diskmatch.__Path}
doesn’t realize that the $_.Antecedent for PhysicalDisk0 (for example) may return more than one match (likely due to hidden file system or boot partitions etc.) So the way to ensure that you use the correct match is to pick a specific partition and then ensure that the match has a corresponding drive letter – if it doesn’t than try the next partition…

Here is a slightly modified version of your script,

$i = 0

$disks=Get-VM $vm| Get-HardDisk -DiskType “RawPhysical”,”RawVirtual”
$logtopart=Get-WmiObject -Class Win32_LogicalDiskToPartition -computername $VM -Credential $creds
$disktopart=Get-WmiObject Win32_DiskDriveToDiskPartition -computername $VM -Credential $creds
$logical=get-wmiobject win32_logicaldisk -computername $Vm -Credential $creds
$volume=get-wmiobject win32_volume -computername $Vm -Credential $creds
$partition=get-wmiobject win32_diskpartition -computername $Vm -Credential $creds

if (($VmView = Get-View -ViewType VirtualMachine -Filter @{“Name” = $Vm})) {
$WinDisks = Get-WmiObject -Class Win32_DiskDrive -ComputerName $VmView.Name -Credential $creds
foreach ($VirtualSCSIController in ($VMView.Config.Hardware.Device | where {$_.DeviceInfo.Label -match “SCSI Controller”})) {
foreach ($VirtualDiskDevice in ($VMView.Config.Hardware.Device | where {$_.ControllerKey -eq $VirtualSCSIController.Key})) {
# To use propert name with spaces in it: @{N=”Cluster”; E={$_.VMHost.Parent.Name}}
# N is name and E is expression
$VirtualDisk = “” | Select DriveLetter, vSphereDiskName, DiskSize, WindowsDisk, FileSystem

$VirtualDisk.vSphereDiskName = $VirtualDiskDevice.DeviceInfo.Label
$VirtualDisk.DiskSize = $VirtualDiskDevice.CapacityInKB * 1KB / 1GB

# Match disks based on SCSI ID
$DiskMatch = $WinDisks | ?{($_.SCSIPort -2 ) -eq $VirtualSCSIController.BusNumber -and $_.SCSITargetID -eq $VirtualDiskDevice.UnitNumber}
if ($DiskMatch) {
$VirtualDisk.WindowsDisk = “Disk $($DiskMatch.Index)”
$i++
}
else {
Write-Host “No matching Windows disk found for SCSI id $($VirtualDisk.SCSI_Id)”
}

$partitionNumber = 0
foreach ($part in $disktopart | Where {$_.Antecedent -eq $diskmatch.__Path}) {
$matchdisktopart = $disktopart | Where {$_.Antecedent -eq $diskmatch.__Path -and $_.Dependent -Match “Partition #$($partitionNumber)”}
$matchlogtopart = $logtopart | Where {$_.Antecedent -eq $matchdisktopart.Dependent}
$logicalmatch = $logical | where {$_.path.path -eq $matchlogtopart.dependent}
$virtualdisk.driveLetter = $logicalmatch.deviceid
$virtualdisk.FileSystem = $logicalmatch.FileSystem

if ($virtualdisk.driveLetter) {
Write-Host “Partition #$($partitionNumber) corresponds to $($virtualdisk.driveLetter)”

# If the partition corresponds to a drive letter then continue out of the loop
continue
}
else {
$partitionNumber++;
}
}

$DiskInfo += $VirtualDisk
}
}
$DiskInfo | ft -AutoSize
}
else {
Write-Host “VM $Vm Not Found”
}

Per · September 20, 2018 at 4:21 pm

Nice, thanks this one helped me in my need to match vmware datastore -> vmware disk (with size,thick,thin) -> windows disk (with filesystem size). The problem with the C drive was in my case multiple partitions on a logical drive

#check for multiple partitions on disk
if ($matchdisktopar.count -gt 1) {
#Not nice… but first partition is in our env the boot partition, just leave it out
$matchlogtopart=$logtopart| Where {$_.Antecedent -eq $matchdisktopar[1].Dependent}
} else {
$matchlogtopart=$logtopart| Where {$_.Antecedent -eq $matchdisktopar.Dependent}
}

Ankit · March 10, 2019 at 6:32 pm

This script is not working when there are multiple SCSI controller

Tharun NC · August 1, 2019 at 1:42 am

Hi ,

My VM and the vcenter are in different domain and because of that i am not able to connect to vm and it is telling access denied.

Could you please rewrite the script, so it will ask credentials to while connecting to the VM.

Paul · August 1, 2019 at 12:00 pm

For some reason Im getting permission denied.
Get-WmiObject : Access is denied. (Exception from HRESULT: 0x80070005 (E_ACCESSDENIED))
At line:19 char:12
+ $logtopart=Get-WmiObject -Class Win32_LogicalDiskToPartition -compute …
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [Get-WmiObject], UnauthorizedAccessException
+ FullyQualifiedErrorId : System.UnauthorizedAccessException,Microsoft.PowerShell.Commands.GetWmiObjectCommand

Get-WmiObject : Access is denied. (Exception from HRESULT: 0x80070005 (E_ACCESSDENIED))
At line:20 char:13
+ $disktopart=Get-WmiObject Win32_DiskDriveToDiskPartition -computernam …
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [Get-WmiObject], UnauthorizedAccessException
+ FullyQualifiedErrorId : System.UnauthorizedAccessException,Microsoft.PowerShell.Commands.GetWmiObjectCommand

get-wmiobject : Access is denied. (Exception from HRESULT: 0x80070005 (E_ACCESSDENIED))
At line:21 char:10
+ $logical=get-wmiobject win32_logicaldisk -computername $Vm
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [Get-WmiObject], UnauthorizedAccessException
+ FullyQualifiedErrorId : System.UnauthorizedAccessException,Microsoft.PowerShell.Commands.GetWmiObjectCommand

get-wmiobject : Access is denied. (Exception from HRESULT: 0x80070005 (E_ACCESSDENIED))
At line:22 char:9
+ $volume=get-wmiobject win32_volume -computername $Vm
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [Get-WmiObject], UnauthorizedAccessException
+ FullyQualifiedErrorId : System.UnauthorizedAccessException,Microsoft.PowerShell.Commands.GetWmiObjectCommand

get-wmiobject : Access is denied. (Exception from HRESULT: 0x80070005 (E_ACCESSDENIED))
At line:23 char:12
+ $partition=get-wmiobject win32_diskpartition -computername $Vm
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [Get-WmiObject], UnauthorizedAccessException
+ FullyQualifiedErrorId : System.UnauthorizedAccessException,Microsoft.PowerShell.Commands.GetWmiObjectCommand

Get-WmiObject : Access is denied. (Exception from HRESULT: 0x80070005 (E_ACCESSDENIED))
At line:25 char:17
+ … $WinDisks = Get-WmiObject -Class Win32_DiskDrive -ComputerName $VmVie …
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [Get-WmiObject], UnauthorizedAccessException
+ FullyQualifiedErrorId : System.UnauthorizedAccessException,Microsoft.PowerShell.Commands.GetWmiObjectCommand

No matching Windows disk found for SCSI id 0 : 0
No matching Windows disk found for SCSI id 0 : 1
No matching Windows disk found for SCSI id 1 : 0
No matching Windows disk found for SCSI id 1 : 1
No matching Windows disk found for SCSI id 1 : 2
No matching Windows disk found for SCSI id 2 : 0

Mayur Parmar · July 10, 2020 at 3:55 pm

Thanks alot.
It saved a lot of time to find NAA id of RDM in Windows Server.

Leave a Reply