Extreme PowerShell / ConfigMgr: Extending Hardware Inventory
Posted by Trevor Sullivan on 2011/07/05
In previous versions of Microsoft System Center Configuration Manager (ConfigMgr / SCCM), a common task for administrators, engineers, and consultants, was to extend the hardware inventory configuration. These inventory extensions were written in Managed Object Format (MOF) and allowed the SCCM client agents to report back a wider array of information to the central site database for reporting purposes, collection building, and other management tasks. Making changes to the configuration could be a tedious task, as MOF is not very forgiving, and rather quite strict, in its syntax.
In Microsoft Systems Management Server 2003 (SMS 2003), each time a configuration change was made, it was necessary to deploy the updated MOF file to the SMS clients — this made ensuring hardware inventory consistency across all clients a challenging task. In SCCM, Microsoft included changes to these MOF files (SMS_DEF.mof and Configuration.mof) as part of the machine policy refresh task, which is a client-side polling mechanism for configuration changes.
In SCCM 2012 Beta 2, Microsoft is taking it a step further and has eliminated the SMS_DEF.mof altogether, left the configuration.mof behind by itself, and stuck the WMI inventory configuration in … WMI. What is WMI? WMI stands for Windows Management Instrumentation, a service built into the Windows Operating System since Windows XP (and Windows 2000 Service Pack 4, I think). It provides a standard method of exposing hardware and software level system information to applications, such as storage, processor, memory, running processes, installed software, and other application configuration data. SCCM is built on top of this technology, and often makes developing software and scripts around the product much easier than it otherwise might be.
For the remainder of this article, we’re going to look at specifically how to extend hardware inventory in SCCM 2012 programmatically using Windows PowerShell with the SCCM WMI provider.
ConfigMgr 2012 Hardware Inventory Configuration
So what happened to SMS_DEF.mof? How do I know what WMI classes are getting queried during a hardware inventory cycle and are being reported back in hardware inventory MIF files?
In SCCM 2012, configuration of hardware inventory classes is done by a “client settings” package. A client settings package can be defined and assigned to a specific collection of systems. This means you can have unique hardware inventory for a given collection of systems, among many other client agent settings. The screenshots below show the “Default Client Agent Settings” and the hardware inventory class editor.
The hardware inventory class editor provides a couple buttons to “Import” a MOF file that defines a WMI class, or you can use the interactive “Add” window to search a WMI namespace for classes and properties to import. Unfortunately, this doesn’t always do the trick, so we’ll look at how to use PowerShell to add WMI classes and properties via the SCCM WMI provider.
There are a couple of WMI classes that we will be working with to extend hardware inventory in SCCM 2012.
First off, there’s the SMS_InventoryClass WMI class. Instances of this class define the WMI classes that are visible to SCCM 2012 hardware inventory (eg. Win32_OperatingSystem, Win32_PageFileUsage, etc.).
It has a few key properties:
Secondly, we have the SMS_InventoryClassProperty WMI class. This class represents the WMI properties that are members of the WMI class defined by SMS_InventoryClass (for example, the Name property of the Win32_PageFileUsage WMI class).
Something important to note is that this class does not enumerate any instances. Rather, instances of this class are retrieved from the Properties property of instances of the SMS_InventoryClass class or are created by instantiating the class SMS_InventoryClassProperty itself. I know there’s a lot of duplicate terminology here, but re-read it a few times if it doesn’t make sense. I’ll state it in a different way. The SMS_InventoryClass class has a property named Properties, which contains an array of instances of SMS_InventoryClassProperty.
The SMS_InventoryClassProperty class has a few key properties also:
The Type property on the SMS_InventoryClassProperty is important. After some experimentation, I’ve discovered the following proper values for it:
Now that we’ve defined the WMI classes we’ll be working with, let’s take a look at how to put this all together.
Extending Hardware Inventory
I’ll start off by describing the high-level steps that we’ll follow to define a new WMI class for hardware inventory.
- Define WMI properties (new instances of SMS_InventoryClassProperty)
- Define the WMI class (new instance of SMS_InventoryClass)
- Add the properties to the class
- Commit the new class instance to the provider
Hopefully this is all coming to light, but keep on reading. In this example, we’re going to define a couple properties of the Win32_PageFileUsage class, which is built into the Windows OS, but isn’t defined by default in SCCM 2012. Here is an example instance, with the property values, of this class.
Here are the property definitions on the Win32_PageFileUsage class, for future reference. We’ll need to know the data types of each of the properties we use in our hardware inventory definition.
Define the WMI Properties
As stated above, the first step is to define the WMI properties that we want to add to the hardware inventory configuration. Let’s see how to do that with PowerShell. For now, we’ll just pull the properties: Name, PeakUsage, CurrentUsage, AllocatedBaseSize.
To define WMI properties, we follow these steps:
- Instantiate the SMS_InventoryClassProperty class
- Set the mandatory properties of our new instance
- Keep the new instance in a variable for later use
The following example shows all three of these steps.
# Get a reference to the SMS_InventoryClassProperty WMI class $InvClassPropClass = [wmiclass]"root\sms\site_lab:SMS_InventoryClassProperty" # Create new instance of SMS_InventoryClassProperty $Property1 = $InvClassPropClass.CreateInstance() # Define the property name $Property1.PropertyName = 'Name' # The Name property is the unique "key" property of the Win32_PageFileUsage class $Property1.IsKey = $true # Win32_PageFileUsage.Name is a string, so we use the integer value: 8 $Property1.Type = 8
Let’s define the three other properties that we mentioned before: PeakUsage, CurrentUsage, AllocatedBaseSize.
# Create new instance of SMS_InventoryClassProperty $Property2 = $InvClassPropClass.CreateInstance() # Define the property name $Property2.PropertyName = 'PeakUsage' # PeakUsage is NOT the unique "key" property of the Win32_PageFileUsage class $Property2.IsKey = $false # Win32_PageFileUsage.PeakUsage is a Uint32, so we use the integer value: 19 $Property2.Type = 19 # Create new instance of SMS_InventoryClassProperty $Property3 = $InvClassPropClass.CreateInstance() # Define the property name $Property3.PropertyName = 'CurrentUsage' # CurrentUsage is NOT the unique "key" property of the Win32_PageFileUsage class $Property3.IsKey = $false # Win32_PageFileUsage.CurrentUsage is a Uint32, so we use the integer value: 19 $Property3.Type = 19 # Create new instance of SMS_InventoryClassProperty $Property4 = $InvClassPropClass.CreateInstance() # Define the property name $Property4.PropertyName = 'AllocatedBaseSize' # AllocatedBaseSize is NOT the unique "key" property of the Win32_PageFileUsage class $Property4.IsKey = $false # Win32_PageFileUsage.AllocatedBaseSize is a Uint32, so we use the integer value: 19 $Property4.Type = 19
Great! Now we’ve got all our WMI property definitions stored in variables called $Property1, $Property2, $Property3, and $Property4! Granted, we could use an array here, but I was too lazy to do that for this example.
Define the WMI Class
Now that we’ve got our properties defined, it’s time to define the Win32_PageFileUsage inventory class. We do that by following these steps:
- Instantiate the SMS_InventoryClass class
- Define mandatory properties on new instance of SMS_InventoryClass
- Store in a variable for later use
The code below shows the three steps above.
# Get a reference to the SMS_InventoryClass class so we can instantiate it $InventoryClass = [wmiclass]"root\sms\site_lab:SMS_InventoryClass" # Create new instance of the SMS_InventoryClass class $NewInvClass = $InventoryClass.CreateInstance() # We want the class definition to be removable later on $NewInvClass.IsDeletable = $true # The WMI class name we are pointing to $NewInvClass.ClassName = 'Win32_PageFileUsage' # The WMI namespace that the WMI class is located in $NewInvClass.Namespace = '\\\\.\\root\\cimv2' # The SMS Reporting ClassID (used to generate SQL tables / view) $NewInvClass.SMSClassID = 'MICROSOFT|PAGE_FILE_USAGE|1.0' # The SMS Group Name (it's the "friendly name" used in Resource Explorer) $NewInvClass.SMSGroupName = 'Page File Usage'
Great, now we have our new inventory class stored in the $NewInvClass variable.
Something to observe here is that we are using twice as many backslashes as necessary when defining the target WMI namespace. Don’t forget that in this case, two slashes equals one.
Add Properties to Class Definition
We’re almost done! Now that we have our class and properties defined, we need to add the properties to the class. This is pretty easy.
$NewInvClass.Properties += [System.Management.ManagementObject]$Property1 $NewInvClass.Properties += [System.Management.ManagementObject]$Property2 $NewInvClass.Properties += [System.Management.ManagementObject]$Property3 $NewInvClass.Properties += [System.Management.ManagementObject]$Property4
See? Easy peasy.
It’s important to take note here that we are explicitly casting a [System.Management.ManagementObject] from each of the WMI objects we created, however. If we don’t do this, PowerShell complains about implicitly casting a ManagementObject from a PSObject, so we must explicitly cast it to avoid this.
Commit the Class Instance to the Provider
At this point, our inventory class has been defined, and the properties have been defined and added to the class definition. The only thing that’s left is to commit the inventory class to the SCCM provider! This is even easier than the last step! Check it out:
# Commit the inventory class instance to the provider $NewInvClass.Put()
We’re all done! We’ve programmatically defined the Win32_PageFileUsage class, along with four of its properties, in our hardware inventory configuration.
Enabling the Hardware
Ok I tricked you – there’s one final step to the whole process. Even though we’ve defined the Win32_PageFileUsage inventory class, we have to go into the client agent settings and enable it. So, go into your SCCM console (restart it first, because it may lock up on you), navigate to Administration –> Client Settings, open up one of your client agent settings packages, open up the Hardware Inventory configuration, and enable the class (see screenshot below).
Check Your Work
Once your SCCM clients refresh their machine policy and run their next hardware inventory cycle, you should start getting data back in your SCCM database. There are a couple of different methods you can validate that you are getting data. First, you can query the SCCM database directly using a tool such as SQL Server Management Studio.
SQL Server Management Studio
Fire up SQL Management Studio and connect to your SCCM database server. Select your SCCM database from the database list, and run the following query:
select * from v_GS_Page_File_Usage
You should get some results similar to the screenshot below.
From Windows PowerShell, you can issue the following command (replacing your site code as appropriate). You should see some results in the console.
Get-WmiObject -Namespace root\sms\site_lab -Class SMS_G_System_Page_File_Usage
After running this command, you should get some output similar to the below screenshot.
This article has described the method of using PowerShell to extend hardware inventory information in System Center Configuration Manager 2012 Beta 2. Because both SCCM and Windows PowerShell integrate tightly with WMI, they are ideal candidates to be used in conjunction with each other.
Although using PowerShell to extend hardware inventory isn’t essential, it provides a method of automating these tasks with Configuration Manager 2012.