SDK: Creating custom inventory classes for clients with the client messaging SDK

Out of the box, the client messaging SDK contains several basic hardware inventory classes for sending inventory data such as CCM_System, Win32_NetworkAdapter, and some others. It has the ability to create inventory data on the fly from pre-formatted XML using InventoryInstanceGeneric. It also has some wrapper functionality to convert existing data in WMI to pre-formatted inventory classes through Microsoft.ConfigurationManagement.Messaging.Messages.WmiClassToInventoryReportInstance. If there’s interest I can go more into this in a future.

If you want to use the object model to create your own custom inventory classes for collection, it’s pretty simple to do this. A prerequisite for making the most of this is knowledge about how XML Serialization in the .NET framework works as this process is heavily dependent on this internally. If you don’t know much about this it should still be pretty easy to get started; things just become more difficult when you’re trying to expose more advanced data sets.

For basic details on how to send a hardware inventory message, check out my post with an in-depth sample on how to use the messaging SDK.

Here’s an example inventory class that I created by extending the SDK for a Contoso Perpetual Energy Reactor attachment:

 
/// <summary>
/// This class represents an inventory instance of a Contoso Perpetual Motion Reactor attachment
/// </summary>
[XmlRoot("Contoso_PerpetualMotionReactor")] // Must define an XmlRoot that represents the class name
public sealed class InventoryElementRecordPerpetualMotionReactor : InventoryInstanceElement
{
    private readonly Collection<string> attachments = new Collection<string>();
 
    /// <summary>
    /// Reactor model
    /// </summary>
    [XmlElement]
    public string Model { get; set; }
 
    /// <summary>
    /// Version
    /// </summary>
    [XmlElement]
    public uint Version { get; set; }
 
    /// <summary>
    /// Attachments for the energy reactor
    /// </summary>
    [XmlElement]
    public Collection<string> Attachments
    {
        get { return attachments; }
    }
 
    /// <summary>
    /// Discover an inventory instance element based local configuration
    /// </summary>
    /// <remarks>This is optional and only here for documentation purposes. By default, DiscoverSelf() will simply throw a NotImplementedException unless
    /// you override it with your own discovery logic</remarks>
    protected override void DiscoverSelf()
    {
        base.DiscoverSelf();
    }
 
    /// <summary>
    /// Initializes a new instance of the <see cref="InventoryElementRecordPerpetualMotionReactor"/> class.
    /// </summary>
    public InventoryElementRecordPerpetualMotionReactor()
        : base(
            "Contoso_PerpetualMotionReactor", // associated base class
            "Contoso_PerpetualMotionReactor", // associated parent class
            @"root\Contoso" /* namespace (scope) */)
    {
    }
}

Keep in mind the XmlRoot and XmlElement attributes. These are used to format the class to XML before sending it to the management point. Here’s an example of how this class will look when serialized to XML (reformatted for clarity):

 
<Contoso_PerpetualMotionReactor>
    <Model>Contoso Perpetual Motion Reactor (Nuclear Powered)</Model>
    <Version>1</Version>
    <Attachments>Dirty Water Cooling Tower</Attachments>
    <Attachments>Unobtanium Heat Sink</Attachments>
    <Attachments>Analogue gauges</Attachments>
    <Attachments>Sport suspension package</Attachments>
</Contoso_PerpetualMotionReactor>

This will be embedded into the inventory report that’s sent to the management point. Here’s some sample code that could bring all these things together to send this:

 
ConfigMgrHardwareInventoryMessage customHinvMessage = new ConfigMgrHardwareInventoryMessage();
customHinvMessage.Settings.HostName = mpHostname;
customHinvMessage.AddCertificateToMessage(certificate, CertificatePurposes.Signing | CertificatePurposes.Encryption);
customHinvMessage.SmsId = clientId;
customHinvMessage.SiteCode = siteCode;
customHinvMessage.NetBiosName = "MyDummyHostName";
customHinvMessage.DomainName = "MyDomain.net";
 
InventoryElementRecordPerpetualMotionReactor reactor = new InventoryElementRecordPerpetualMotionReactor();
reactor.Model = "Contoso Perpetual Motion Reactor (Nuclear Powered)";
reactor.Version = 1;
reactor.Attachments.Add("Dirty Water Cooling Tower");
reactor.Attachments.Add("Unobtanium Heat Sink");
reactor.Attachments.Add("Analogue gauges");
reactor.Attachments.Add("Sport suspension package");
 
// Create an instance containing the element
InventoryInstance instance = new InventoryInstance(reactor);
 
// Now add the instance to the inventory list
customHinvMessage.AddInstanceToInventory(instance);
 
customHinvMessage.SendMessage(Sender);

Now when you do this, if you look at MP_Hinv.log on the management point you’ll notice something will be wrong. The MP’s hardware inventory processor will complain about this class with a log line that looks something like this:

Hinv: class name not found in the mapping table: Contoso_PerpetualMotionReactor    MP_HinvEndpoint    4/10/2013 1:44:38 PM    4592 (0x11F0)

The reason for this is you can’t just start creating new hardware inventory classes without taking some action on the site server. First you’ll need to create a .MOF file that represents the custom class you’re creating. Here’s one I created that represents the code above:

 
//=============================================================================
// SMS_Class_Template must be the parent of every class
//=============================================================================
class SMS_Class_Template
{
};
 
[ SMS_Report (TRUE),
  SMS_Group_Name ("Perpetual Motion Reactor"),
  SMS_Class_ID ("CONTOSO|PERPETUAL_MOTION_REACTOR|1.0"),
  Namespace ("\\\\\\\\.\\\\root\\\\contoso") ]
class Contoso_PerpetualMotionReactor : SMS_Class_Template
{
    [SMS_Report(TRUE), key]
    String Model;
 
    [SMS_Report(TRUE)]
    UInt32 Version;
 
    [SMS_Report(TRUE)]
    String Attachments[];
};

The next step is to import this MOF file into Configuration Manager. To do this, you need to go to the Administration view in the admin console, go to Client Settings, choose your client settings group, then go to Hardware Inventor, choose Set Classes, and import your mof file:

image

When you send this inventory a second time, it will get processed successfully by the management point with a line like this in the MP_Hinv.log:

Hinv Sax: Inserting class instance Contoso_PerpetualMotionReactor, attr=New    MP_HinvEndpoint    4/10/2013 2:04:54 PM    4592 (0x11F0)

Now if you open Resource Explorer for your system, you’ll see this new data represented for your client:

image