Here is my final version of the script in case anybody wants to reference it:
# Load PowerCLI Plugin and connect to VCenter Server (Put in your FQDN where it says YOURVCENTERSERVERNAME)
Import-Module VMware.VimAutomation.Core -ErrorAction SilentlyContinue
connect-viserver YOURVCENTERSERVERNAME
# User with permission to query the WMI on the guest
$cred = if ($cred){$cred}else{Get-Credential}
# CSV file with a column named vmName
Import-Csv -Path .\vmnames.csv -UseCulture -PipelineVariable row |
ForEach-Object -Process {
$vm = Get-VM -Name $row.vmName
# If the script can't determine the FQDN of the Guest OS, the VM is skipped
$winHostName = ''
if($vm.Guest.State -eq 'Running'){
if($vm.Guest.HostName -ne ''){
$WinHostName = $vm.Guest.HostName
}
elseif($vm.Guest.IPAddress){
$resolve = Resolve-DnsName -Name $vm.guest.IPAddress[0]
if($resolve){
$WinHostName = $resolve.NameHost
}
}
}
if($winHostName){
$vmDisks = Get-HardDisk -VM $vm | Sort-Object -Property Name
$vmDatacenterView = Get-Datacenter -VM $vm | Get-View
$virtualDiskManager = Get-View -Id VirtualDiskManager-virtualDiskManager
# Getting the list of Windows disks and partitions using WMI
$winDisk = Get-WmiObject -Class Win32_DiskDrive -ComputerName $WinHostName -Credential $cred
$diskToDriveVolume = Get-WmiObject Win32_DiskDrive -ComputerName $WinHostName -Credential $cred| % {
$disk = $_
$partitions = "ASSOCIATORS OF " +
"{Win32_DiskDrive.DeviceID='$($disk.DeviceID)'} " +
"WHERE AssocClass = Win32_DiskDriveToDiskPartition"
Get-WmiObject -Query $partitions -ComputerName $WinHostName -Credential $cred| % {
$partition = $_
$drives = "ASSOCIATORS OF " +
"{Win32_DiskPartition.DeviceID='$($partition.DeviceID)'} " +
"WHERE AssocClass = Win32_LogicalDiskToPartition"
Get-WmiObject -Query $drives -ComputerName $WinHostName -Credential $cred| % {
New-Object -Type PSCustomObject -Property @{
Disk = $disk.DeviceID
DriveLetter = $_.DeviceID
VolumeName = $_.VolumeName
}
}
}
}
#Getting a disk serial number
foreach ($disk in $winDisk)
{
$disk | Add-Member -MemberType NoteProperty -Name AltSerialNumber -Value $null
$diskSerialNumber = $disk.SerialNumber
if ($disk.Model -notmatch 'VMware Virtual disk SCSI Disk Device')
{
if ($diskSerialNumber -match '^\S{12}$'){$diskSerialNumber = ($diskSerialNumber | foreach {[byte[]]$bytes = $_.ToCharArray(); $bytes | foreach {$_.ToString('x2')} } ) -join ''}
$disk.AltSerialNumber = $diskSerialNumber
}
}
#Searching all VM disks and matching them with Windows disks by their SerialNumber / UUID
foreach ($vmDisk in $vmDisks)
{
$vmDiskUuid = $virtualDiskManager.queryvirtualdiskuuid($vmDisk.Filename, $vmDatacenterView.MoRef) | foreach {$_.replace(' ','').replace('-','')}
$windowsDisk = $winDisk | where {$_.SerialNumber -eq $vmDiskUuid}
if (-not $windowsDisk){
$windowsDisk = $winDisk | where {$_.AltSerialNumber -eq $vmDisk.ScsiCanonicalName.substring(12,24)}
}
$ctrl = $vm.ExtensionData.Config.Hardware.Device | where{$_.Key -eq $vmDisk.ExtensionData.ControllerKey}
$curDiskMap = "" | select vmDiskDatastore, vmDiskVmdk, SCSIAddress, vmDiskName, windowsDiskIndex, vmDiskUuid, windowsDeviceID, drives, volumes
$driveVolumes = $diskToDriveVolume | where {$_.Disk -eq $windowsDisk.DeviceID}
New-Object -TypeName PSObject -Property ([ordered]@{
VM = $vm.Name
vmDiskDatastore = $vmDisk.filename.split(']')[0].split('[')[1]
vmDiskVmdk = $vmDisk.filename.split(']')[1].trim()
SCSIAddress = "SCSI($($ctrl.BusNumber):$($vmDisk.ExtensionData.UnitNumber))"
vmDiskName = $vmDisk.Name
vmDiskSizeGB = $vmDisk.CapacityGB
windowsDiskIndex = if ($windowsDisk){$windowsDisk.Index}else{"FAILED TO MATCH"}
vmDiskUuid = $vmDiskUuid
windowsDeviceID = if ($windowsDisk){$windowsDisk.DeviceID}else{"FAILED TO MATCH"}
drives = $driveVolumes.DriveLetter
volumes = $driveVolumes.VolumeName
})
}
}
else{
Write-Host "Could not determine FQDN for VM ($vm.Name)"
}
} | Export-Csv -Path .\report.csv -NoTypeInformation -UseCulture
Make sure when you're running the PowerShell script that you are in the working directory first where the vmnames.csv file resides. Otherwise it'll complain it can't find the vmnames.csv file. All of the VMs you want to run this against need to go in this file. This will also be the same directory that the report.csv exports to.
You can do a search and export the list of VMs from the Virtual Machines view in vCenter so you don't have to type them all out by hand if you have a lot.
Another issue I had was some VMs were affected by a vSphere 6.5 bug where the "disk.EnableUUID = "TRUE" value was missing from multiple vmx configuration files. I'll have to go back and fix that on those VMs. Without that value the Uuid is not exposed to the Guest OS. Therefore, it can't match the drives up.
You can reference that KB article here.
https://kb.vmware.com/s/article/52815
Finally, As mentioned. This is not a fool proof method and only works under the right conditions. Your mileage may vary.
HUGE THANKS to . I wouldn't have even known where to begin (or end) without his help!