Video Screencast Help
Symantec Connect login will not be available from 7am-1pm PT, Saturday April 12th, estimated. During that time, you will not be able to log in or engage in any activity on the site such as posting, commenting, or voting. You can still view and search content. Sorry for the inconvenience.

Custom Inventory – Pulling Values from the Registry

Created: 20 May 2009 • Updated: 20 May 2009 | 5 comments
Language Translations
Mike.Langford's picture
+8 10 Votes
Login to vote

The purpose of this article is to provide a walkthrough for creating a custom inventory job that will retrieve values from the registry and store them in Altiris where they can be reported on.

The following five files and executables are required to run a custom inventory that will pull information from the registry:

  • AeXCustInv.exe
  • AeXInvSoln.exe
  • AeXNSInvCollector.exe
  • An INI file with Custom Inventory command lines and settings
  • An XML file that tells the custom inventory what information to pull and what table to put it in.

Example:

imagebrowser image

Let's begin with the XML file since that is by far the most complex piece of the process. A lot of the XML files that you use for custom inventories will be static from one inventory to the next. Once you figure out the pieces that need to change each time it is a great idea to script the XML creation so you can quickly generate the file with just a few command line parameters.

Here is a sample of a basic XML file that we can use to pull image version information from the registry in my organization:

<?xml version="1.0" encoding="windows-1252"?>
<InventoryClasses>

<InventoryClass name="GWL_SW_ImageInfo" manufacturer='Altiris' description='' platform='Win32' version='1.0' mifClass='Altiris|GWL_SW_ImageInfo|1.0'>
<xml xmlns:s="uuid:BDC6E3F0-6DA3-11d1-A2A3-00AA00C14882" xmlns:dt="uuid:C2F41010-65B3-11d1-A29F-00AA00C14882" xmlns:rs="urn:schemas-microsoft-com:rowset" xmlns:z="#RowsetSchema">
<s:Schema id="RowsetSchema">
<s:ElementType name="row" content="eltOnly" rs:updatable="true">
<s:AttributeType name="c0" rs:name="BaseVersion" rs:number="0" rs:nullable="true" mifAttrId="0">
<s:datatype dt:type="string" dt:maxLength="50"/>
</s:AttributeType>
</s:ElementType>
</s:Schema>
<rs:data>
<%set path="HKEY_LOCAL_MACHINE\SOFTWARE\MICROSOFT\MSSQLSERVER"%>
<z:row
c0="<%writexml "reg:HKEY_LOCAL_MACHINE\SYSTEM\Setup\Base Version"%>"
/>
</rs:data>
</xml>
</InventoryClass>

</InventoryClasses>

Like any XML file, this may look slightly daunting at first, but there is very little information that needs to change from one XML to the next, so lets start by going over the non-static pieces of the file. First, your inventory needs a name. When it runs, your inventory will actually create a new table in your Altiris database using the name of your inventory with an Inv appended to the front, so in the example above, my inventory is named GWL_SW_ImageInfo, so the table that gets created in the database is going to be named Inv_ GWL_SW_ImageInfo. The name needs to go in two places.

<?xml version="1.0" encoding="windows-1252"?>
<InventoryClasses>

<InventoryClass name="<NAME GOES HERE>" manufacturer='Altiris' description='' platform='Win32' version='1.0' mifClass='Altiris|<NAME GOES HERE>|1.0'>

Next, we need to name the attribute or value that we will be pulling from the registry. This will actually be the name of the column in your new table once the inventory has run. In my example above, my attribute name is "BaseVersion", so once this inventory runs, I will have an Inv_GWL_SW_ImageInfo table with a "Base Version" column that will hold the value pulled from the registry. You can also specify here what the data type and length are going to be for the column. I have used string type and set the max length to 50 because I don't anticipate version information exceeding 50 characters.

<xml xmlns:s="uuid:BDC6E3F0-6DA3-11d1-A2A3-00AA00C14882" xmlns:dt="uuid:C2F41010-65B3-11d1-A29F-00AA00C14882" xmlns:rs="urn:schemas-microsoft-com:rowset" xmlns:z="#RowsetSchema">
<s:Schema id="RowsetSchema">
<s:ElementType name="row" content="eltOnly" rs:updatable="true">
<s:AttributeType name="c0" rs:name="<ATTRIBITE NAME GOES HERE>" rs:number="0" rs:nullable="true" mifAttrId="0">
<s:datatype dt:type="<DATA TYPE GOES HERE>" dt:maxLength="<LENGTH GOES HERE>"/>
</s:AttributeType>
</s:ElementType>
</s:Schema>

Finally, we just need to tell the inventory where to pull its information from. This is done in the final piece of the XML file. This would pull the information from this key in my registry:

<rs:data>
<%set path="HKEY_LOCAL_MACHINE\SOFTWARE\MICROSOFT\MSSQLSERVER"%>
<z:row
c0="<%writexml "reg:<PATH TO YOUR REGISTRY KEY GOES HERE> "%>"
/>
</rs:data>
</xml>
</InventoryClass>

</InventoryClasses>

My example above would pull populate the value in the new table for my machine with "XP Base 2":

imagebrowser image

So overall, there are only six values in the XML file you would need to change from one inventory to the next. There are a couple more things that can be updated if you want to record multiple values with one inventory. Doing so would create a table with multiple columns to hold the values for each of the keys.

Here is an example where I am pulling seven values from the registry with a single inventory. Basically the only other things that need to change to support multiple entries are the AttributeType "name", "rs:number", and "mifAttrId". Notice how they all increment for each attribute that will be stored. Then when you pull the values at the bottom of the XML, make sure that the values correspond to the appropriate AttributeType name:

<?xml version="1.0" encoding="windows-1252"?>
<InventoryClasses>

<InventoryClass name="GWL_SW_ImageInfo" manufacturer='Altiris' description='' platform='Win32' version='1.0' mifClass='Altiris|GWL_SW_ImageInfo|1.0'>
<xml xmlns:s="uuid:BDC6E3F0-6DA3-11d1-A2A3-00AA00C14882" xmlns:dt="uuid:C2F41010-65B3-11d1-A29F-00AA00C14882" xmlns:rs="urn:schemas-microsoft-com:rowset" xmlns:z="#RowsetSchema">
<s:Schema id="RowsetSchema">
<s:ElementType name="row" content="eltOnly" rs:updatable="true">
<s:AttributeType name="c0" rs:name="BaseVersion" rs:number="0" rs:nullable="true" mifAttrId="0">
<s:datatype dt:type="string" dt:maxLength="255"/>
</s:AttributeType>
<s:AttributeType name="c1" rs:name="BuildVersion" rs:number="1" rs:nullable="true" mifAttrId="1">
<s:datatype dt:type="string" dt:maxLength="255"/>
</s:AttributeType>
<s:AttributeType name="c2" rs:name="BuildInfo" rs:number="2" rs:nullable="true" mifAttrId="2">
<s:datatype dt:type="string" dt:maxLength="255"/>
</s:AttributeType>
<s:AttributeType name="c3" rs:name="BuildDate" rs:number="3" rs:nullable="true" mifAttrId="3">
<s:datatype dt:type="string" dt:maxLength="255"/>
</s:AttributeType>
<s:AttributeType name="c4" rs:name="DSJobName" rs:number="4" rs:nullable="true" mifAttrId="4">
<s:datatype dt:type="string" dt:maxLength="255"/>
</s:AttributeType>
<s:AttributeType name="c5" rs:name="DSJobTime" rs:number="5" rs:nullable="true" mifAttrId="5">
<s:datatype dt:type="string" dt:maxLength="255"/>
</s:AttributeType>
<s:AttributeType name="c6" rs:name="DSJobUser" rs:number="6" rs:nullable="true" mifAttrId="6">
<s:datatype dt:type="string" dt:maxLength="255"/>
</s:AttributeType>
</s:ElementType>
</s:Schema>
<rs:data>
<%set path="HKEY_LOCAL_MACHINE\SOFTWARE\MICROSOFT\MSSQLSERVER"%>
<z:row
c0="<%writexml "reg:HKEY_LOCAL_MACHINE\SYSTEM\Setup\Base Version"%>"
c1="<%writexml "reg:HKEY_LOCAL_MACHINE\SYSTEM\Setup\Build Version"%>"
c2="<%writexml "reg:HKEY_LOCAL_MACHINE\SYSTEM\Setup\Build Information"%>"
c3="<%writexml "reg:HKEY_LOCAL_MACHINE\SYSTEM\Setup\Build Date"%>"
c4="<%writexml "reg:HKEY_LOCAL_MACHINE\SYSTEM\Setup\DSJobName"%>"
c5="<%writexml "reg:HKEY_LOCAL_MACHINE\SYSTEM\Setup\DSJobTime"%>"
c6="<%writexml "reg:HKEY_LOCAL_MACHINE\SYSTEM\Setup\DSJobUser"%>"
/>
</rs:data>
</xml>
</InventoryClass>

</InventoryClasses>

Overall, still not too difficult, and it is something that can be easily scripted so it is not a manual creation every time you need an inventory run.

That covers the XML. Next, let's look at the INI file that holds command lines and parameters for the inventory agent. Here are the entire contents of my INI file. Short and sweet:

aexcustinv.exe /in .\GWL_SW_ImageInfo.xml /out GWL_SW_ImageInfo.nsi
aexnsinvcollector.exe /hidden /nsctransport /v default /useguid

This is telling the custom inventory agent to use the XML file as input for the inventory. It then creates the nsi that holds the results from the inventory, and the inventory collector agent sends it up to the Altiris server to be processed.

Now all that is left to do is to run the AeXInvSoln.exe with a command line to tell it to read the INI file for input.

AeXInvSoln.exe /hidden /s GWL_SW_ImageInfo.ini

This can be set up as a task to run on machines in your environment just like any other package push, using the "AeXInvSoln.exe" as the exe that will be pushed out and giving it "/hidden /s GWL_SW_ImageInfo.ini" as its command line.

Now that our custom inventory has run, our new table now appears in the list that is accessed through the report builder.

imagebrowser image

When the report is run, you see the data that has been collected and stored in the columns that we provided through the XML:

imagebrowser image

That is all there is to it!

I hope this has been helpful.

Comments 5 CommentsJump to latest comment

Broadway's picture

 Awesome tutorial!  Works like a champ!

0
Login to vote
Sid Markolov's picture

but I am happy to say it worked for me as well!  First shot out of hte box!

Thanks!

Sid

0
Login to vote
Leigh Webber's picture

But wait -- you said, "Now that our custom inventory has run, our new table now appears in the list that is accessed through the report builder."

How exactly do you do that? Starting from the Management Console, what exactly do I click to get the "report builder". All of my attempts lead to a New Computer Report page, but nothing on that page lets me pick from "Available Objects" as you depict.

0
Login to vote
Leigh Webber's picture

I figured out the answer to my earlier question. For the benefit of others, here it is.

When you create a Custom Data Class, the system creates a new table called dbo.Inv_Your_Class_Name. It has one field for each of the attributes you defined for your custom data class, plus an indexed field called _ResourceGuid. The _ResourceGuid field is a foreign key that points to the Guid field that uniquely identifies all "resources" in the system. To create a report showing your custom data class, you build a query that joins the dbo.Inv_Your_Class_Name to a view that includes the relevant data elements. For example, if your custom data class pertains to computers, then join dbo.Inv_Your_Class_Name to dbo.vComputerEx, which is a built-in view that surfaces several useful computer attributes. Using a view is much easier than using the underlying tables -- but if you're really hard core, you can look inside the view definitions to see how they ultimately draw from the underlying tables. Trust me -- use the views instead.

Here's my example. Note: I have not included any of the "scoping" ornaments that you will see when you SQL-ize a Management Console report. I'm not sure what those are all for -- my guess is that they relate to permissions or something. But that doesn't matter to me, so I just go for the bare metal query as follows:

 SELECT c.Name as Computer, c.[User], c.[IP Address],
 d.[File_Name]
 FROM dbo.vComputerex as c LEFT OUTER JOIN dbo.Inv_DandS_Plugin_Version as d
 ON c.Guid = d._ResourceGuid
WHERE c.IsManaged = 1
ORDER BY  c.Name

My custom data class is DandS Plugin Version. The corresponding table is dbo.Inv_DandS_Plugin_Version which I alias to d. My custom data class has an attribute called File_Name, which I want to report on. The join is on the Guid column of the built-in vComputerEx view and the _ResourceGuid column of the custom data class table. I filterd with c.IsManaged = 1 to restrict the report to managed computers. I used a LEFT OUTER JOIN so that I would get every managed computer in the report whether it had any custom data class rows or not. I also tossed in the computer's name, primary user, and IP address, which are handy columns in the vComputerEx view.

Gee -- wouldn't it be nice if the documentation included something like this?

+2
Login to vote
Capt Altiris's picture

The instructions worked like a charm once you create the custom data class. This can be done via Settings / All Settings. Expand Discovery and Inventory then Inventory Solution and then choose Manage Custom Data Classes

+1
Login to vote