none
PowerShell - Trouble with using ASSOCIATORS OF RRS feed

  • Question

  • Hi All,

    I have been playing around with associating related classes recently and have had reasonable success, however I am stumped on this one.

    I am currently querying HP hardware using WMI using the root\hpq namespace.

    The below snippet works well when querying hard disks, and from here I then create my note properties:

    $pd1 = get-wmiobject -namespace root\hpq -class HPSA_DiskDrive -ComputerName $Computer
    
    foreach ($pd in $pd1) {
    
                        $pd2 = Get-WmiObject -namespace root\hpq -ComputerName $Computer -query ("Associators of {HPSA_DiskDrive.CreationClassName='HPSA_DiskDrive',DeviceID='" + $pd.DeviceID + "',SystemCreationClassName='" + $pd.SystemCreationClassName + "',SystemName='" + $pd.SystemName + "'} where AssocClass=HPSA_DiskPhysicalPackageDiskDrive")
    
                        $pd3 = Get-WmiObject -namespace root\hpq -ComputerName $Computer -query ("Associators of {HPSA_DiskDrive.CreationClassName='HPSA_DiskDrive',DeviceID='" + $pd.DeviceID + "',SystemCreationClassName='" + $pd.SystemCreationClassName + "',SystemName='" + $pd.SystemName + "'} where AssocClass=HPSA_DiskDriveStorageExtent")
    
                        $pd4 = Get-WmiObject -namespace root\hpq -ComputerName $Computer -query ("Associators of {HPSA_DiskDrive.CreationClassName='HPSA_DiskDrive',DeviceID='" + $pd.DeviceID + "',SystemCreationClassName='" + $pd.SystemCreationClassName + "',SystemName='" + $pd.SystemName + "'} where AssocClass=HPSA_DiskDriveDiskDriveFirmware")

    However, when I try the same for the physical NIC's, I receive an 'Invalid Query' error.

    The only difference I can see when querying the NIC's, is the key property that relates to all related classes is stuck inside an array as such {deviceID}. Also note, that these classes have varying numbers of 'Key' properties. In the example above the HPSA_DiskDrive class actually has 4 'Key' properties, which is why the Associators Of query is so long. I'm still not sure why I need to use all 4 properties but it works! Even the combined classes at the end makes no sense, but again it works.

    So the question is, if using the same structure as above for the NIC cards, how do I extract the 'DeviceID' instance out so it can be associated?

    I hope I haven't confused you all too much.

    Wednesday, January 15, 2014 9:10 AM

Answers

  • $_.GetRelated()


    ^^ This. There's almost never a need to write "ASSOCIATORS OF" WQL queries yourself anymore. If you're using Get-WmiObject, you have the GetRelated() method on every object that it returns. If you're using the newer Get-CimInstance cmdlet, there is also Get-CimAssociatedInstance. In both cases, they take care of most of the work for you.
    • Marked as answer by Omegamon Thursday, January 16, 2014 7:41 AM
    Wednesday, January 15, 2014 1:03 PM
  • GetRelated() returns a ManagementObjectCollection (basically, an array, for your purposes), and you're running PowerShell 2.0 which doesn't support the "member enumeration" feature. You could access (for example) $pd2[0].PropertyName, if you're certain that the collection will contain exactly one object. Better would be to check the Count property or use a foreach loop.

    • Marked as answer by Omegamon Thursday, January 16, 2014 7:40 AM
    Thursday, January 16, 2014 5:04 AM
  • Do not use Associators of.  GetRelated() does all of that automatically.

    foreach ($nicC in $NicConf) {
        $nicC.GetRelated('win32_networkadapter')
    }


    ¯\_(ツ)_/¯

    • Marked as answer by Omegamon Thursday, January 16, 2014 7:40 AM
    Wednesday, January 15, 2014 1:40 PM

All replies

  • Why not just tell us what it Is that you need to get about the NIC.  Which associated class.

    Tell us what are you trying to do and not how you are trying to do it.


    ¯\_(ツ)_/¯

    Wednesday, January 15, 2014 12:12 PM
  • I am simply creating an object with various properties as you would with Win32_NetworkAdapterConfiguration and its associations.

    The class is HP_WinEthernetPort and its associated classes are HP_WinEthLocation and HP_WinEthBootCodeVersion.

    The properties themselves aren't relevant at this stage but they are different to the Windows root\cimv2 network classes.

    The 'key' properties for HP_WinEthernetPort are the same as for HPSA_DiskDrive shown above: CreationClassName, DeviceID, SystemCreationClassName and SystemName.

    Wednesday, January 15, 2014 12:49 PM
  • I am simply creating an object with various properties as you would with Win32_NetworkAdapterConfiguration and its associations.

    The class is HP_WinEthernetPort and its associated classes are HP_WinEthLocation and HP_WinEthBootCodeVersion.

    The properties themselves aren't relevant at this stage but they are different to the Windows root\cimv2 network classes.

    The 'key' properties for HP_WinEthernetPort are the same as for HPSA_DiskDrive shown above: CreationClassName, DeviceID, SystemCreationClassName and SystemName.

    Why do you say you are "creating" a class? 

    How do you know that the classes are associated. 

    Since this is an HP WMI class you should really be posting int he HP forum for the hardware you are using.

    You can also use direct reference to get the relations.

    Example:
     gwmi win32_networkadapter | %{$_.GetRelated()|select __CLASS}

    This will poll for all related classes for each instance.  Pick and instance with "-filter" and see what is available.


    ¯\_(ツ)_/¯


    • Edited by jrv Wednesday, January 15, 2014 12:57 PM
    Wednesday, January 15, 2014 12:56 PM
  • $_.GetRelated()


    ^^ This. There's almost never a need to write "ASSOCIATORS OF" WQL queries yourself anymore. If you're using Get-WmiObject, you have the GetRelated() method on every object that it returns. If you're using the newer Get-CimInstance cmdlet, there is also Get-CimAssociatedInstance. In both cases, they take care of most of the work for you.
    • Marked as answer by Omegamon Thursday, January 16, 2014 7:41 AM
    Wednesday, January 15, 2014 1:03 PM
  • Here is a probe for all relations:

    gwmi win32_networkadapter |
        ForEach-Object{
            $_.Caption
            $_.GetRelationships()|
                %{'       RELATED:  {0}' -f $_.__CLASS}
        }


    ¯\_(ツ)_/¯

    Wednesday, January 15, 2014 1:05 PM
  • Keeping the Win32_NetworkAdapter example going, here's how I'd find its associated configuration object:

    # Assumes that you have a connection named "Local Area Connection"; works on my Windows 7 desktop.
    $adapter = Get-WmiObject -Class Win32_NetworkAdapter -Filter 'NetConnectionID = "Local Area Connection"' $config = $adapter.GetRelated('Win32_NetworkAdapterConfiguration')

    Wednesday, January 15, 2014 1:11 PM
  • The example you have provided jrv is how I have found the associations. CIM Studio is also another good tool for a GUI representation.

    I don't want to get in to the namespace I am using, but more into how the ASSOCIATORS OF command works.

    My situation is I have "Class A" which has 2 known associated classes "Class B" and "Class C".

    "Class A" has 4 'Key' properties.

    of the 4 'key' properties in "Class A" is 'DeviceID' which has a value of {1234} and the associated classes have a different 'key' property called 'Instance' which has the same value of {1234}. As you can see the values are stored in an array (or curly brackets) and I believe this is why the association fails when using the ASSOCIATORS OF command. Is there a way to extract this value out so its not masked by an array?

    I am using PowerShell v2 so Get-CimAssociatedInstance is not an option.

    The end result is similar to this for Win32_NetworkAdapterConfiguration:

    $NicConf = Get-WmiObject Win32_NetworkAdapterConfiguration -Filter 'IPEnabled=TRUE' -ComputerName $Computer
    
    foreach ($nicC in $NicConf) {
    $NicConf2 = Get-WmiObject -query "Associators of {Win32_NetworkAdapterConfiguration.index='$($nicC.index)'} where resultclass=win32_networkadapter"
    
    $MyProps = @ {
    'A' = $NicC.whatever
    'B' = $NicConf2.something
    }
    $MyObj = New-Object -TypeName PSObject -Property $MyProps
    }

    Wednesday, January 15, 2014 1:31 PM
  • Do not use Associators of.  GetRelated() does all of that automatically.

    foreach ($nicC in $NicConf) {
        $nicC.GetRelated('win32_networkadapter')
    }


    ¯\_(ツ)_/¯

    • Marked as answer by Omegamon Thursday, January 16, 2014 7:40 AM
    Wednesday, January 15, 2014 1:40 PM
  • Thanks guys, I will try out your suggestions tomorrow. Getting late here in Oz.

    Still concerned about the value being in an array, but we'll see how we go

    • Edited by Omegamon Wednesday, January 15, 2014 1:50 PM
    Wednesday, January 15, 2014 1:47 PM
  • I've tested this out now using the GetRelated method which seems to be doing the trick so thanks for the suggestion to no longer use ASSOCIATORS OF.

    However I am now faced with the problem of when calling the properties, they show as empty.

    This happens when using the script I used in the OP which was working.

    Here is the modified working script I am using now:

    $pd1 = get-wmiobject -namespace root\hpq -class HPSA_DiskDrive -ComputerName $Computer
    
    foreach ($pd in $pd1) {
    
                        $pd2 = $pd.GetRelated('HPSA_DiskPhysicalPackage')
    
                        $pd3 = $pd.GetRelated('HPSA_StorageExtent')
    
                        $pd4 = $pd.GetRelated('HPSA_DiskDriveFirmware')
    
    Write-Debug
    
    }

    I have also inserted Write-Debug to see what is going on.

    When I run the script and query each of the variables in its suspended state, they all show their properties as expected:

    $pd

    $pd2

    $pd3

    $pd4

    when I try to view an individual property for $pd there are no issues eg. $pd.DeviceID shows the property value with no issues

    However when I try to view an individual property for the other variables, they show as empty eg. $pd1.deviceID or $pd2.deviceID.

    But if I run: $pd1 | select DeviceID it will show a result.

    Has anyone come across this before? If so does anyone know of how to get around it.

    As mentioned earlier, this script does work using ASSOCIATORS OF as shown in OP


    • Edited by Omegamon Thursday, January 16, 2014 2:56 AM
    Thursday, January 16, 2014 2:41 AM
  • I do already have various copies of those HP manuals. I am not concerned about their classes. Unless there was something in that link I was supposed to notice?

    Also I have used the 'DeviceID' property as an fictional example only. Actual properties I could use would be Model, Manufacturer, Name, Versionstring etc... But again, the issue here is why they are showing as empty, when using the method $pd2.propertyname.


    • Edited by Omegamon Thursday, January 16, 2014 2:56 AM
    Thursday, January 16, 2014 2:55 AM
  • read the documentation  on the classes carefully.  It tells you that the fields are no populat4ed under numerous conditions.

    The other thing you need to be aware of is that some hardware elements are protected and can only be read when running elevated.


    ¯\_(ツ)_/¯

    Thursday, January 16, 2014 3:07 AM
  • The fields are populated and they show when running the variables in debug mode. Its only when using the method $pd2.propertyname or $pd3.propertyname that they show as empty. So if I run the below in debug mode:

    ps>>> $pd2

    PropertyName : Whatever

    AnotherProperty : Something

    It will show all its properties and they are all populated.

    Then I try:

    ps>>> $pd2.propertyname

    It will show empty

    I am also running as administrator and had no issues with the Associators Of command using the same privileges.


    • Edited by Omegamon Thursday, January 16, 2014 3:35 AM
    Thursday, January 16, 2014 3:34 AM
  • Just tried the below and it works:

    $pd1 = get-wmiobject -namespace root\hpq -class HPSA_DiskDrive -ComputerName $Computer
    
    foreach ($pd in $pd1) {
    
                        $pd2 = $pd.GetRelated('HPSA_DiskPhysicalPackage') | Select *
    
                        $pd3 = $pd.GetRelated('HPSA_StorageExtent') | Select *
    
                        $pd4 = $pd.GetRelated('HPSA_DiskDriveFirmware') | Select *
    

    This seems a strange requirement to pipe out to select * but it works.

    It also slows the script down a lot.

    Any other suggestions?

    Thursday, January 16, 2014 3:47 AM
  • GetRelated() returns a ManagementObjectCollection (basically, an array, for your purposes), and you're running PowerShell 2.0 which doesn't support the "member enumeration" feature. You could access (for example) $pd2[0].PropertyName, if you're certain that the collection will contain exactly one object. Better would be to check the Count property or use a foreach loop.

    • Marked as answer by Omegamon Thursday, January 16, 2014 7:40 AM
    Thursday, January 16, 2014 5:04 AM
  • Thankyou all so much for your patience, input and steering me in to the right direction.

    I am going to stick with piping out to select * as it works well and doesn't slow the script down as much as first thought.

    I tried referencing the first object in the array but got an error where it couldn't find the index, but I will look in to using the count property and foreach loop to see if it speeds up the script a little.

    Thursday, January 16, 2014 7:39 AM
  • Thankyou all so much for your patience, input and steering me in to the right direction.

    I am going to stick with piping out to select * as it works well and doesn't slow the script down as much as first thought.

    I tried referencing the first object in the array but got an error where it couldn't find the index, but I will look in to using the count property and foreach loop to see if it speeds up the script a little.

    You do not always have an array.  This will prevent the issue:
    $pd2 = @($pd.GetRelated('HPSA_DiskPhysicalPackage') )

    This will guarantee that there is always at least a one element array. 

    Be aware that ther can be multiple instances or none on each call.   This would require that you enumerate each to get all instances:

    $pd.GetRelated('HPSA_DiskPhysicalPackage')| Object{$_.property}

    Now you will get all and it will never give you an issue or error.


    ¯\_(ツ)_/¯

    Thursday, January 16, 2014 3:22 PM
  • You do not always have an array. 

    As far as I can tell, GetRelated always returns a ManagementObjectCollection (which can be treated as an Array in PowerShell.)  That collection may contain zero objects, though.  Some demonstration of this:

    PS C:\Source\temp> $nic = gwmi win32_networkAdapter -Filter 'NetConnectionID = "Local Area Connection"'
    PS C:\Source\temp> $nic
    
    
    ServiceName      : e1cexpress
    MACAddress       : 28:D2:44:24:E6:18
    AdapterType      : Ethernet 802.3
    DeviceID         : 9
    Name             : Intel(R) 82579LM Gigabit Network Connection
    NetworkAddresses :
    Speed            : 100000000
    
    
    
    PS C:\Source\temp> $config = $nic.GetRelated('Win32_NetworkAdapterConfiguration')
    PS C:\Source\temp> $config.GetType().FullName
    System.Management.ManagementObjectCollection
    PS C:\Source\temp> $test = $nic.GetRelated('Win32_BogusClass')
    PS C:\Source\temp> $null -eq $test
    False
    PS C:\Source\temp> $test.GetType().FullName
    System.Management.ManagementObjectCollection
    PS C:\Source\temp> $test.Count
    0
    PS C:\Source\temp> $config.Count
    1
    PS C:\Source\temp>

    Thursday, January 16, 2014 3:46 PM
  • Except when it returns nothing and you cannot index into nothing.

    $null[0].Model

    If an error occurs or if the returned object is not a WMI object you will get an error.  Enumerating the object handles all conditions.

    Posh V3 and later WMI will always return a collection.  V2 on XP does not always return a collection when no instances are returned.  It returns nothing.  I am not sure but a patch to the framework may be what is required to prevent this.


    ¯\_(ツ)_/¯

    Thursday, January 16, 2014 4:15 PM
  • Note also that providers handle the GetRelated() call and may not function as expected. I have had issues with both Dell and HP WMI implementations.


    ¯\_(ツ)_/¯

    Thursday, January 16, 2014 4:17 PM
  • You do not always have an array.  This will prevent the issue:
    $pd2 = @($pd.GetRelated('HPSA_DiskPhysicalPackage') )

    This will guarantee that there is always at least a one element array. 

    Be aware that ther can be multiple instances or none on each call.   This would require that you enumerate each to get all instances:

    $pd.GetRelated('HPSA_DiskPhysicalPackage')| Object{$_.property}

    Now you will get all and it will never give you an issue or error.


    Is there any difference between:

    $pd.GetRelated('HPSA_DiskPhysicalPackage') | Select-Object *

    and

    $pd.GetRelated('HPSA_DiskPhysicalPackage') | Select-Object{$_.property}

    I also tried $pd2 = @($pd.GetRelated('HPSA_DiskPhysicalPackage') ) in the chance of it being an array and had no luck.

    Tuesday, January 21, 2014 12:29 AM
  • One is legitimate code and the other is senseless

    This says show me all of the properties of the object:

    $pd.GetRelated('HPSA_DiskPhysicalPackage') | Select-Object *

    This says Give me all of the property names.

    $pd.GetRelated('HPSA_DiskPhysicalPackage') | Select-Object{$_.property}

    This makes more sense:
    $pd.GetRelated('HPSA_DiskPhysicalPackage') | select -expand Properties

    Which is why I recommend looking into this: http://technet.microsoft.com/en-us/scriptcenter/dd793612.aspx


    ¯\_(ツ)_/¯

    Tuesday, January 21, 2014 1:01 AM
  • I couldn't see any differences in the approach in this case, which was why I asked if there were any differences, since it was you who suggested the second option. Is this merely just a better scripting practice?

    Thanks for the slap in the face link though, and from all of the different sources I have read from or watched, there hasn't been anything close to why this is happening which is why I came to this forum for help.

    Tuesday, January 21, 2014 3:30 AM
  • How can you not see any differences. They are absolutely different.

    one returns a list of property values and the other a collection of property objects.

    See:
    PS C:\scripts> gwmi win32_bios |select {$_.Properties}

    $_.Properties
    -------------
    {BiosCharacteristics, BIOSVersion, BuildNumber, Caption...}


    PS C:\scripts> gwmi win32_bios |select *


    PSComputerName        : W8TEST
    Status                : OK
    Name                  : V2.03
    Caption               : V2.03
    SMBIOSPresent         : True

    Here is wht one of those properties looks like:

    PS C:\scripts> $x=gwmi win32_bios |select {$_.Properties}
    PS C:\scripts> $x.'$_.Properties'[0]


    Name       : BiosCharacteristics
    Value      : {7, 11, 12, 15...}
    Type       : UInt16
    IsLocal    : True
    IsArray    : True
    Origin     : Win32_BIOS
    Qualifiers : {CIMTYPE}


    ¯\_(ツ)_/¯

    Tuesday, January 21, 2014 3:56 AM
  • I think you are overthinking this without looking closely at the basics.  You seem to be guessing at how this works.  Go back and try to understand how the technology is engineered.  Once you see how the parts are intended to work I think you will see why you are jut missing what is being presented.

    I have reviewed the fundamentals dozens of times.  This is the nature of technology.  Details and deep understanding come slowly.  It requires serious study.

    You are dealing in a new setting.  We do not need to use old constructs.  With WMI we use GetRelated() and simply specify the class of interest.  It can return none or  more related instances.  We expand objects and select properties using select-object.  ($_.properties) Is not a reasonable property of most objects in the pipeline.  If we want to get this collection we would use -expand as just usinf the $_ object does not quite get us there.

    This:

    gwmi win32_bios |select -expand Properties

    Gives us the properties but we get other unnecessary information

    Note how this works:

    PS C:\scripts> gwmi win32_bios |select Properties

    Properties
    ----------
    {BiosCharacteristics, BIOSVersion, BuildNumber, Caption...}


    PS C:\scripts> gwmi win32_bios |select BiosCharacteristics, BIOSVersion, BuildNumber, Caption

    BiosCharacteristics           BIOSVersion                   BuildNumber                   Caption
    -------------------           -----------                   -----------                   -------
    {7, 11, 12, 15...}            {ACRSYS - 1, V2.03, Phoeni...                               V2.03

    One gives us the properties as a collection.  The other extracts the property values directly which is generally what we want.

    Here is an even more obvious example of the difference:

    PS C:\scripts> gwmi win32_diskpartition |select properties

    Properties
    ----------
    {Access, Availability, BlockSize, Bootable...}
    {Access, Availability, BlockSize, Bootable...}
    {Access, Availability, BlockSize, Bootable...}
    {Access, Availability, BlockSize, Bootable...}
    {Access, Availability, BlockSize, Bootable...}

    PS C:\scripts> gwmi win32_diskpartition |select Access, Availability, BlockSize, Bootable

    Access                        Availability                                      BlockSize                      Bootable
    ------                        ------------                                      ---------                      --------
                                                                                          512                         False
                                                                                          512                          True
                                                                                          512                         False
                                                                                          512                         False
                                                                                          512                         False

    So you can see that one method is useful and the other is not for most things.


    ¯\_(ツ)_/¯

    Tuesday, January 21, 2014 4:11 AM