VMware Cloud Community
zarty
Contributor
Contributor

PowerCLI Report VM host datastores to LUNs to Windows Volumes & Drives

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?

0 Kudos
7 Replies
LucD
Leadership
Leadership

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

0 Kudos
zarty
Contributor
Contributor

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      

0 Kudos
LucD
Leadership
Leadership

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

0 Kudos
zarty
Contributor
Contributor

LucD, yes, PoweCLI 6.5

0 Kudos
LucD
Leadership
Leadership

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

0 Kudos
ganapa2000
Hot Shot
Hot Shot

Hi LucD,

Please help...How to save this file as ? Example as .ps1 or .psm1

How to import this function to the system ?

0 Kudos
LucD
Leadership
Leadership

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

0 Kudos