Sometimes you may need to extend a class with additional attributes.  If those attributes are accessible via the registry or by WMI extending a class to add them is easy.  But what if those attributes are not accessible via registry or WMI?  The solution there is actually quite easy as well.  Let’s walk through how to do it and at the end of the post I’ll attach the sample management pack built using this approach.

For our example I will use a flat file containing the attributes I want to add.  Let’s get started - and as we get started let me point out that OpsMgr is NOT intended to be use like SCCM - you shouldn't extend a class with 9 billion attributes - but where it makes sense thsi method works.

First, we need to create an extended class so we can add our attributes of interest.  We could do this in the OpsMgr console and then save and move to the authoring console – but it’s just as easy to do it all in the authoring console.  Launch the authoring console and create a new empty management pack.  For our example we will title ours “Windows_Computer_Extended_Discovery_MP” with a Display name of “Windows Computer Extended Discovery MP”.  Once created, select the service model node and the classes.  Right click to create a new custom class.  Our class will be called ‘Windows_Computer_Extended_from_Flat_File”

image

On the general tab of the class use Windows Computer as the base class and type in a friendly name for the display name of the class..

NOTE:  Windows Computer should almost NEVER be used as a base class.  In this case we are extending Windows Computer to add additional attributes so selecting it as the base class is appropriate.

image

On the Properties tab, add the attributes to extend the base class.  In our case, the base class will be extended to include information such as system model, datacenter the system is housed in, the rack within the datacenter that contains the system and whether the system is operated with or without a monitor in the rack (headless).  To create an attribute just right-click on the left hand window and add as many attributes as needed.  Don’t forget to add a display name else your property will have a blank column value in the OpsMgr UI.  A completed properties window is shown below.

Note:  Make absolutely SURE that your additional attributes are ones that do not change often.  If these attributes are in a state of churn it will reak havoc with your management group.

image

As simple as that, the extended class is created.  You might think you need to add something on the relationships tab but if you take a look, it’s already filled out for you.

image

OK, the class has been built – now we need to build out the discovery to populate these custom attributes.  In the authoring console, navigate to the health model section and the click on discoveries.  On the right hand pane, right-click and select new script based discovery.

Note:  You could have also chosen custom discovery but would have had to add the script based discovery module anyway so we save a step by just choosing script to start with.

On the general page, edit the element ID, display name and target fields as shown.

Note:  Be as focused as possible when selecting a target.  In this case, we will create our discovery disabled and select the system to run the discovery via override so using Windows Computer is OK.

image 
For testing only, I am choosing to run my discovery every minute. In practice, discovery should be run at a much less frequent interval.

image

Next we need to add our script.  We will use datafromfile.vbs as our script name and then paste in our script to do the discovery.

image

We also need to pass two parameters to the script so in the parameters dialogue, add MPElement and TargetID.

image

A sample script is below and is available in the attached MP at the end of this post.  I’ve commented the script to demonstrate what it is doing.  Note that is is a basic script without error checking and additional logic you may wish to use – but the script does get the job done for our sample.  For our example, the input file is a comma delimited text file with just a few systems in it.  The text file I use is also attached at the end of this blog post.

SCRIPT
'Declare variables to be used by the script
Dim SourceId
Dim objConnection
Dim oRS
Dim sConnectString
Dim ManagedEntityID
Dim oAPI
Dim oDiscoveryData
Dim oAttributes
Dim oDataCenter
Dim oHostName
Dim oModel
Dim oRack
Dim oFSO
Dim oINst
dim fsoFile

'Read in command line arguments to script
SourceId                = WScript.Arguments(0)
ManagedEntityId         = WScript.Arguments(1)

'Set up our environment

'Sets up OpsMgr scripting objects
Set oAPI                = CreateObject("MOM.ScriptAPI")
'Sets up OpsMgr Discovery Data
Set oDiscoveryData      = oAPI.CreateDiscoveryData(0,SourceId,ManagedEntityId)
'Sets up File system Object
Set oFSO             = CreateObject("Scripting.FileSystemObject")
'Sets up access to file containing data using the file system object
set fsoFile            = ofso.opentextfile("c:\datafile.txt", 1)

'Read first line of file that contains header info - don't need
'this so just reading and throwing away. 
oAttributes=fsofile.readline

'Loop to read through our text file, one line at a time
'Each line of the file will be processed to pull out data
'of interest and then added to our discovery bag.
Do Until fsofile.AtEndOFStream
    oAttributes=fsofile.readline
    oDataCenter=Left(oAttributes,(InStr(oAttributes,",")-1))
    oAttributes=Right(oAttributes,Len(oAttributes)-Len(oDataCenter)-1)
    oHostName=Left(oAttributes,(InStr(oattributes,",")-1))
    oAttributes=Right(oAttributes,Len(oAttributes)-Len(oHostName)-1)
    oModel=Left(oAttributes,(InStr(oattributes,",")-1))
    oAttributes=Right(oAttributes,Len(oAttributes)-Len(oModel)-1)
    oRack=Left(oAttributes,(InStr(oattributes,",")-1))
    oAttributes=Right(oAttributes,Len(oAttributes)-Len(oRack)-1)
    oHeadless=oAttributes
    oAttributes=""
    wscript.echo oDataCenter, oHostName, oModel, oRack, oHeadless

    'Create in an instance of discovery data for the class
    Set oInst = oDiscoveryData.CreateClassInstance("$MPElement[Name='WIndows_Computer_Extended_Discovery_MP.Windows_Computer_Extended_from_Flat_File']$")

    'Add the properties to the instance of discovery data.
    'Note that the principal name attribute here must be FQDN
    'format and must exist in the database.  Also, case sensitivity
    'is important.  Notice the capitol I in WIndows.  This is required
    'because the class was declared with the capitolization shown.
    Call oInst.AddProperty("$MPElement[Name='Windows!Microsoft.Windows.Computer']/PrincipalName$", oHostName)
    Call oInst.AddProperty("$MPElement[Name='WIndows_Computer_Extended_Discovery_MP.Windows_Computer_Extended_from_Flat_File']/DataCenter$", oDataCenter)
    Call oInst.AddProperty("$MPElement[Name='WIndows_Computer_Extended_Discovery_MP.Windows_Computer_Extended_from_Flat_File']/Model$", oModel)
    Call oInst.AddProperty("$MPElement[Name='WIndows_Computer_Extended_Discovery_MP.Windows_Computer_Extended_from_Flat_File']/Rack$", oRack)
    Call oInst.AddProperty("$MPElement[Name='WIndows_Computer_Extended_Discovery_MP.Windows_Computer_Extended_from_Flat_File']/Headless$", oHeadless)
    Call oDiscoveryData.AddInstance(oInst)
Loop

'Once the discovery data is obtained it needs to be submitted
Call oAPI.Return(oDiscoveryData)

INPUT TEXT FILE
DataCenter,HostName,Model,Rack,Headless
Scranton,dc01.opsmgr.net,Dell,P01,yes
Philly,sql1cln1.opsmgr.net,IBM,XN6,no
Dallas,VS4.opsmgr.net,HP,034,no
Scranton,VS2.opsmgr.net,IBM,C30,yes
Dallas,OMDB.opsmgr.net,Dell,107,yes

With the wizard completed, go back into the properties of the discovery and add the discovered class as shown.

image

Almost done.  I mentioned earlier that we need to create this class disabled.  The reason is that we have all of our attribute data in a flat file – so we only need to run this on the system that hosts that flat file.  In my case I run this on the RMS.  As long as the frequency of discovery isn’t too great then running on the RMS, which owns all groups anyway, is not a big deal.  Note that in what we have done so far there is no option to disable the discovery by default.  We will have to do that in XML.  So save your management pack and then open it in any XML editor – even notepad – and locate the discovery as shown.  Note that it is enabled by default.

image

Change it to false, save the file and then import it into your management group.  Once imported navigate to the authoring node, select object discoveries and scope your view to windows computer extended.  The discovery from the sample MP should appear.  Select properties on it and you will see that this discovery is disabled by default.

image

As mentioned earlier, all we want to do is enable this discovery for whichever system is hosting our flat file.  In our example I’m using the RMS so I will introduce an override to enable this discovery on my RMS only.

image

With all of this done, we just have to wait a few minutes and can take a look at the results of our newly extended class.  In the monitoring node, select discovered inventory and then change the target type to our extended class.

image

Note that all of the systems that show up have all attributes you would find in the standard windows computer class plus those added from text file.  But also notice that the total membership of the extended class is far less than the parent windows computer class as shown.

image

OK, wait – something is wrong here.  When you extend a class the resulting class should be a copy of the base class – including all members – the only difference is the added attributes – right!?  Yes, but not here.  In this case the only objects that get added to the class are the ones that have a corresponding entry in the flat file. 

All done.  A final note.  The flat file is just one example – the source could be anything you want – a database, AD, whatever – just adjust the script to work with that source and the process is the same.