Need assistance in modifying Powershell script to list Windows Drive letter and VMDK on the datastore ?


I've got Powershell script below that I need your help to modify it so that it display the Windows Drive letter correctly with the correct VMDK, see the below script:

# This script requires PowerCLI 4.0 U1
# Create VM Disk Mapping v2.1
# Created by Arnim van Lieshout
# Http://
# Did you ever got a request to extend a disk on a VM?
# Most probably you were asked to extend Windows disk number x
# Unfortunately this Windows disk number doesn't correspond to the virtual disk number of your VM.
# Finding out which virtual disk in the VM's settings corresponds to this Windows disk can be a cumbersome task. 
# Especially when you have multiple SCSI controllers and/or many disks attached to your VM
# This script matches Windows disks and their VMware virtual disk counterparts.
# It uses the Invoke-VMScript cmdlet to retrieve WMI information from the Windows guest, so there is no network connection needed to the VM
# This makes the script suitable for isolated guests too (Internal only network, DMZ, or otherwise seperated by firewall).
# Multiple vCenter- or ESX(i)-servers can be added to the $VCServerList array, so there's no need to know which host or vCenter manages your VM

# Initialize variables
# $VCServerList is a comma-separated list of vCenter- or ESX(i)-servers
$VCServerList = "PROD-VCENTER-VM01"
$DiskInfo= @()

# Set Default Server Mode to Multiple
Set-PowerCLIConfiguration -DefaultVIServerMode Multiple -Confirm:$false | Out-Null
# Connect to vCenter Server(s)
foreach ($VCServer in $VCServerList) {Connect-VIServer -Server "$VCServer" | Out-Null}
# Ask for VM to create diskmapping for
$Vm = Read-Host "Enter VMName to create disk mapping for"
if (($VmView = Get-View -ViewType VirtualMachine -Filter @{"Name" = $Vm})) {
	# Get the ESX host which the VM is currently running on
	$ESXHost = Get-VMHost -id $VmView.Summary.Runtime.Host
	# Get credentials for host and guest
	$HostCred = $Host.UI.PromptForCredential("Please enter credentials", "Enter ESX host credentials for $ESXHost", "root", "")
	$GuestCred = $Host.UI.PromptForCredential("Please enter credentials", "Enter Guest credentials for $VM", "", "")

	#Get WMI info using Invoke-VMScript, so no network connection to the VM is needed
	$Out = Invoke-VMScript "wmic path win32_diskdrive get Index, SCSIPort, SCSITargetId /format:csv" -vm $VM -HostCredential $HostCred -GuestCredential $GuestCred -scripttype "bat"
	if (!$error) {
		#Export plaintext WMI disk info to temporary file and import it again using the Import-Csv CmdLet
		$FileName = [System.IO.Path]::GetTempFileName()
		$Out.Substring(2) > $FileName
		$WinDisks = Import-Csv $FileName
		Remove-Item $FileName
		#Create DiskMapping table
		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})) {
				$VirtualDisk = "" | Select SCSIController, DiskName, SCSI_Id, DiskFile,  DiskSize, WindowsDisk
				$VirtualDisk.SCSIController = $VirtualSCSIController.DeviceInfo.Label
				$VirtualDisk.DiskName = $VirtualDiskDevice.DeviceInfo.Label
				$VirtualDisk.SCSI_Id = "$($VirtualSCSIController.BusNumber) : $($VirtualDiskDevice.UnitNumber)"
				$VirtualDisk.DiskFile = $VirtualDiskDevice.Backing.FileName
				$VirtualDisk.DiskSize = $VirtualDiskDevice.CapacityInKB * 1KB / 1GB
				# Match disks based on Controller and SCSI ID
				$DiskMatch = $WinDisks | ?{($_.SCSIPort – 1) -eq $VirtualSCSIController.BusNumber -and $_.SCSITargetID -eq $VirtualDiskDevice.UnitNumber}
				if ($DiskMatch){
					$VirtualDisk.WindowsDisk = "Disk $($DiskMatch.Index)"
				else {Write-Host "No matching Windows disk found for SCSI id $($VirtualDisk.SCSI_Id)"}
				$DiskInfo += $VirtualDisk
		#Display DiskMapping table
		$DiskInfo | Out-GridView
	else {Write-Host "Error Retrieving WMI info from guest"}
else {Write-Host "VM $Vm Not Found"}

Disconnect-VIServer * -Confirm:$false

Open in new window

but somehow the result is misleading as can be seen from the screenshot below.

If the there are multiple drive letter with the same disk capacity size, then it is hard to point which VMDK is for which windows drive letter ?

Thanks in advance.
LVL 11
Senior IT System EngineerIT ProfessionalAsked:
Who is Participating?

[Product update] Infrastructure Analysis Tool is now available with Business Accounts.Learn More

I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

Sean Plemons Kelly, CISSPSecurity/Information Assurance EngineerCommented:

Take a look here.

Also found some code at this website:
#Example snippet to tie a Windows Volume to a VMware 

#Define computername
    $computer = "xxxx-db-01"

#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.
    $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,
                    @{ 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...
                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
                    Write-Error "no match found"
                    $VMSummary.DeviceID = "Error: None found"


Open in new window

Gives an output similar to:
VM                        HostName      PowerState DiskFile                                                DiskName       DiskSize SCSIController SCSITarget DeviceID
--                        --------      ---------- --------                                                --------       -------- -------------- ---------- --------
xxxx-DB-01 xxxxxxxxxxxxxx xxxxxxxxxxxx  PoweredOn  [ds-k00031] xxxx-DB-01 xxxxxxxxxxxxxx/xxxx-DB-01.vmdk   Hard disk 1 42949672960              0          0 C:      
xxxx-DB-01 xxxxxxxxxxxxxx xxxxxxxxxxxx  PoweredOn  [ds-k00031] xxxx-DB-01 xxxxxxxxxxxxxx/xxxx-DB-01_1.vmdk Hard disk 2 17179869184              0          1 D:      
xxxx-DB-01 xxxxxxxxxxxxxx xxxxxxxxxxxx  PoweredOn  [ds-k00031] xxxx-DB-01 xxxxxxxxxxxxxx/xxxx-DB-01_2.vmdk Hard disk 3 21474836480              0          2 E:      
xxxx-DB-01 xxxxxxxxxxxxxx xxxxxxxxxxxx  PoweredOn  [ds-k00031] xxxx-DB-01 xxxxxxxxxxxxxx/xxxx-DB-01_3.vmdk Hard disk 4 15032385536              0          3 F:      

Open in new window

I would consider bouncing your code off of what was posted at the second website.


Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
Senior IT System EngineerIT ProfessionalAuthor Commented:
Thanks !
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today

From novice to tech pro — start learning today.