So I was working on a PowerCLI script to pull out the SCSI information for vmdk drives, so I can do the matching into the Windows OS to drive letters. Upon doing so, I came across a very odd bug that took quite a while to explain, when I ran it across my VM Architect and he realized what was going on. The issue that I was seeing is that when I tried to identify the SCSI controller, it was coming back with multiple controllers, each with the same key. Moreover, when I tried to identify the disks, based on their disk key, I was finding multiple disks, with different backing information. Here is my code:
PROCESS {
if ( $PSBoundParameters.ContainsKey("VMName") ) {
$VMs = Get-VM $VMName
}
else {
$VMs = Get-VM
}
ForEach ( $Vm in $VMs ) {
$VMView = Get-View -ViewType VirtualMachine -Filter @{"Name" = $Vm.Name}
$SCSIControllers = $VMView.Config.Hardware.Device | Where-Object { $_.DeviceInfo.Label -match "SCSI Controller" }
$Disks = $Vm | Get-HardDisk
ForEach ( $Disk in $Disks ) {
$Id = $Disk.Id
$DeviceId = $Id.Split("/")[1]
$SCSIDevice = $VMView.Config.Hardware.Device | Where-Object { $_.Key -eq $DeviceId -and $_.Backing.FileName -eq $Disk.FileName }
$SCSIController = $SCSIControllers | Where-Object { $SCSIDevice.ControllerKey -eq $_.Key -and $_.Device -contains $DeviceId }
if ( $SCSIController -is [array] ) {
$BusNumbers = $SCSIController | Select-Object -ExpandProperty BusNumber | Sort-Object -Unique
if ( $BusNumbers -is [array] -and $BusNumbers.Count -ne 1 ) {
[PSCustomObject] @{
VM = $VM.Name
FileName = $Disk.FileName
Name = $Disk.Name
CapacityGB = $Disk.CapacityGB
DeviceId = $DeviceId
ControllerKey = $SCSIDevice.ControllerKey
SCSIBus = "Unable to be determined"
SCSIUnit = $SCSIDevice.UnitNumber
SCSIId = "X:$($SCSIDevice.UnitNumber)"
}
continue
}
else {
$BusNumber = $BusNumbers
}
}
else {
$BusNumber = $SCSIController.BusNumber
}
[PSCustomObject] @{
VM = $VM.Name
FileName = $Disk.FileName
Name = $Disk.Name
CapacityGB = $Disk.CapacityGB
DeviceId = $DeviceId
ControllerKey = $SCSIDevice.ControllerKey
SCSIBus = $BusNumber
SCSIUnit = $SCSIDevice.UnitNumber
SCSIId = "$($BusNumber):$($SCSIDevice.UnitNumber)"
}
}
}
}
So the magic was happening in the following line:
$VMView = Get-View -ViewType VirtualMachine -Filter @{"Name" = $Vm.Name}
As it turns out, contrary to what I believed should happen, the Get-View commandlet was returning multiple VMs, instead of just one, even though I had specified "=" as part of my filter. So as a result, if I searched for a VM called "VM01", the Get-View filter was returning VM01, TESTVM01, TEST2VM01, and any other VM that had "VM01" as a partial match of its name.
This is a simple work around - I'll just pipe the Get-View output to Where-Object and ensure the name is an exact match in that portion of the pipeline, instead of relying on Get-View to return me just one item.
No need to use a Where-clause, just remember that the Filter in the Get-View interprets the right-hand operator as a RegEx expression.
By adding RegEx anchor points you can filter on an exact match.
$VMView = Get-View -ViewType VirtualMachine -Filter @{"Name" = "^$($Vm.Name)$"}
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
Before I get too many responses here, I should point out the following two lines:
$SCSIDevice = $VMView.Config.Hardware.Device | Where-Object { $_.Key -eq $DeviceId -and $_.Backing.FileName -eq $Disk.FileName }
$SCSIController = $SCSIControllers | Where-Object { $SCSIDevice.ControllerKey -eq $_.Key -and $_.Device -contains $DeviceId }
These lines were the result of me doing my best to filter out these duplicates. I initially had come up with:
$SCSIDevice = $VMView.Config.Hardware.Device | Where-Object { $_.Key -eq $DeviceId }
$SCSIController = $SCSIControllers | Where-Object { $SCSIDevice.ControllerKey -eq $_.Key }
I added the filename for the vmdk, as this filtered out the files that didn't match the correct filename. But I was still getting multiple SCSI controllers, so I tried to include filtering only the Devices that had the same DeviceId attached - this is because I found a couple instances of SCSI Controllers where the BUS Id was different, (which is possibly valid, I have not yet gone back to explore this) - I then grabbed all the BusNumbers that were returned, and sorted them uniquely so at the very least, I was only returning a single BUS Id - which worked in my environment, but would not have been a perfect solution. In the end, I was returning only valid SCSI Ids, but it was more through chance and luck that my environment was largely homogeneous than correct logic.
No need to use a Where-clause, just remember that the Filter in the Get-View interprets the right-hand operator as a RegEx expression.
By adding RegEx anchor points you can filter on an exact match.
$VMView = Get-View -ViewType VirtualMachine -Filter @{"Name" = "^$($Vm.Name)$"}
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
So then this is intended behavior and should always be thought of as a regex expression? That should work. Thank you LucD
Yes, see the explanation for the Filter parameter on the Get-View cmdlet.
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference