Using PowerCLI, I can list datastore and vmdk info like this...
CapacityGB Persistence Filename
136.729 Persistent [L1OSSTORE_T2_01] JUNO/JUNO_2.vmd
100.000 Persistent [L1DATASTORE_T2_01] JUNO/JUNO_1.vmdk
Using Powersell, for each VM, I can list Windows volumes like this...
DriveLetter FileSystemLabel FileSystem DriveType
F Backups NTFS Fixed
D Databases NTFS Fixed
L LOGS NTFS Fixed
V SnapInfo NTFS Fixed
S SYSDB NTFS Fixed
T TempDB NTFS Fixed
C sys NTFS Fixed
Is there a way to combine the two datasets into one to show the mapping from the host, including LUNS, to the vm volumes/drives?
On the risk of opening up the same can of worms again, no you can't do this in a fool-proof way I'm afraid.
There have been posts that work in certain situations, but it will definitely not work on all occasions (especially if you start juggling VMDK around and having multiple guest OS partitions (including empty ones with unknown partition types) on the same VMDK).
Feel free to search this community, there might be a few methods that could work for your specific environment.
We have included one such method in the scripts that come with the PowerCLI Reference book, see Listing 8.4 on the FTP site
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
Thanks LucD. I tried out the 8.4 script but it bombed at the beginning for a reason I don't understand. By the way, I saw somewhere that VMware supports an API via Python? If so, how mature is that as a strategy compared to PowerCLI? Is Powershell/PowerCLI seen as less of a priority these days in terms of development/investment?
Cheers.
Get-vm Juno | Get-VMDiskMapping
cmdlet Get-VMDiskMapping at command pipeline position 2
Supply values for the following parameters:
Get-VMDiskMapping : The input object cannot be bound to any parameters for the command either because the command does not take pipeline input or the input and its properties do not match any of the parameters that take pipeline input.
At line:146 char:15
+ Get-vm Juno | Get-VMDiskMapping
+ ~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (JUNO:PSObject) [Get-VMDiskMapping], ParameterBindingException
+ FullyQualifiedErrorId : InputObjectNotBound,Get-VMDiskMapping
I assume you are running the function under PowerCLI 6.5x?
In that case the function would need some changes.
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
LucD, yes, PoweCLI 6.5
This version should work under PowerCLI 6.5.
But, again, this method is not foolproof, and with Windows Server 2016 it will not work.
function Get-VMDiskMapping
{
<#
.SYNOPSIS
Creates a report to match Windows disk numbers and their
virtual disk counterparts.
.DESCRIPTION
This function creates an overview of the virtual machine's
virtual disks and their Windows counterparts.
.NOTES
Source: Automating vSphere Administration
Authors: Luc Dekens, Arnim van Lieshout, Jonathan Medd,
Alan Renouf, Glenn Sizemore
.PARAMETER VM
Specify the virtual machine to report on.
.PARAMETER HostCredential
Specify a PSCredential object containing the credentials you
want to use for authenticating with the host.
.PARAMETER GuestCredential
Specify a PSCredential object containing the credentials you
want to use for authenticating with the VM guest OS.
.EXAMPLE
PS> Get-VM VM001 | Get-VMDiskMapping
.EXAMPLE
PS> Get-VM VM001 | Get-VMDiskMapping -hostCredential $hostCred -guestCredential $guestCred | Out-GridView
#>
Param (
[parameter(ValueFromPipeline = $true, Mandatory = $true)]
[VMware.VimAutomation.ViCore.Types.V1.Inventory.VirtualMachine]$VM,
[System.Management.Automation.PSCredential]$hostCredential,
[System.Management.Automation.PSCredential]$guestCredential
)
#Create vbs scriptfile
$FileName = [System.IO.Path]::GetTempFileName()
‘Set objReg = GetObject(“winmgmts:{impersonationLevel=impersonate}!\\.\root\default:StdRegProv”)’ > $filename
‘Set objWMI = GetObject(“winmgmts:{impersonationLevel=impersonate}!\\.\root\cimv2”)’ >> $filename
‘Set colPCISlotNumber = CreateObject(“Scripting.Dictionary”)’ >> $filename
‘objReg.EnumKey &H80000002,”SYSTEM\CurrentControlSet\Enum\PCI”, colHardwareId’ >> $filename
‘For Each HardwareId In colHardwareId’ >> $filename
‘ objReg.EnumKey &H80000002,”SYSTEM\CurrentControlSet\Enum\PCI\” & HardwareId, colControllerId’ >> $filename
‘ For Each ControllerId In colControllerId’ >> $filename
‘ objReg.GetDWORDValue &H80000002,”SYSTEM\CurrentControlSet\Enum\PCI\” & HardwareId & “\” & ControllerId, “UINumber”, dwUINumber’ >> $filename
‘ colPCISlotNumber.Add “PCI\” & UCase(HardwareId) & “\” & UCase(ControllerId), dwUINumber’ >> $filename
‘ Next’ >> $filename
‘Next’ >> $filename
‘Set colDiskDrive = objWMI.ExecQuery(“Select * from Win32_DiskDrive”)’ >> $filename
‘Set colSCSIControllerDevice = objWMI.ExecQuery(“Select * from Win32_SCSIControllerDevice”)’ >> $filename
‘WScript.Echo “DiskPNPDeviceId,Index,SCSIPort,SCSITargetId,Size,CtrlPNPDeviceId,CtrlPCISlotNumber”’ >> $filename
‘For Each Disk in colDiskDrive’ >> $filename
‘ For Each item in colSCSIControllerDevice’ >> $filename
‘ If Replace(Split(item.Dependent,chr(34))(1),”\\”,”\”) = Disk.PNPDeviceId Then’ >> $filename
‘ CtrlPNPDeviceId = UCase(Replace(Split(item.Antecedent,chr(34))(1),”\\”,”\”))’ >> $filename
‘ Exit For’ >> $filename
‘ End If’ >> $filename
‘ Next’ >> $filename
‘ WScript.Echo Disk.PNPDeviceId & “,” & Disk.Index & “,” & Disk.SCSIPort & “,” & Disk.SCSITargetId & “,” & Disk.Size & “,” & CtrlPNPDeviceId & “,” & colPCISlotNumber.Item(CtrlPNPDeviceId)’ >> $filename
‘Next’ >> $filename
#Determine location to copy script to
$temp = Invoke-VMScript “echo %temp%” -vm $VM -HostCredential $hostCredential -GuestCredential $guestCredential -ScriptType “bat”
$destFileName = $temp.Trim(“`r`n”) + “\guestScsiInfo.vbs”
Copy-VMGuestFile -Source $FileName -Destination $destFileName -VM $VM -LocalToGuest -HostCredential $hostCredential -GuestCredential $guestCredential
Remove-Item $FileName
#Get Windows disk info
$error.Clear()
$Out = (Invoke-VMScript `
“cscript /nologo $destFileName && del $destFileName” `
-vm $VM -HostCredential $hostCredential `
-GuestCredential $guestCredential `
-ScriptType “bat”).ScriptOutput
if (!$error -and $Out)
{
$WinDisks = $Out | ConvertFrom-Csv
#Determine SCSIPort offset
$portOffset = ($WinDisks | Where-Object {$_.SCSIPort} | `
Measure-Object -Property SCSIPort -Minimum).Minimum
#All entries that don’t match any known pciSlotNumber are
#attached to scsi0. Change these entries to the pciSlotnumber
#of scsi0
$scsi0pciSlotNumber = ($VM.Extensiondata.Config.ExtraConfig | Where-Object{$_.key -like “scsi0.pciSlotNumber”}).value
$scsiPciSlotNumbers= @()
$VM.Extensiondata.Config.ExtraConfig | Where-Object {$_.key -like “scsi?.pciSlotNumber”} | ForEach-Object{
$scsiPciSlotNumbers += $_.value
}
$WinDisks | %{
if ($scsiPciSlotNumbers -notcontains $_.CtrlPCISlotNumber)
{
$_.CtrlPCISlotNumber = ($VM.ExtensionData.Config.Extraconfig | Where-Object{$_.key -like “scsi0.pciSlotNumber”}).value
}
}
#Create DiskMapping table
foreach ($VirtualSCSIController in ($VM.Extensiondata.Config.Hardware.Device | Where-Object {$_.DeviceInfo.Label -match “SCSI Controller”}))
{
foreach ($VirtualDiskDevice in ($VM.Extensiondata.Config.Hardware.Device | Where-Object {$_.ControllerKey -eq $VirtualSCSIController.Key}))
{
$VirtualDisk = New-Object PSObject -Property @{
VMSCSIController = $VirtualSCSIController.DeviceInfo.Label
VMDiskName = $VirtualDiskDevice.DeviceInfo.Label
SCSI_Id = “$($VirtualSCSIController.BusNumber) : $($VirtualDiskDevice.UnitNumber)”
VMDiskFile = $VirtualDiskDevice.Backing.FileName
VMDiskSizeGB = $VirtualDiskDevice.CapacityInKB * 1KB / 1GB
RawDeviceName = $VirtualDiskDevice.Backing.DeviceName
LunUuid = $VirtualDiskDevice.Backing.LunUuid
WindowsDisk = ""
WindowsDiskSizeGB = 0
}
#Match disks
if ([int]$vm.version.ToString().Replace("v","") -lt 7)
{
#For hardware v4 match disks based on controller’s SCSIPort an disk’s SCSITargetId.
#Not supported with mixed scsi adapter types.
$DiskMatch = $WinDisks | Where-Object {($_.SCSIPort – $portOffset) -eq $VirtualSCSIController.BusNumber -and $_.SCSITargetID -eq $VirtualDiskDevice.UnitNumber}
}
else
{
#For hardware v7 match disks based on controller’s pciSlotNumber and disk’s SCSITargetId
$DiskMatch = $WinDisks | Where-Object {$_.CtrlPCISlotNumber -eq ($VM.Extensiondata.Config.Extraconfig |
Where-Object {$_.key -match “scsi$($VirtualSCSIController.BusNumber).pcislotnumber”}).value -and $_.SCSITargetID -eq $VirtualDiskDevice.UnitNumber}
}
if ($DiskMatch)
{
$VirtualDisk.WindowsDisk = “Disk $($DiskMatch.Index)”
$VirtualDisk.WindowsDiskSizeGB = $DiskMatch.Size / 1GB
}
else
{
Write-Warning “No matching Windows disk found for SCSI id $($virtualDisk.SCSI_Id)”
}
$VirtualDisk
}
}
}
else
{
Write-Error “Error Retrieving Windows disk info from guest”
}
}
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
Hi LucD,
Please help...How to save this file as ? Example as .ps1 or .psm1
How to import this function to the system ?
You can save this as a .ps1 file, then dot-source the file so the function is known to PowerShell.
Once done, you can use the function as a regular cmdlet, i.e. just call it by it;'s name (see the examples in the function)
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference