B4DschK4Pp
B4DschK4Pp

Reputation: 193

Add-Member AliasProperty to sub property in PowerShell

I have an object that has an array of objects as a property.

PS C:\> $Object

GroupType        : Object
StateRevCounter  : 3846
SchemaTag        : Computer
PropGroupList    : {DSM.MdsPropGroup, DSM.MdsPropGroup, DSM.MdsPropGroup, DSM.MdsPropGroup...}



PS C:\> $Object.PropGroupList

Tag                       PropertyList
---                       ------------
BasicInventory            {DSM.MdsTypedPropertyOfString, DSM.MdsTypedPropertyOfString, DSM.MdsTypedPr... 
ClientInfo                {DSM.MdsTypedPropertyOfNullableOfDateTime, DSM.MdsTypedPropertyOfNullableOf... 
Computer                  {DSM.MdsTypedPropertyOfString, DSM.MdsTypedPropertyOfNullableOfDateTime, DS...
CustomPatchManagement     {DSM.MdsTypedPropertyOfNullableOfBoolean, DSM.MdsTypedPropertyOfString}        
HardwareBasedRemoteMgmt   {DSM.MdsTypedPropertyOfString, DSM.MdsTypedPropertyOfNullableOfBoolean, DSM...



PS C:\> $Object.PropGroupList.PropertyList

TypedValue                                  Tag                                        Type
----------                                  ---                                        ----
7.4.1.4461                                  ClientVersion                            String
Client                                      ComputerRole                             Option
169                                         CPUArchitecture                     CatalogLink
2262                                        CPUType                             CatalogLink
DSMCLIENT00.Computers.ideri.dev             DirectoryContext                         String
DSMClient00.ideri.dev                       FullQualifiedName                        String
                                            InfrastructureRole                       Option
000C29E1B2FD                                InitialMACAddress                        String
227                                         InstalledOS                         CatalogLink
315                                         InstalledOSCulture                  CatalogLink
1458                                        InstalledOSFlavor                   CatalogLink
Windows 10 Enterprise 1511                  InstalledOSFriendlyName                  String
DSM.MdsVersion                              InstalledOSVersion                      Version
4193                                        InstalledRAM                              Int32
66057                                       LastBootServer                            Int32
.....

Now I want to create AliasProperties for $Object to show the values of $Object.PropGroupList.PropertyList directly within the output of $Object and update the values at the right spot, if the AliasProperty is changed.

Desired output:

PS C:\> $Object

BasicInventory_ClientVersion   : 7.4.1.4461
BasicInventory_ComputerRole    : Client
BasicInventory_CPUArchitecture : 169
...
GroupType                      : Object
StateRevCounter                : 3846
SchemaTag                      : Computer
PropGroupList                  : {DSM.MdsPropGroup, DSM.MdsPropGroup, DSM.MdsPropGroup, DSM.MdsPropGroup...}

So if I then update BasicInventory_ClientVersion to for example 10.4.2.3333, the corresponding value in the sub property (array) is updated as well and vice versa.

Is this even possible with Add-Member -MemberType AliasProperty? Or can I only add AliasProperties for properties in the root of the object?

Regards Sebbo

Upvotes: 0

Views: 668

Answers (2)

B4DschK4Pp
B4DschK4Pp

Reputation: 193

As @AdminOfThings suggested, I used ScriptProperty in the end. Thanks. I've ended up building a function to add the properties with the right links to the array.

As you can see, I had to compose the script block as a string first to get the values of my variables resolved first. If I would have written it in the script block directly, the variable $prop.Tagfor example would not have been resolved, as it is not set in the script block.

function ExpandObjectMdsPropGroupList ($ObjectList)
{
    foreach($obj in $ObjectList)
    {
        $PropGroupList = $obj.Propgrouplist
        foreach($propGrp in $PropGroupList)
        {
            foreach($prop in $propGrp.PropertyList)
            {
                # compose the getter
                $GetterScriptBlockAsString = "(`$this.propGroupList.PropertyList | Where-Object{`$_.Tag -eq `"$($prop.Tag)`"}).TypedValue"
                $GetterScriptBlock = [scriptblock]::Create($GetterScriptBlockAsString)

                # compose the setter
                [string]$typeOfPropTypedValue = $null
                try{
                    # get the type of TypedValue
                    $typeOfPropTypedValue = $prop.TypedValue.GetType()
                }catch{
                    # If TypedValue is null we have to get the type from get-member
                    $memberType = ($prop | Get-Member -Name TypedValue).Definition
                    $typeOfPropTypedValue = ($memberType.Remove($memberType.IndexOf(' ')))
                }
                if($typeOfPropTypedValue){
                    $typeOfPropTypedValue = "[$typeOfPropTypedValue]"
                }
                $SetterScriptBlockAsString = "param($typeOfPropTypedValue`$val);(`$this.propGroupList.PropertyList | Where-Object{`$_.Tag -eq `"$($prop.Tag)`"}).TypedValue = `$val"
                $SetterScriptBlock = [scriptblock]::Create($SetterScriptBlockAsString)

                # Add the member to the object
                $obj | Add-Member -MemberType ScriptProperty -Name "$($propGrp.Tag)_$($prop.Tag)" -Value $GetterScriptBlock -SecondValue $SetterScriptBlock
            }
        }
    }
    $ObjectList
}

Now I can use the function on any object with PropGroupList as a property and it adds the ScriptProperties no mather what PropGroups are in the List.

Thanks to the getters and setters I can update the values on either side.

Regards Sebbo

Upvotes: 1

AdminOfThings
AdminOfThings

Reputation: 25001

You can use a Add-Member to add member type ScriptProperty. However, building the object is a fairly manual process. Here is an example using two properties, ClientVersion and ComputerRole.

$object | Add-Member -MemberType ScriptProperty -Name "BasicInventory_ClientVersion" -Value {
    (($this.propgrouplist | Where Tag -eq 'BasicInventory').propertylist | where Tag -eq 'ClientVersion').TypedValue
}
$object | Add-Member -MemberType ScriptProperty -Name "BasicInventory_ComputerRole" -Value {
    (($this.propgrouplist | Where Tag -eq 'BasicInventory').propertylist | where Tag -eq 'ComputerRole').TypedValue
}

Now you can update the source property and have it be reflected in the scriptproperty.

# Properties Before Change
$object | fl

GroupType                    : Object
PropGroupList                : @{Tag=BasicInventory; PropertyList=System.Object[]}
BasicInventory_ClientVersion : 7.4.1.4461
BasicInventory_ComputerRole  : Client

# Properties After Change
($Object.PropGroupList.PropertyList | Where Tag -eq 'ClientVersion').TypedValue = '20.3.4'
$object | fl

GroupType                    : Object
PropGroupList                : @{Tag=BasicInventory; PropertyList=System.Object[]}
BasicInventory_ClientVersion : 20.3.4
BasicInventory_ComputerRole  : Client

Use caution when trying to make this dynamic with variables. Any variable used in the scriptproperty value will be computed when the object is called based on the variables defined in the calling scope. For example, if you assigned value to be {$tag}, $tag would need to be defined somewhere before $object is retrieved.

Upvotes: 1

Related Questions