AlbertWT
Virtuoso
Virtuoso

PowerCLI script to lists Windows Drive letter and VM Disk number in Data center ?

Jump to solution

Hi All,

Can anyone here please assist me with the powershell script if possible to list the VM information like the following format or in CSV format is OK:

SCSI (0:0) VM Hard Disk 1 [R5D23] PRODFSCLUS01-VM/PRODFSCLUS01-VM.vmdk - Windows C: drive - 60 GB

SCSI (1:1) VM Hard Disk 2 [NAS-D76] PRODFSCLUS01-VM/PRODFSCLUS01-VM.vmdk - Windows Q: drive - 1 GB

SCSI (1:2) VM Hard Disk 3 [NAS-D23] PRODFSCLUS01-VM/PRODFSCLUS01-VM.vmdk - Windows G: drive - 1.77 TB

SCSI (1:3) VM Hard Disk 4 [R5D52] PRODFSCLUS01-VM/PRODFSCLUS01-VM.vmdk - Windows H: drive - 1.77 GB

SCSI (1:4) VM Hard Disk 5 [NAS-D19] PRODFSCLUS01-VM/PRODFSCLUS01-VM.vmdk - Windows T: drive - 60 GB

Thanks in advance.

/* Any kind of comment or input would be greatly appreciated */
1 Solution

Accepted Solutions
LucD
Leadership
Leadership

Not sure if you have read my previous comments, but there is no fool-proof method to map Guest OS partitions/drives to VMDK files.

With Get-VMGuestDisk this has changed, but there are prerequisites.


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

View solution in original post

49 Replies
Prakas
Enthusiast
Enthusiast

The below pieces would help to grab the info

$VM = Get-VM

$VM.HardDisks | Select Name,Filename

$vmg = $VM | Get-VMGuest

$vmg.Disks | select Path,CapacityGB,FreeGB

LucD
Leadership
Leadership

If you don't have more than one guest OS partition on a VMDK, you can use something like this

$compName = 'MyVM'

$volTab = @{}

foreach($disk in (Get-CimInstance -ComputerName $compName -ClassName Win32_DiskDrive)){

    foreach($partition in (Get-CimAssociatedInstance -InputObject $disk -ResultClassName Win32_DiskPartition)){

        Get-CimAssociatedInstance -InputObject $partition -ResultClassName Win32_LogicalDisk | %{

            $volTab.Add("$($disk.SCSIBus):$($disk.SCSITargetId)",($_.DeviceID,$_.VolumeName -join '|'))

        }

    }

}

$vm = Get-VM -Name $compName

foreach($ctrl in Get-ScsiController -VM $vm){

    foreach($disk in (Get-HardDisk -VM $vm | where{$_.ExtensionData.ControllerKey -eq $ctrl.Key})){

        $obj = [ordered]@{

            VM = $vm.name

            HD = $disk.Name

            VMDK = $disk.Filename

            Device = "$($ctrl.ExtensionData.BusNumber):$($disk.ExtensionData.UnitNumber)"

            Drive = ""

            Label = ""

        }

        if($volTab.ContainsKey("$($ctrl.ExtensionData.BusNumber):$($disk.ExtensionData.UnitNumber)")){

            $obj.Drive = $volTab["$($ctrl.ExtensionData.BusNumber):$($disk.ExtensionData.UnitNumber)"].Split('|')[0]

            $obj.Label = $volTab["$($ctrl.ExtensionData.BusNumber):$($disk.ExtensionData.UnitNumber)"].Split('|')[1]

        }

        New-Object -TypeName PSObject -Property $obj

    }

}


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

AlbertWT
Virtuoso
Virtuoso

yes that's the one almost. .:smileygrin:

Somehow the Drive letter and label is still not populated ?

/* Any kind of comment or input would be greatly appreciated */
0 Kudos
AlbertWT
Virtuoso
Virtuoso

I've tried using:

#Example snippet to tie a Windows Volume to a VMware

#Define computername

    $computer = "PRODFS03-VM"

#Change this as needed.  Our standard display name is the hostname followed by a space...

    $VMView = Get-View -ViewType VirtualMachine -Filter @{'Name' = "$computer "}

#Thanks go to Richard Siddaway for the basic queries to tie diskdrive>partition>logicaldisk.

#http://itknowledgeexchange.techtarget.com/powershell/mapping-physical-drives-to-logical-drives-part-...

    $ServerDiskToVolume = @(

        Get-WmiObject -Class Win32_DiskDrive -ComputerName $computer | foreach {

       

            $Dsk = $_

            $query = "ASSOCIATORS OF {Win32_DiskDrive.DeviceID='$($_.DeviceID)'} WHERE ResultClass=Win32_DiskPartition"

       

            Get-WmiObject -Query $query -ComputerName $computer | foreach {

           

                $query = "ASSOCIATORS OF {Win32_DiskPartition.DeviceID='$($_.DeviceID)'} WHERE ResultClass=Win32_LogicalDisk"

           

                Get-WmiObject -Query $query -ComputerName $computer | Select DeviceID,

                    VolumeName,

                    @{ label = "SCSITarget"; expression = {$dsk.SCSITargetId} },

                    @{ label = "SCSIBus"; expression = {$dsk.SCSIBus} }

            }

        }

    )

# Now loop thru all the SCSI controllers on the VM and find those that match the Controller and Target

    $VMDisks = 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}))

        {

            #Build a custom object to hold this.  We use PS3 language...

            [pscustomobject]@{

                VM = $VM.Name

                HostName = $VMView.Guest.HostName

                PowerState = $VM.PowerState

                DiskFile = $VirtualDiskDevice.Backing.FileName

                DiskName = $VirtualDiskDevice.DeviceInfo.Label

                DiskSize = $VirtualDiskDevice.CapacityInKB * 1KB

                SCSIController = $VirtualSCSIController.BusNumber

                SCSITarget = $VirtualDiskDevice.UnitNumber

                DeviceID = $null

            }

       

            #Match up this VM to a logical disk

                $MatchingDisk = @( $ServerDiskToVolume | Where {$_.SCSITarget -like $VMSummary.SCSITarget -and $_.SCSIBus -like $VMSummary.SCSIController} )

           

            #Shouldn't happen, but just in case..

                if($MatchingDisk.count -gt 1)

                {

                    Write-Error "too many matches: $($MatchingDisk | select -property deviceid, partitions, SCSI* | out-string)"

                    $VMSummary.DeviceID = "Error: Too Many"

                }

                elseif($MatchingDisk.count -eq 1)

                {

                    $VMSummary.DeviceID = $MatchingDisk.DeviceID

                }

                else

                {

                    Write-Error "no match found"

                    $VMSummary.DeviceID = "Error: None found"

                }

            $VMSummary

        }

    }

but it is not returning any result ?

/* Any kind of comment or input would be greatly appreciated */
0 Kudos
LucD
Leadership
Leadership

That is in fact the script I replied to earlier, but that thread seems to have disappeared overnight :smileyconfused:

The script you mention is the pre-PSv3 way of doing it, in PSv3 the Get-CimAssociatedInstance  cmdlet was introdcued, which avoids these awful ASSOCIATORS queries.

If the drive letter and label are not there, that would mean that the WMI queries don't find the info.

What does this show for that specific VM ?

$compName = 'MyVM'

$volTab = @{}

foreach($disk in (Get-CimInstance -ComputerName $compName -ClassName Win32_DiskDrive)){

    foreach($partition in (Get-CimAssociatedInstance -InputObject $disk -ResultClassName Win32_DiskPartition)){

        Get-CimAssociatedInstance -InputObject $partition -ResultClassName Win32_LogicalDisk | %{

            $volTab.Add("$($disk.SCSIBus):$($disk.SCSITargetId)",($_.DeviceID,$_.VolumeName -join '|'))

        }

    }

}

$volTab.GetEnumerator()


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

0 Kudos
AlbertWT
Virtuoso
Virtuoso

LucD‌ it returns as follows:

Exception calling "Add" with "2" argument(s): "Item has already been added. Key in dictionary: '0:0'  Key being added: '0:0'"

At C:\Users\Admin\AppData\Local\Temp\b19a36b6-f1ed-4bff-bc63-f411d95c083d.ps1:8 char:45

+ ...            $volTab.Add("$($disk.SCSIBus):$($disk.SCSITargetId)",($_.D ...

+                                                ~~~~~~~~~~~~~~~~~~

    + CategoryInfo          : NotSpecified: (:) [], MethodInvocationException

    + FullyQualifiedErrorId : ArgumentException

Name                           Value                                                                                                                                                                                                  

----                           -----                                                                                                                                                                                                  

0:0                            C:|C-PRODFS03-VM    

/* Any kind of comment or input would be greatly appreciated */
0 Kudos
LucD
Leadership
Leadership

That seems to indicate that you have duplicate bus:scsiid entries on a VM, which shouldn't be possible.

What does this produce for that VM ?

$compName = 'MyVM'

foreach($disk in (Get-CimInstance -ComputerName $compName -ClassName Win32_DiskDrive)){

    foreach($partition in (Get-CimAssociatedInstance -InputObject $disk -ResultClassName Win32_DiskPartition)){

        Get-CimAssociatedInstance -InputObject $partition -ResultClassName Win32_LogicalDisk | %{

            Write-Output "$($disk.SCSIBus):$($disk.SCSITargetId) $($_.DeviceID) $($_.VolumeName)"

        }

    }

}


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

AlbertWT
Virtuoso
Virtuoso

LucD‌ the result is:

0:0 C: C-PRODFS03-VM

0:0 E: E-PRODFS03-VM

from the vSphere console I can see that the E: drive is on SCSI 1:0 not 0:0

same thing with the other VM:

0:0 C: C-PRODPXE01-VM

0:0 😧 D-OS IMAGES

All returns 0:0

/* Any kind of comment or input would be greatly appreciated */
0 Kudos
LucD
Leadership
Leadership

Can you check this variation ?

$compName = 'MyVM'

foreach($disk in (Get-CimInstance -ComputerName $compName -ClassName Win32_DiskDrive)){

    foreach($partition in (Get-CimAssociatedInstance -InputObject $disk -ResultClassName Win32_DiskPartition)){

        Get-CimAssociatedInstance -InputObject $partition -ResultClassName Win32_LogicalDisk | %{

            Write-Output "$($disk.SCSIPort-2):$($disk.SCSITargetId) $($_.DeviceID) $($_.VolumeName)"

        }

    }

}


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

AlbertWT
Virtuoso
Virtuoso

LucD‌ Yes it is getting better Luc,

The result now shows the SCSI ID better:

0:0 C: C-PRODFS03-VM

1:0 😧 D-PRODFS03-VM

Previously the 😧 drive is the same 0:0

/* Any kind of comment or input would be greatly appreciated */
0 Kudos
AlbertWT
Virtuoso
Virtuoso

LucD‌ this is the script that I've found somehwere in this forum:

$report = @()

foreach($vm in Get-VM -Name "PRODFS03-VM","PRODSQLDB02-VM" ){

    Get-HardDisk -VM $vm | ForEach-Object {

        $HardDisk = $_

        $row = "" | Select Hostname, VM, GuestName, Datastore, VMXpath, HardDisk, DiskType, CapacityGB, DiskUsage

                    $row.Hostname = $vm.Host.Name

                    $row.VM = $VM.Name

                    $row.GuestName = $vm.Guest.HostName

                    $row.Datastore = $HardDisk.Filename.Split("]")[0].TrimStart("[")

                    $row.VMXpath = $HardDisk.FileName

                    $row.HardDisk = $HardDisk.Name

                    $row.CapacityGB = ("{0:f1}" -f ($HardDisk.CapacityKB/1MB))

  $row.DiskType = $HardDisk.get_DiskType()

  $row.DiskUsage = $vm.get_UsedSpaceGB()

                    $report += $row

   }

 

}

$report | ft -AutoSize

This is the result from the script above:

What missing is the drive letter column that I'm interested to know if it is possible.

Result.JPG

Thanks so far for the assistance.

/* Any kind of comment or input would be greatly appreciated */
0 Kudos
LucD
Leadership
Leadership

Did you already combine that with the last script I gave in this thread ?


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

AlbertWT
Virtuoso
Virtuoso

LucD‌ ah I'm not sure how to combine it with your script hence I was just asking if it is possible :smileygrin:

/* Any kind of comment or input would be greatly appreciated */
0 Kudos
de2rfg
Enthusiast
Enthusiast

I'm also having problems to find or write a script that reports the VMDK, SCSI ID, Windows drive letters. The best I could find is the following;

VMware: matching guest drives to .vmdk files? - Ars Technica OpenForum

It works nicely as long as the VM has only a one SCSI controller. Any idea to modify the script to work with multipe SCSI controller?

VM       HostName              DiskFile                                      DiskName       DiskSize SCSIController SCSITarget DeviceID

--       --------              --------                                      --------       -------- -------------- ---------- --------

xxxx2019 xxxx2019      [xx_Tiering_LUN038] xxxx2019/xxxx2019.vmdk    Hard disk 1 42949672960              0          0 {D:, C:}

xxxx2019 xxxx2019      [xx_Tiering_LUN038] xxxx2019/xxxx2019_1.vmdk Hard disk 2 21474836480              1          0       

xxxx2019 xxxx2019      [xx_Tiering_LUN038] xxxx2019/xxxx2019_2.vmdk Hard disk 3 75161927680              1          1       

0 Kudos
de2rfg
Enthusiast
Enthusiast

I've now a solution that returns data for VM's with two SCSI Controller. Funny thing is that for at least one VM I still get wrong results. This VM has 4 controllers, but only 3 have attached disks. This seems to confuse the scrip.Not sure which other VM's might have false results.

VM:

HD1     SCSI  0 0

HD2     SCSI 1 0

HD3     SCSI 3 0  (note: not 2 0)

$ServerDiskToVolume: SCSI Bus is wrong for D drive. It should be 0 3.

DeviceID                                            VolumeName                                                                                  SCSITarget                                            SCSIBus

--------                                            ----------                                                                                  ----------                                            -------

😧                                                  xxxx_D                                                                                           0                                                  2

E:                                                  xxxx_E                                                                                           0                                                  1

C:                                                  xxxx_C                                                                                           0                                                  0

Thus in the script result D:is missing as Device ID.

VM       HostName           DiskFile                                               DiskName         DiskSize SCSIController SCSITarget DeviceID

--       --------           --------                                               --------         -------- -------------- ---------- --------

xxxx xxxx [xxxx_LUN048] xxxx/xxxx.vmdk   Hard disk 1   53687091200              0          0 C:     

xxxx xxxx [xxxx_LUN048] xxxx/xxxx_1.vmdk Hard disk 2 1503238553600              1          0 E:     

xxxx xxxx [xxxx_LUN048] xxxx/xxxx_3.vmdk Hard disk 3 1099511627776              3          0        

#Example snippet to tie a Windows Volume to a VMware

clear

$cred = Get-Credential -Credential "xxxx"

#Define computername

$computers = "xxxx"

foreach ($computer in $computers) {

Write $computer

#Change this as needed. Our standard display name is the hostname followed by a space...

$VMView = Get-VM -Name $computer | Get-View

$session = New-CimSession –ComputerName $computer -Credential $cred

$ServerDiskToVolume = @(

foreach($disk in (Get-CimInstance -CimSession $session -ClassName Win32_DiskDrive)){

    #Write-Output "Disk: " $disk

  foreach($partition in (Get-CimAssociatedInstance -CimSession $session -InputObject $disk -ResultClassName Win32_DiskPartition)){

        #Write-Output "Partition: " $partition

  Get-CimAssociatedInstance -CimSession $session -InputObject $partition -ResultClassName Win32_LogicalDisk | select DeviceID, VolumeName,

            #Write-Output "$($disk.SCSIPort-2):$($disk.SCSITargetId) $($_.DeviceID) $($_.VolumeName)"

  @{ label = "SCSITarget"; expression = {$disk.SCSITargetId} },

  @{ label = "SCSIBus"; expression = {$disk.SCSIPort-2} }

        }

    }

Remove-CimSession -Name  *

)

<# Commented out for later use.

$ServerDiskToVolume = @(

  Get-WmiObject -Credential $cred -Class Win32_DiskDrive -ComputerName $computer | foreach {

  $Dsk = $_

  $query = "ASSOCIATORS OF {Win32_DiskDrive.DeviceID='$($_.DeviceID)'} WHERE ResultClass=Win32_DiskPartition"

  Get-WmiObject -Credential $cred -Query $query -ComputerName $computer | foreach {

  $query = "ASSOCIATORS OF {Win32_DiskPartition.DeviceID='$($_.DeviceID)'} WHERE ResultClass=Win32_LogicalDisk"

  Get-WmiObject -Credential $cred -Query $query -ComputerName $computer | Select DeviceID,VolumeName,

  @{ label = "SCSITarget"; expression = {$dsk.SCSITargetId} },

  @{ label = "SCSIBus"; expression = {$dsk.SCSIPort-2} }

  }

  }

)

#>

Write-Output $ServerDiskToVolume

# Now loop thru all the SCSI controllers on the VM and find those that match the Controller and Target

$VMDisks = 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})) {

  #Match up this VM to a logical disk

  $MatchingDisk = @( $ServerDiskToVolume | Where {$_.SCSITarget -eq $VirtualDiskDevice.UnitNumber -and $_.SCSIBus -eq $VirtualSCSIController.BusNumber} )

  #Build a custom object to hold this. We use PS3 language...

  [pscustomobject]@{

  VM = $VMView.Name

  HostName = $VMView.Guest.HostName

  DiskFile = $VirtualDiskDevice.Backing.FileName

  DiskName = $VirtualDiskDevice.DeviceInfo.Label

  DiskSize = $VirtualDiskDevice.CapacityInKB * 1KB

  SCSIController = $VirtualSCSIController.BusNumber

  SCSITarget = $VirtualDiskDevice.UnitNumber

  DeviceID = $MatchingDisk.DeviceID

  }

  }

}

$VMDisks | ft -AutoSize #| out-file -append c:\Users\rfg\vm_disk.txt

}

0 Kudos
FMON
Enthusiast
Enthusiast

Look at something I posed a couple days ago:  How to trace a VM disk to a guest disk.

That should help you associate VMware disk to OS disk - should work any number of scsi adapters.  The methodology should work for any OS although the script I provided is for Windows.

That script does not address your requirement for needing to correlate drive letters to a disk.  But I do have some stuff that will do that in Windows as long as psremoting is enabled on your guest (drive letters don't need psremoting, but mountpoints do).  If you need help with that then post a new question and I'll try to assist this evening.

0 Kudos
bikashyadav
Contributor
Contributor

Hi LuCD,

In my environment CIM instance & WMI is not working as they are not enabled..

I tried the invoke-vmscript and it gives me the output without CIM Instance & WMI.

How can we modify the script and use 'Invoke-VMScript -VM $VM -ScriptType Powershell "Get-WmiObject -Class Win32_DiskDrive"'. 

Thanks

Bikash

0 Kudos
LucD
Leadership
Leadership

Do you mean remote WMI is disabled?

Otherwise it will not work via Invoke-VMScript either.

Btw, it should probably (and possible also provide guest credentials)

Invoke-VMScript -VM $VM -ScriptType Powershell -ScriptText "Get-WmiObject -Class Win32_DiskDrive"


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

0 Kudos
bikashyadav
Contributor
Contributor

HI LucD,

Below is the output i am getting. Only Invoke-VMScript is working. How can we modify the script and use Invoke-VMScript to have the same output.

PS C:\Users\Documents> Get-CimInstance -ComputerName $VM -ClassName Win32_DiskDrive
Get-CimInstance : The connection to the specified remote host was refused. Verify that the WS-Management service is running on the remote host and configured to listen
for requests on the correct port and HTTP URL.
At line:1 char:1
+ Get-CimInstance -ComputerName $VM -ClassName Win32_DiskDrive
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : ResourceBusy: (root\cimv2:Win32_DiskDrive:String) [Get-CimInstance], CimException
    + FullyQualifiedErrorId : HRESULT 0x80338112,Microsoft.Management.Infrastructure.CimCmdlets.GetCimInstanceCommand
    + PSComputerName        : XXXXX

PS C:\Users\Documents> Get-WmiObject -Class Win32_DiskDrive -ComputerName $VM
Get-WmiObject : The RPC server is unavailable. (Exception from HRESULT: 0x800706BA)
At line:1 char:1
+ Get-WmiObject -Class Win32_DiskDrive -ComputerName $VM
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (:) [Get-WmiObject], COMException
    + FullyQualifiedErrorId : GetWMICOMException,Microsoft.PowerShell.Commands.GetWmiObjectCommand

PS C:\Users\Documents> Invoke-Command -ComputerName $VM -ScriptBlock {Get-WmiObject -Class Win32_DiskDrive}
[XXXXX] Connecting to remote server XXXXX failed with the following error message : The connection to the specified remote host was refused. Verify that the
WS-Management service is running on the remote host and configured to listen for requests on the correct port and HTTP URL. For more information, see the
about_Remote_Troubleshooting Help topic.
    + CategoryInfo          : OpenError: (XXXXX:String) [], PSRemotingTransportException
    + FullyQualifiedErrorId : CannotConnectWinRMService,PSSessionStateBroken


PS C:\Users\Documents> Invoke-VMScript -VM $VM -ScriptType Powershell "Get-WmiObject -Class Win32_DiskDrive"

ScriptOutput
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
|  Partitions : 1
|  DeviceID   : \\.\PHYSICALDRIVE5
|  Model      : VMware Virtual disk SCSI Disk Device
|  Size       : 536864025600
|  Caption    : VMware Virtual disk SCSI Disk Device
|
|  Partitions : 1
|  DeviceID   : \\.\PHYSICALDRIVE7
|  Model      : VMware Virtual disk SCSI Disk Device
|  Size       : 644245056000
|  Caption    : VMware Virtual disk SCSI Disk Device
|
|  Partitions : 1
|  DeviceID   : \\.\PHYSICALDRIVE1
|  Model      : VMware Virtual disk SCSI Disk Device
|  Size       : 64420392960
|  Caption    : VMware Virtual disk SCSI Disk Device
|
|  Partitions : 1
|  DeviceID   : \\.\PHYSICALDRIVE10
|  Model      : VMware Virtual disk SCSI Disk Device
|  Size       : 1649267343360
|  Caption    : VMware Virtual disk SCSI Disk Device
|
|  Partitions : 1
|  DeviceID   : \\.\PHYSICALDRIVE4
|  Model      : VMware Virtual disk SCSI Disk Device
|  Size       : 53686402560
|  Caption    : VMware Virtual disk SCSI Disk Device

Thanks

Bikash

0 Kudos