VMware: Matching Attached vDisk UUID to Guest Windows HDD

Ever wanted to remove an unused hard drive from a VM without removing the wrong one?
Sometimes VMs will have multiple vDisks with the same size, making it difficult to determine which one is the drive in Windows you wanted to remove.

 

I present to you… a script. Winking smile

Done groaning yet?  Well good!

There are many commands, snippets and even other scripts that will do what this one does.  But this one is special, because it was made by me.  So… yeah, that’s pretty much it.

Oh, almost fogot!  It’s been updated to work with WindowsManagementFramework 5.1 and PowerCLI 6.5!

 

Open a PowerShell command line using an account that has approporiate rights to your vCenter server.

Function Get-RequiredModule
{
Param([string]$name)
if(!(Get-Module $name)){if(!(Get-Module -ListAvailable | Where-Object {$_.name -eq $name})){write-host "Required module $($name) missing."} else { Import-Module $name }} else { $true }
}

# Load the required modules
Get-RequiredModule -name "VMware.PowerCLI"

# Check if required modules are loaded, if not, break out of script.
if(!(Get-RequiredModule -name "VMware.PowerCLI")){Break}

# Modify this section as needed
$VC=@()
$vmName=@()

# Change these defaults to suit your environment
$dft_VC = "vCenter.domain.com"
$dft_vmName = "Virtual Machine Name"

# Get inputs from user, with default values
$VC = Read-Host -Prompt "Input your vCenter Server here (Press enter for: $($dft_VC))"
$vmName = Read-Host -Prompt "Input your Virtual Machine name here (Press enter for: $($dft_vmName))"

# Assign default values to the field if no user input was given
If(!($VC)){$VC=$dft_VC}
If(!($vmName)){$vmName=$dft_vmName}

# Do not modify below here
Connect-VIServer -Server "$vc" -Force
$win32DiskDrive = Get-WmiObject -Class Win32_DiskDrive -ComputerName $vmName
$vmHardDisks = Get-VM -Name $vmName | Get-HardDisk
$vmDatacenterView = Get-VM -Name $vmName | Get-Datacenter | Get-View
$virtualDiskManager = Get-View -Id VirtualDiskManager-virtualDiskManager
$diskToDriveVolume = Get-WmiObject Win32_DiskDrive -ComputerName $vmName | % {
$disk = $_
$partitions = "ASSOCIATORS OF " + "{Win32_DiskDrive.DeviceID='$($disk.DeviceID)'} " + "WHERE AssocClass = Win32_DiskDriveToDiskPartition"
	Get-WmiObject -Query $partitions -ComputerName $vmName | % {
		$partition = $_
		$drives = "ASSOCIATORS OF " + "{Win32_DiskPartition.DeviceID='$($partition.DeviceID)'} " + "WHERE AssocClass = Win32_LogicalDiskToPartition"
		Get-WmiObject -Query $drives -ComputerName $vmName | % {
			New-Object -Type PSCustomObject -Property @{
			Disk        = $disk.DeviceID
			DriveLetter = $_.DeviceID
			VolumeName  = $_.VolumeName
			}
		}
	}
}

foreach ($diskDrive in $win32DiskDrive)
{
	$diskDrive | Add-Member -MemberType NoteProperty -Name AltSerialNumber -Value $null
	$diskSerialNumber = $diskDrive.SerialNumber
	if ($diskDrive.Model -notmatch 'VMware Virtual disk SCSI Disk Device')
	{
		if ($diskSerialNumber -match '^\S{12}$'){$diskSerialNumber = ($diskSerialNumber | foreach { [byte[]]$bytes = $_.ToCharArray(); $bytes | foreach {$_.ToString('x2')} }) -join ''}
		$diskDrive.AltSerialNumber = $diskSerialNumber
	}
}

$results = @()
foreach ($vmHardDisk in $vmHardDisks){
	$vmHardDiskUuid = $virtualDiskManager.queryvirtualdiskuuid($vmHardDisk.Filename, $vmDatacenterView.MoRef) | foreach {$_.replace(' ','').replace('-','')}
	$windowsDisk = $win32DiskDrive | where {$_.SerialNumber -eq $vmHardDiskUuid}
	if (-not $windowsDisk){$windowsDisk = $win32DiskDrive | where {$_.AltSerialNumber -eq $vmHardDisk.ScsiCanonicalName.substring(12,24)}}
	$result = "" | select vmName,vmHardDiskDatastore,vmHardDiskVmdk,vmHardDiskName,windowsDiskIndex,windowsDiskSerialNumber,vmHardDiskUuid,windowsDeviceID,drives,volumes
	$result.vmName = $vmName.toupper()
	$result.vmHardDiskDatastore = $vmHardDisk.filename.split(']')[0].split('[')[1]
	$result.vmHardDiskVmdk = $vmHardDisk.filename.split(']')[1].trim()
	$result.vmHardDiskName = $vmHardDisk.Name
	$result.windowsDiskIndex = if ($windowsDisk){$windowsDisk.Index}else{"FAILED TO MATCH"}
	$result.windowsDiskSerialNumber = if ($windowsDisk){$windowsDisk.SerialNumber}else{"FAILED TO MATCH"}
	$result.vmHardDiskUuid = $vmHardDiskUuid
	$result.windowsDeviceID = if ($windowsDisk){$windowsDisk.DeviceID}else{"FAILED TO MATCH"}
	$driveVolumes = $diskToDriveVolume | where {$_.Disk -eq $windowsDisk.DeviceID}
	$result.drives = $driveVolumes.DriveLetter
	$result.volumes = $driveVolumes.VolumeName
	$results += $result
}
$results = $results | sort {[int]$_.vmHardDiskName.split(' ')[2]}
$results | ft -AutoSize