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:
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":
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.
When the report is run, you see the data that has been collected and stored in the columns that we provided through the XML:
That is all there is to it!
I hope this has been helpful.