Modifying embedded properties in WMI using PowerShell

This isn’t immediately obvious. Say you have a WMI class, e.g. SMS_SCI_Component from the SCCM WMI provider (root\SMS\site_XXX). You can obtain a PowerShell object representing the various instances of this class easily enough:


$SiteCode = "XXX"
$WmiObjectNamespace = "root\SMS\site_$($SiteCode)"
$WmiObjectClass = SMS_SCI_Component
$WmiObjectFilter = "ComponentName='SMS_AD_SECURITY_GROUP_DISCOVERY_AGENT'"


$WmiObject = Get-WmiObject -Namespace $WmiObjectNamespace -Class $WmiObjectClass -Filter $WmiObjectFilter

$WmiObject will now be an instance of the [System.Management.ManagementObject] class, with properties similar to:


PS S:\SCCM2012> $WmiObject

__GENUS : 2
__CLASS : SMS_SCI_Component
__SUPERCLASS : SMS_SiteControlItem
__DYNASTY : SMS_BaseClass
__RELPATH : SMS_SCI_Component.FileType=2,ItemName="SMS_AD_SECURITY_GROUP_DISCOVERY_AGENT|DEVXX-CM01.DEVXX.local"
,ItemType="Component",SiteCode="XXX"
__PROPERTY_COUNT : 9
__DERIVATION : {SMS_SiteControlItem, SMS_BaseClass}
__SERVER : DEVXX-CM01
__NAMESPACE : root\SMS\site_D71
__PATH : \\DEVXX-CM01\root\SMS\site_D71:SMS_SCI_Component.FileType=2,ItemName="SMS_AD_SECURITY_GROUP_DISCOVER
Y_AGENT|DEVXX-CM01.DEVXX.local",ItemType="Component",SiteCode="XXX"
ComponentName : SMS_AD_SECURITY_GROUP_DISCOVERY_AGENT
FileType : 2
Flag : 2
ItemName : SMS_AD_SECURITY_GROUP_DISCOVERY_AGENT|DEVXX-CM01.DEVXX.local
ItemType : Component
Name : DEVXX-CM01.DEVXX.local
PropLists : {AD Accounts:test2, AD Attributes, AD Containers, Search Bases:blah...}
Props : {Days Since Last Logon, Days Since Last Password Set, Discover DG Membership, Enable Filtering Expir
ed Logon...}
SiteCode : XXX

Pretty much everything in SCCM WMI is like this, an object with a list of embedded SMS_EmbeddedPropertyList objects.

Accessing these is fairly simple, just access the PropLists member of the $WmiObject instance. E.g. to remove one:


$Name = "Testing"
$PropListName = "Search Bases:$($Name)"

# Apply filter
$proplists = $WmiObject.PropLists
$proplists = $proplists | where {$_.PropertyListName -ne $PropListName}

# Finally write changes back to the object
$WmiObject.PropLists = $proplists
$WmiObject.put() > $null

But how about adding one? Well we need to create an instance of an SMS_EmbeddedPropertyList and then add it to the parent object’s list. To create an instance we use:


$new = [WmiClass] "$WmiObjectNamespace:SMS_EmbeddedPropertyList"
$embeddedproperylist = $new.CreateInstance()

This will give you an instance of the [System.Management.ManagementObject] class with the following properties:


PS S:\SCCM2012> $embeddedproperylist

__GENUS : 2
__CLASS : SMS_EmbeddedPropertyList
__SUPERCLASS :
__DYNASTY : SMS_EmbeddedPropertyList
__RELPATH :
__PROPERTY_COUNT : 3
__DERIVATION : {}
__SERVER :
__NAMESPACE :
__PATH :
ItemType :
PropertyListName :
Values :

So you fill in the required parameters, and then add it to the $proplists array for writing back…


$embeddedproperylist.PropertyListName = "testname"
$embeddedproperylist.Values = @("value1", "value2")

$WmiObject.PropLists += $embeddedproperylist

$WmiObject.put()

Ah…


PS S:\SCCM2012> $WmiObject.PropLists += $embeddedproperylist
Exception setting "PropLists": "Unable to cast object of type 'System.Management.Automation.PSObject' to type 'System.M
anagement.ManagementBaseObject'."
At line:1 char:12
+ $WmiObject. <<<< PropLists += $epl
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : PropertyAssignmentException

It seems that if you make any modifications to the instance it can no longer automatically convert it into its base type for writing back to WMI. The trick is to perform the cast manually:


$embeddedproperylist = [System.Management.ManagementBaseObject] $embeddedproperylist

$WmiObject.PropLists += $embeddedproperylist

$WmiObject.put()

Success!