PowerCLI: Match VM and Windows harddisks – Part 2

This is a follow up on a post I did a couple of weeks ago to create a mapping table between Windows- and VMware hard disks. In another previous post PowerCLI: Get WMI info from isolated guests, I showed you how to get WMI info from a guest without using the guest’s network. I used this technique to enhance my mapping table script.

You need to login to both the ESX host and the Windows guest seperately, so there’s no more need for the user running the script to have administrator permissions on the guest. Multiple domains aren’t an issue anymore and neither are firewalls.

Remember: this only works when VMware Tools are installed

# This script requires PowerCLI 4.0 U1
#
# Create Disk Mapping Table v2.0
# Created by Arnim van Lieshout
# Http://www.van-lieshout.com

# Initialize variables
# $VCServerList is a comma-separated list of vCenter servers
$VCServerList = "vcenter01","vcenter02"
$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}

$Vm = Read-Host "Enter VMName to create disk mapping for"
if (($VmView = Get-View -ViewType VirtualMachine -Filter @{"Name" = $Vm})) {
    $ESXHost = Get-VMHost -id $VmView.Summary.Runtime.Host
    # Get credentials
    $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
    $Error.Clear()
    $Out = Invoke-VMScript "wmic path win32_diskdrive get Index, SCSIPort, SCSITargetId /format:csv" -vm $VM -HostCredential $HostCred -GuestCredential $GuestCred -scripttype "bat"
    if (!$error) {
        $FileName = [System.IO.Path]::GetTempFileName()
        $Out.Substring(2) > $FileName
        $WinDisks = Import-Csv $FileName
        Remove-Item $FileName

        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 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
            }
        }
        $DiskInfo | Out-GridView
    }
    else {Write-Host "Error Retrieving WMI info from guest"}
}
else {Write-Host "VM $Vm Not Found"}

Disconnect-VIServer * -Confirm:$false

Since I like using the VESI, I integrated the script into the EcoShell with just a few minor adjustments. You can also use PowerGUI instead.
Just create a new Script node and paste the following code:

if ($global:defaultviservers) {
    $DiskInfo= @()
    $Vm = Read-Host "Enter VMName to create disk mapping for"
    if (($VmView = Get-View -ViewType VirtualMachine -Filter @{"Name" = $Vm})) {
        $ESXHost = Get-VMHost -id $VmView.Summary.Runtime.Host
        $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", "", "")
        $Out = Invoke-VMScript "wmic path win32_diskdrive get Index, SCSIPort, SCSITargetId /format:csv" -vm $VM -HostCredential $HostCred -GuestCredential $GuestCred -scripttype "bat"
        $FileName = [System.IO.Path]::GetTempFileName()
        $Out.Substring(2) > $FileName
        $WinDisks = Import-Csv $FileName
        Remove-Item $FileName
        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
                $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
            }
        }
        $DiskInfo
    }
    else {[System.Windows.Forms.MessageBox]::Show("VM $Vm Not Found",'Virtual Machine not Found',[System.Windows.Forms.MessageBoxButtons]::OK,[System.Windows.Forms.MessageBoxIcon]::Information) | Out-Null}
}
Else {
    [System.Windows.Forms.MessageBox]::Show('You must connect to one or more hosts before you can use this node. Please click on the ''Managed Hosts'' node of the VMware PowerPack, connect to one or more of the servers you have configured there, and then try again.','Connection not established',[System.Windows.Forms.MessageBoxButtons]::OK,[System.Windows.Forms.MessageBoxIcon]::Information) | Out-Null
}

Or just download my VESI/PowerGui PowerPack.

Example output from the EcoShell:

Related posts:

  1. Match VM and Windows harddisks using PowerCLI Tweet Today I was asked to extend a disk of a Windows virtual machine. Normally this is a standard procedure and finished within minutes. The hardest part of the procedure...
  2. PowerCLI: Get WMI info from isolated guests Tweet A few weeks back I posted an article on matching Windows and VMware disks. Unfortunately this would work only if you could remotely query WMI information from that VM....
  3. Setting custom attributes with VMware PowerCLI Tweet Last week I wanted to extend my vCenter with some extra custom attributes on my VMs. This would extend the usability of the Export List feature for reporting purposes....
  4. List HBA WWPNs and LUNs using Powershell Tweet Lately I’m moving around my VMs and storage luns between my ESX clusters a lot to accomplish a complete redesign of my Virtual Infrastructure. At some point I got...
  5. How big is my VM? Tweet If you want to know the size of your vm, you probably first look at the size of the virtual disks in the vm’s settings, but there’s more to...

21 Comments on “PowerCLI: Match VM and Windows harddisks – Part 2”

  1. #1 Match VM and Windows harddisks using PowerShell | Arnim van Lieshout
    on Feb 3rd, 2010 at 11:50 pm

    [...] I recently made some improvements that get rid of these limitations. Read all about it in Match VM and Windows harddisks part 2. [...]

  2. #2 Michael Kahlke
    on Oct 20th, 2010 at 5:24 pm

    This algorithm works with vmx-04 but with the addition of the newer controllers in vmx-07 (LSI Logic SAS and Paravirtual) the offset to SCSIPort is no longer fixed at one, but can be anywhere from 0 to 3 from what I have seen. Has anyone encountered this, and if so, found a solution?

  3. #3 Albert Widjaja
    on Apr 5th, 2011 at 1:28 am

    Yes, this is a very2 good script and the most useful that I have ever found in the internet, however how can we know which Windows Disk/partitions it relates to ?

    The WindowsDisk column is confusing me :-|

  4. #4 A. Mikkelsen
    on Jun 27th, 2011 at 1:00 pm

    Hi,
    Great script if you are using 32 bit OS.
    It’s doesn’t work with ex. Win2008R2 :-(

    A. Mikkelsen

  5. #5 A. Mikkelsen
    on Jun 27th, 2011 at 2:32 pm

    An update
    To get it to work against a Win2008 64 Bit, just replace the line
    $Out = Invoke-VMScript “wmic path win32_diskdrive get Index, SCSIPort, SCSITargetId /format:csv” -vm $VM -HostCredential $HostCred -GuestCredential $GuestCred -scripttype “bat”

    with (Removing “path win32_”)

    $Out = Invoke-VMScript “wmic diskdrive get Index, SCSIPort, SCSITargetId /format:csv” -vm $VM -HostCredential $HostCred -GuestCredential $GuestCred -scripttype “bat”

  6. #6 Arnim van Lieshout
    on Jun 30th, 2011 at 1:17 pm

    There is an updated version of this function available in the PowerCLI Reference Book.
    Code is available for download.

  7. #7 Anders Mikkelsen
    on Jun 30th, 2011 at 2:17 pm

    Thanks,
    I just bought it, but still waiting for delevery.
    Do you know what chapter the code can be found in?

  8. #8 John Henry
    on Jun 30th, 2011 at 11:56 pm

    Where can I get the updated script Arnim ?
    Please share the URL here.

    Thanks.

  9. #9 Arnim van Lieshout
    on Jul 4th, 2011 at 10:33 pm

    Listing 7.4

  10. #10 Arnim van Lieshout
    on Jul 4th, 2011 at 10:34 pm

    Don’t know the exact URL. Search the wiley site. (or buy the book ;-) )

  11. #11 John Henry
    on Jul 5th, 2011 at 12:25 am

    Already done from Amazon and really love the book Arnim.

  12. #12 Larry
    on Mar 12th, 2012 at 4:54 pm

    I’m getting nothing but errors.

    3/12/2012 10:52:34 AM Invoke-VMScript The guest authentication being used does not have sufficient permissions to perform the operation. (Invoke-VMScript) At line: 11 char: 31

    The accounts used when prompted are ESX\root and a Domain Admin (for the guest). Also tried local admin.

    You cannot call a method on a null-valued expression. At line: 13 char: 23

    This one is related to $Out.Substring(2) > $FileName

  13. #13 Larry
    on Mar 12th, 2012 at 7:25 pm

    And getting the “Error Retrieving WMI info from guest”, even though I can manually retrieve WMI info with the same creds.

    This is incredibly frustrating.

  14. #14 Arnim van Lieshout
    on Mar 12th, 2012 at 10:41 pm

    The second error

    You cannot call a method on a null-valued expression. At line: 13 char: 23

    is generated, because the Invoke-VMscript didn’t return anything. So let’s focus on the Invoke-VMscript failure.
    Are VMware Tools installed and up-to-date?
    Are you running the latest version of PowerCLI?

  15. #15 Dave
    on Apr 5th, 2012 at 6:06 pm

    This may be a very simple question, but does this have to be done on the esx host, or can it be done on the guest OS?

  16. #16 Arnim van Lieshout
    on Apr 17th, 2012 at 11:23 pm

    This script runs against the vCenter server or ESX host.

  17. #17 John Henry
    on Apr 24th, 2012 at 7:49 am

    Hi Arnim,

    Is it possible to modify the script to show one more column which is the LUN ID number like in Manage Path properties ?

    THat’ll be very helpful.

    Cheers !

  18. #18 Jose Hernandez
    on Sep 10th, 2012 at 9:34 pm

    Any way to get rid of the 32-bit dependency to run this script? I’m using the updated one from wiley.com and it still requires you to launch a 32-bit PowerCLI instance.

  19. #19 Navil
    on Nov 12th, 2012 at 10:07 am

    I’ve got
    Timeout error while waiting for VMware Tools to start in the guest.
    probably because the version of VMware Tools is out of date

  20. #20 Mark
    on Mar 18th, 2013 at 11:17 pm

    Hi,

    Has anyone managed to get this working on Windows 2008 R2?

    I appear to be getting the following error “the remote server returned an error (403) Forbidden. (Invoke-VMscript).

    I have checked permissions, firewall, RPC services and everything appears to be correct.

    Thanks in advance.

    Mark

  21. #21 Theo
    on Feb 7th, 2014 at 8:44 pm

    It is close, but no cigar. I actually worked on this very issue with a level3 VM Storage Engineer for some time. His first solution failed. His second solution worked, but I have not figured out how to automate it. This solution is incomplete. I think it may be failing on the raw mappings, of which are my primary concern. It also may have trouble when the SCSI controllers no longer follow their original values. It finds about 12 of the drives and is unable to map about 12. What I have found to be fool proof is to do this and then match up the scsi0.pciSlotNumber = “160″ with the disk property Location Id from the disk management GUI. Like I said, it is a pain in the arse especially when you have tons of disks. I have created a feature request, but got nothing back yet.

    (I edited out most, but this shows controller location 160, Disk ID 1 which is exactly how it looks in the windows properties.)
    # grep scsi vmname.vmx|sort -u
    scsi0.pciSlotNumber = “160″
    scsi0:1.deviceType = “scsi-hardDisk”

Leave a Comment