IBM Support

Creating Config Files from a SCRIPT extension in TADDM

Technical Blog Post


Abstract

Creating Config Files from a SCRIPT extension in TADDM

Body

The Problem

A customer wants to audit all their Windows Computer Systems so that they know what local accounts exist on each. TADDM doesn't collect this information by default, however, we can use a Computer System Template Extension to collect the list of local users and store those as a Config File.

The Solution

Login to the TADDM Discovery Console, go to the Computer Systems drawer, and ensure that the Windows Computer System Template is enabled.

image

 

Now, create the $COLLATION_HOME/etc/templates/commands/WindowsComputerSystemTemplate file with a line to execute a script on every Windows Computer System:

SCRIPT:etc/templates/commands/extension-scripts/getUsers.py

Now, create the jython script getUsers.py (getUsers.py.tgz)

Almost every extension script will start with the same code:

# Standard Library Imports
import sys
import java
from java.lang import System

# Set the Path information
coll_home = System.getProperty("com.collation.home")
System.setProperty("jython.home",coll_home + "/external/jython-2.1")
System.setProperty("python.home",coll_home + "/external/jython-2.1")

jython_home = System.getProperty("jython.home")
sys.path.append(jython_home + "/Lib")
sys.path.append(coll_home + "/lib/sensor-tools")
sys.prefix = jython_home + "/Lib"

import string
import traceback
from jarray import array

#  Local App Imports
import sensorhelper

########################
# LogError      Error logger
########################
def LogError(msg):
    '''
    Print Error Message using Error Logger with traceback information
    '''
    log.error(msg)
    (ErrorType, ErrorValue, ErrorTB) = sys.exc_info()
    traceback.print_exc(ErrorTB)

########################
# LogDebug      Print routine for normalized messages in log
########################
def LogDebug(msg):
    '''
    Print Debug Message using debug logger (from sensorhelper)
    '''
    # assuming SCRIPT_NAME and template name are defined globally...
    # point of this is to create a consistent logging format to grep
    # the trace out of
    log.debug(msg)

########################
# LogInfo Print routine for normalized messages in log
########################
def LogInfo(msg):
    '''
    Print INFO level Message using info logger (from sensorhelper)
    '''

 # assuming SCRIPT_NAME and template name are defined globally...
    # point of this is to create a consistent logging format to grep
    # the trace out of
    log.info(msg)

 

#-----------------------------------------------------------------------------
# MAIN
#-----------------------------------------------------------------------------

# The first thing we need to do is get the Objects that are passed to a sensor
(os_handle,result,server,seed,log) = sensorhelper.init(targets)

LogInfo(" ****** STARTING getUsers.py ******* ")

At this point, I would run discovery of a WindowsComputerSystem to make sure the script is firing. If it is, you will see a message in the log about Starting getUsers.py.

$ cat WindowsComputerSystemSensor* |grep STARTING

2015-06-04 10:52:36,162 DiscoverManager [DiscoverWorker-21] 2015060410504386#WindowsComputerSystemSensor-192.168.37.160 INFO sys.CustomComputerSystemAgent -  ****** STARTING getUsers.py *******

 

Now, we query Win32_UserAccount via WMI and store the result in a sorted list:

users=""
try:
        accounts = sensorhelper.getWmiCimV2Class('Win32_UserAccount')
        userlist=[]
        users=""
        for acct in accounts:
                #print acct['Name']
                if (acct['LocalAccount'] == "True"):
                        #users=users + acct['Name'] + "\n"
                        userlist.append(acct['Name'])
        userlist.sort()
        for a in userlist:
                users = users + a + "\n"

The sensorhelper library has a defect which was fixed for AppServer, but not for ComputerSystem. In order to modify logical content associated with a ComputerSystem, we have to access the target hashmap directly:

        cfarray = targets.get("contentarray")

        cf = sensorhelper.newModelObject("cdm:app.ConfigFile")
        cf.setContent(users)
        cf.setURI("file://" + server.getName() + "//localAccounts")
        cf.setFixedPath("localAccounts")
        #cf.setChecksum(calc_checksum(users))
        cfarray.add(cf)

The final part of the script is just catching the exception if the WMI "try" fails.

except:
        msg = "failed to fetch the Win32_Account class via WMI"
        LogError(msg)
        result.warning(msg)

Now, when discovery is run against a target, we can go to the Config File tab of the details panel for that target and see the list of local users:

image

And if we click on that link:

image

One final point about this extension. The customer then tried to compare various computer systems against a known-good computer system but, for some reason, TADDM would NOT show the differences found between this localAccounts configuration file. TADDM would report the differences between a statically collected file (like the system32/drivers/etc/hosts). I used api.bat to dump out the xml for the computer system and the only real difference I found between my programmatically created Config File and the one that TADDM collected from the file system was that the TADDM-collected one had the checksum set. I modifed my code to calculate the checksum and lo-and-behold, the comparison started showing the differences.

Here is the function to set the checksum. Simply add this to the file and uncomment the call to calc_checksum() in the code above.

def calc_checksum(s):
        sum = 0
        for i in range(len(s)):
                sum = sum + ord(s[i])
        temp = sum % 256 #modulo 256
        rem = -temp # two's complement
        return '%2X' % (rem & 0xFF)

 

 

[{"Business Unit":{"code":"BU053","label":"Cloud & Data Platform"},"Product":{"code":"SSPLFC","label":"Tivoli Application Dependency Discovery Manager"},"Component":"","Platform":[{"code":"PF025","label":"Platform Independent"}],"Version":"","Edition":"","Line of Business":{"code":"LOB45","label":"Automation"}}]

UID

ibm11275364