DSCResources/POSHOrigin_vSphere_VM/Helpers/_GetGuestDiskToVMDiskMapping.ps1

# Based on https://communities.vmware.com/thread/528535?start=0&tstart=0

function _GetGuestDiskToVMDiskMapping {
    [cmdletbinding()]
    param (
        [Parameter(Mandatory)]
        [ValidateNotNull()]
        $VM,

        [Parameter(Mandatory)]
        [Microsoft.Management.Infrastructure.CimSession]$CimSession
    )

    try {
        $os = _GetGuestOS -CimSession $CimSession
        $vmView = $VM | Get-View -Verbose:$false -Debug:$false

        # Get the ESX host which the VM is currently running on
        $esxHost = Get-VMHost -Id $vmView.Summary.Runtime.Host -Verbose:$false

        $wmiDisks = Get-CimInstance -CimSession $CimSession -ClassName Win32_DiskDrive -Verbose:$false

        # Use 'Invoke-VMScript' to grab disk information WMI on the guest
        #$Out = Invoke-VMScript "wmic path win32_diskdrive get Index, SCSIPort, SCSITargetId /format:csv" -vm $VM -GuestCredential $guestCred -scripttype "bat"
        #$fileName = [System.IO.Path]::GetTempFileName()
        #$out.Substring(2) > $fileName
        #$wmiDisks = Import-Csv -Path $fileName
        #Remove-Item $fileName

        # Match the guest disks to the VM disks by SCSI bus number and unit number
        $diskInfo = @()
        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})) {

                $mapping = [pscustomobject]@{
                    SCSIController = $virtualSCSIController.DeviceInfo.Label
                    DiskName = $virtualDiskDevice.DeviceInfo.Label
                    SCSIId = "$($virtualSCSIController.BusNumber)`:$($virtualDiskDevice.UnitNumber)"
                    SCSIBus = $virtualSCSIController.BusNumber
                    SCSIUnit = $virtualDiskDevice.UnitNumber
                    DiskFile = $virtualDiskDevice.Backing.FileName
                    DiskSize = (($virtualDiskDevice.CapacityInKB * 1KB / 1GB)).ToInt32($Null)
                }

                # $mapping = new-object psobject
                # Add-Member -InputObject $mapping -MemberType NoteProperty -Name SCSIController -Value $virtualSCSIController.DeviceInfo.Label
                # Add-Member -InputObject $mapping -MemberType NoteProperty -Name DiskName -Value $virtualDiskDevice.DeviceInfo.Label
                # Add-Member -InputObject $mapping -MemberType NoteProperty -Name SCSIId -Value "$($virtualSCSIController.BusNumber)`:$($virtualDiskDevice.UnitNumber)"
                # Add-Member -InputObject $mapping -MemberType NoteProperty -Name SCSIBus -Value $($virtualSCSIController.BusNumber)
                # Add-Member -InputObject $mapping -MemberType NoteProperty -Name SCSIUnit -Value $($virtualDiskDevice.UnitNumber)
                # Add-Member -InputObject $mapping -MemberType NoteProperty -Name DiskFile -Value $virtualDiskDevice.Backing.FileName
                # Add-Member -InputObject $mapping -MemberType NoteProperty -Name DiskSize -Value (($virtualDiskDevice.CapacityInKB * 1KB / 1GB)).ToInt32($Null)

                #$match = $wmiDisks | Where-Object {([int]$_.SCSIPort - 2) -eq $virtualSCSIController.BusNumber -and [int]$_.SCSITargetID -eq $virtualDiskDevice.UnitNumber}
                $hasSerial = $true
                $match = $wmiDisks | where {$_.serialnumber -eq $virtualDiskDevice.backing.uuid.Replace('-','')}
                if (!$match) {
                    $hasSerial = $false
                    $match = $wmiDisks | Where-Object {([int]$_.SCSIPort - 2) -eq $virtualSCSIController.BusNumber -and [int]$_.SCSITargetID -eq $virtualDiskDevice.UnitNumber}
                }
                if ($match) {
                    Add-Member -InputObject $mapping -MemberType NoteProperty -Name WindowsDisk -Value $match.Index
                    Add-Member -InputObject $mapping -MemberType NoteProperty -Name HasSN -Value $hasSerial
                    Add-Member -InputObject $mapping -MemberType NoteProperty -Name SerialNumber -Value $match.SerialNumber
                    if ($os -lt 62) {
                        $partitions = Get-CimInstance -Query "ASSOCIATORS OF {Win32_DiskDrive.DeviceID=`"$($match.DeviceID.replace('\','\\'))`"} WHERE AssocClass = Win32_DiskDriveToDiskPartition" -CimSession $CimSession -Verbose:$false | Select -Property *

                        foreach($part in $partitions) {
                            $vols = Get-CimInstance -Query "ASSOCIATORS OF {Win32_DiskPartition.DeviceID=`"$($part.DeviceID)`"} WHERE AssocClass = Win32_LogicalDiskToPartition" -CimSession $CimSession -Verbose:$false | Select -Property *
                            foreach($vol in $vols) {
                               $tempVol = Get-CimInstance -ClassName Win32_Volume -CimSession $CimSession -Verbose:$false | Select -Property *
                               $tempMatch = $tempVol | Where-Object {$_.DriveLetter -eq $vol.DeviceID}
                                if ($tempMatch) {
                                    Add-Member -InputObject $mapping -MemberType NoteProperty -Name VolumeName -Value $tempMatch.DriveLetter.SubString(0,1)
                                    Add-Member -InputObject $mapping -MemberType NoteProperty -Name VolumeLabel -Value $tempMatch.Label
                                    Add-Member -InputObject $mapping -MemberType NoteProperty -Name BlockSize -Value $tempMatch.BlockSize
                                    Add-Member -InputObject $mapping -MemberType NoteProperty -Name Format -value $tempMatch.FileSystem
                                }
                            }
                        }
                    }
                    $diskInfo += $mapping
                } else {
                    Write-Verbose -Message "No matching Windows disk found for Serial Number [$($virtualDiskDevice.backing.uuid.Replace('-',''))] or SCSI ID [$($mapping.SCCIId)]"
                }
            }
        }
        return $diskInfo
    } catch {
        Write-Error -Message 'There was a problem getting the guest disk mapping'
        Write-Error -Message "$($_.InvocationInfo.ScriptName)($($_.InvocationInfo.ScriptLineNumber)): $($_.InvocationInfo.Line)"
        write-Error $_
    }
}