VMware Cloud Community
omrsafetyo
Enthusiast
Enthusiast
Jump to solution

Bug in Get-VMView - equals filter is using match comparison

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.

Tags (2)
1 Solution

Accepted Solutions
LucD
Leadership
Leadership
Jump to solution

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

View solution in original post

4 Replies
omrsafetyo
Enthusiast
Enthusiast
Jump to solution

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.

Reply
0 Kudos
LucD
Leadership
Leadership
Jump to solution

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

omrsafetyo
Enthusiast
Enthusiast
Jump to solution

So then this is intended behavior and should always be thought of as a regex expression?  That should work.  Thank you LucD

Reply
0 Kudos
LucD
Leadership
Leadership
Jump to solution

Yes, see the explanation for the Filter parameter on the Get-View cmdlet.


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

Reply
0 Kudos