Developing Content 101 – INI Files


Update: Added link to Location sensor on Tanium community website.
So you’d like to create Tanium Content for distribution to your infrastructure. Knowing what you want to do goes a long way to knowing how to do it with Tanium. For this article we’ll start with a very simple scenario: You need to create a brand new INI file that will hold physical location data about each of your endpoints. This INI file will be configured manually but you’d like the data retrieved whenever you need it.
To make this happen we’ll need a few things:
1. Two packages… one for Windows and one for Mac/Linux. Packages are not cross-platform, thus to do what we want, we’ll need to create two packages. The Windows package will contain a simple VBS script that takes are incoming arguments and writes out an INI file. The Mac/Linux both handle shell scripts, so we can create a single shell script to do the same thing our VBS will be doing.
2. One sensor… These are indeed cross-platform and we can embed both a VBS and SH scripts for all three operating systems to read our INI file and return the results.

Development Environment
To get started, we’ll need a test box for all three environments. Most of us have a file synchronization application running like Google Drive, Microsoft’s OneDrive, Dropbox or others. This is a great place to work from since many of these apps also have cross-platform clients.
Start by creating a directory for your project as well as our content. Make it look like this:
> Location Project
>> Content
>>> Sensors
>>>> Location (https://community.tanium.com/repo/sensor/393)
>>> Packages
>>>> Set Location (Windows)
>>>> Set Location (Mac/Linux)

Package: Set Location (Windows)
Most likely you are working from a windows workstation, so let’s start with the VB script since we can very quickly test it on this system. Here is the sudo code for our VB Script:
1. Capture our command line arguments into variables
2. If our INI file already exists, then open for writing, otherwise create it for writing.
3. Write to the INI file in the proper INI format all of our incoming arguments.
To accomplish this we’re going to need two of our highly reused functions:
GetTaniumDir and GeneratePath
These functions will give us the full path of our Tanium Client directory and create any sub directories as needed.
Here is the full Set Location for Windows VB Script:

‘=======================================
’ Set Location
’=======================================

If WScript.Arguments.Count >= 5 Then
Country = Replace(WScript.Arguments.Item(0),“%20”,“ ”)
State = Replace(WScript.Arguments.Item(1),“%20”,“ ”)
City = Replace(WScript.Arguments.Item(2),“%20”,“ ”)
Street = Replace(WScript.Arguments.Item(3),“%20”,“ ”)
Number = Replace(WScript.Arguments.Item(4),“%20”,“ ”)

Const ForReading = 1
Const ForWriting = 2
Const ForAppending = 8
Set fso = CreateObject(“Scripting.FileSystemObject”)

locationFilePath = GetTaniumDir(““) & ”Location.ini”
If fso.FileExists(locationFilePath) Then
WScript.Echo “Location.ini File Does Exist – Overwriting”
Set locationFile = fso.OpenTextFile(locationFilePath, ForWriting)
Else
WScript.Echo “Location.ini File Does Not Exist – Creating”
Set locationFile = fso.CreateTextFile(locationFilePath)
End If

locationFile.WriteLine “[Location]”
locationFile.WriteLine “Country=” & Country
locationFile.WriteLine “State=” & State
locationFile.WriteLine “City=” & City
locationFile.WriteLine “Street=” & Street
locationFile.WriteLine “Number=” & Number
locationFile.Close
End If

Function GetTaniumDir(strSubDir)
‘GetTaniumDir with GeneratePath, works in x64 or x32
‘looks for a valid Path value

Dim objShell
Dim keyNativePath, keyWoWPath, strPath

Set objShell = CreateObject(“WScript.Shell”)

keyNativePath = “HKLM\Software\Tanium\Tanium Client”
keyWoWPath = “HKLM\Software\Wow6432Node\Tanium\Tanium Client”

’ first check the Software key (valid for 32-bit machines, or 64-bit machines in 32-bit mode)
On Error Resume Next
strPath = objShell.RegRead(keyNativePath&“\Path”)
On Error Goto 0

If strPath = ““ Then
’ Could not find 32-bit mode path, checking Wow6432Node
On Error Resume Next
strPath = objShell.RegRead(keyWoWPath&”\Path“)
On Error Goto 0
End If

If Not strPath = ”“ Then
If strSubDir <> ”“ Then
strSubDir = ”” & strSubDir
End If

Dim fso
Set fso = WScript.CreateObject(“Scripting.Filesystemobject”)
If fso.FolderExists(strPath) Then
If Not fso.FolderExists(strPath & strSubDir) Then
’’Need to loop through strSubDir and create all sub directories
GeneratePath strPath & strSubDir, fso
End If
GetTaniumDir = strPath & strSubDir & “”
Else
’ Specified Path doesn’t exist on the filesystem
WScript.Echo ”Error: “ & strPath & ” does not exist on the filesystem“
GetTaniumDir = False
End If
Else
WScript.Echo ”Error: Cannot find Tanium Client path in Registry”
GetTaniumDir = False
End If
End Function ’GetTaniumDir

Function GeneratePath(pFolderPath, fso)
GeneratePath = False
If Not fso.FolderExists(pFolderPath) Then
If GeneratePath(fso.GetParentFolderName(pFolderPath), fso) Then
GeneratePath = True
Call fso.CreateFolder(pFolderPath)
End If
Else
GeneratePath = True
End If
End Function ’GeneratePath

Test our “Set Location” script by using the following command line:
cscript setlocation.vbs “US” “Arkansas” “Springdale” “Daniel Ave” “1234”
You should see a brand new “Location.ini” file appear within your Tanium Client directory.
(Note that this script writes to the Program Files directory, so you’ll need administrative access on your command prompt.)

Location Sensor (Windows)
Since we’re still our windows computer, let’s quickly develop the windows script for reading our new Location.ini file. Just like the “Set Location” script, we’ll need a few reusable functions and a new one that will easily read our INI file: GetTaniumDir, GeneratePath, and ReadIni
The sudo code for this script is extremely easy!

1. Locate our INI file
2. Read each property within the INI file
3. Echo to the command prompt which gets picked up by the Tanium client during sensor execution.
The following is our Location Sensor’s VBScript:

‘=======================================
’ Read Location
’=======================================

Const ForReading = 1
Const ForWriting = 2
Const ForAppending = 8
Set fso = CreateObject(“Scripting.FileSystemObject”)
locationFilePath = GetTaniumDir(““) & ”Location.ini“
location = Trim(ReadIni(locationFilePath, ”Location“, ”Country“))
location = location & ”|“ & Trim(ReadIni(locationFilePath, ”Location“, ”State“))
location = location & ”|“ & Trim(ReadIni(locationFilePath, ”Location“, ”City“))
location = location & ”|“ & Trim(ReadIni(locationFilePath, ”Location“, ”Street“))
location = location & ”|“ & Trim(ReadIni(locationFilePath, ”Location“, ”Number”))
wscript.echo location

Function ReadIni( myFilePath, mySection, myKey )
’ This function returns a value read from an INI file

’ Arguments:
’ myFilePath [string] the (path and) file name of the INI file
’ mySection [string] the section in the INI file to be searched
’ myKey [string] the key whose value is to be returned

’ Returns:
’ the [string] value for the specified key in the specified section

’ CAVEAT: Will return a space if key exists but value is blank

’ Written by Keith Lacelle
’ Modified by Denis St-Pierre and Rob van der Woude
Const ForReading = 1
Const ForWriting = 2
Const ForAppending = 8

Dim intEqualPos
Dim objFSO, objIniFile
Dim strFilePath, strKey, strLeftString, strLine, strSection

Set objFSO = CreateObject( “Scripting.FileSystemObject” )

ReadIni = “”
strFilePath = Trim( myFilePath )
strSection = Trim( mySection )
strKey = Trim( myKey )

If objFSO.FileExists( strFilePath ) Then
Set objIniFile = objFSO.OpenTextFile( strFilePath, ForReading, False )
Do While objIniFile.AtEndOfStream = False
strLine = Trim( objIniFile.ReadLine )

‘ Check if section is found in the current line
If LCase( strLine ) = “[” & LCase( strSection ) & “]” Then
strLine = Trim( objIniFile.ReadLine )

‘ Parse lines until the next section is reached
Do While Left( strLine, 1 ) <> “[”
‘ Find position of equal sign in the line
intEqualPos = InStr( 1, strLine, “=”, 1 )
If intEqualPos > 0 Then
strLeftString = Trim( Left( strLine, intEqualPos – 1 ) )
‘ Check if item is found in the current line
If LCase( strLeftString ) = LCase( strKey ) Then
ReadIni = Trim( Mid( strLine, intEqualPos + 1 ) )
‘ In case the item exists but value is blank
If ReadIni = “” Then
ReadIni = ” ”
End If
‘ Abort loop when item is found
Exit Do
End If
End If

‘ Abort if the end of the INI file is reached
If objIniFile.AtEndOfStream Then Exit Do

‘ Continue with next line
strLine = Trim( objIniFile.ReadLine )
Loop
Exit Do
End If
Loop
objIniFile.Close
Else
‘WScript.Echo strFilePath & ” doesn’t exists. Exiting…”
Wscript.Quit 1
End If
End Function

Function GetTaniumDir(strSubDir)
‘GetTaniumDir with GeneratePath, works in x64 or x32
‘looks for a valid Path value

Dim objShell
Dim keyNativePath, keyWoWPath, strPath

Set objShell = CreateObject(“WScript.Shell”)

keyNativePath = “HKLM\Software\Tanium\Tanium Client”
keyWoWPath = “HKLM\Software\Wow6432Node\Tanium\Tanium Client”

’ first check the Software key (valid for 32-bit machines, or 64-bit machines in 32-bit mode)
On Error Resume Next
strPath = objShell.RegRead(keyNativePath&“\Path”)
On Error Goto 0

If strPath = ““ Then
’ Could not find 32-bit mode path, checking Wow6432Node
On Error Resume Next
strPath = objShell.RegRead(keyWoWPath&”\Path“)
On Error Goto 0
End If

If Not strPath = ”“ Then
If strSubDir <> ”“ Then
strSubDir = ”” & strSubDir
End If

Dim fso
Set fso = WScript.CreateObject(“Scripting.Filesystemobject”)
If fso.FolderExists(strPath) Then
If Not fso.FolderExists(strPath & strSubDir) Then
’Need to loop through strSubDir and create all sub directories
GeneratePath strPath & strSubDir, fso
End If
GetTaniumDir = strPath & strSubDir & “”
Else
’ Specified Path doesn’t exist on the filesystem
WScript.Echo ”Error: “ & strPath & ” does not exist on the filesystem“
GetTaniumDir = False
End If
Else
WScript.Echo ”Error: Cannot find Tanium Client path in Registry”
GetTaniumDir = False
End If
End Function ’GetTaniumDir

Function GeneratePath(pFolderPath, fso)
GeneratePath = False
If Not fso.FolderExists(pFolderPath) Then
If GeneratePath(fso.GetParentFolderName(pFolderPath), fso) Then
GeneratePath = True
Call fso.CreateFolder(pFolderPath)
End If
Else
GeneratePath = True
End If
End Function ’GeneratePath

Now we have our location.vbs script… so let’s test it… run the following command line:
cscript location.vbs
You should see the lcoation information echo’d out to the command line and pipe | delimited.

Set Location (Mac/Linux)
What we’re trying to accomplish with writing and reading INI files is easily done with Shell script. We are not doing anything special and thus a common Mac/Linux script is possible. If you are trying to “DO” something else, you need to consider the various flavors of Linux like: Red Hat, CentOS, Ubuntu, and so many more.
The sudo code for our Mac/Linux shell script is identical to that of the Windows VBScript, so refer to that section for details.

Let’s switch over to our non-windows computer for further development. Typically I prefer to work on my Mac laptop but on occasion I’ll boot up my Ubuntu laptop to have a different experience. Here is the full script for setting the location on Posix systems:

#!/bin/bash
#=======================================
#Set Location
#=======================================
Country=$1
State=$2
City=$3
Street=$4
Number=$5

echo “[Location]” > ‘../../Location.ini’
echo “Country=$Country” | sed -e “s/%20/ /g” >> ‘../../Location.ini’
echo “State=$State” | sed -e “s/%20/ /g” >> ‘../../Location.ini’
echo “City=$City” | sed -e “s/%20/ /g” >> ‘../../Location.ini’
echo “Street=$Street” | sed -e “s/%20/ /g” >> ‘../../Location.ini’
echo “Number=$Number” | sed -e “s/%20/ /g” >> ‘../../Location.ini’

The working directory for packages in Tanium is within the client directory… Tanium Client/Downloads/Action_XXXX (Where XXXX is your action number). This means to write a file within the Tanium Client directory, you need to go up two as shown in the script above.
To test the above setlocation.sh script, use the following shell commands:
chmod +x setlocation.sh
./setlocation.sh “US” “Arkansas” “Springdale” “Daniel Ave” “1234”
You should find the Location.ini file two directories above where you developed this… and if you’re using the directory structure described at the beginning of this article, it’ll be within the “Content” directory.

Location Sensor (Mac/Linux)
Let’s quickly write up our location.sh script for reading the ini file. Note that the working directory for sensors is the root directory of your Tanium Client… Thus there is no need to go up two directories like we did in the package script. Here is the full location.sh script:

#!/bin/bash
#=======================================
#Read Location
#=======================================
if [ -f Location.ini ]; then
Country=grep -w "^Country" Location.ini| cut -d= -f2
State=grep -w "^State" Location.ini| cut -d= -f2
City=grep -w "^City" Location.ini| cut -d= -f2
Street=grep -w "^Street" Location.ini| cut -d= -f2
Number=grep -w "^Number" Location.ini| cut -d= -f2

echo “$Country|$State|$City|$Street|$Number”
else
echo “”
fi

To test this, copy the Location.ini file into the same directory as your script and run the following commands:
chmod +x location.sh
./location.sh
You should see the exact same output as our Windows VBScript with the location information pipe | delimited.

Pulling It All Together
Now that we have working and validated scripts… it is extremely easy to switch over to the Tanium Console and wrap them up in sensor and package objects for use on our entire infrastructure.

Building the Sensor:
Open your Tanium Console website and navigate to the Authoring->Sensors section. Click the “Add New Sensor” button in the top right.

We will need to define additional columns for the pipe | delimited values…


Next we’ll want to copy and past our VBScript into the Windows script box, and our Shell Script into both the Mac and Linux script boxes.

Building the Packages:
Open your Tanium Console website and navigate to the Authoring->Packages section. Click the “Add New Package” button in the top right.
We’ll start with the “Set Location (Windows)” package. In the files section, choose the “Add Local Files” button and locate/select the “setlocation.vbs” file.

Upon launch, the console user will need to enter some parameters that are written… so click Advanced Settings and configure as follows:

Next we’ll build the “Set Location (Mac/Linux)” package… and just like before, choose the “Add Local Files” button and locate/select the “setlocation.sh” file.

And just like the windows package, we need to configure a few parameters:

Testing
That’s it. Now it’s time to do some expanded testing in your lab.

Ask the following question: Get Computer Name and Location from all machines
Your machines will all reply with no set location. Select one or more of your windows machines and deploy the “Set Location (Windows)” package with some location information to be written.
Run the question again and you should see location information appearing for those windows computers.

Continue testing to validate each of the scenarios you anticipate your console users will want to do.

Post your questions below and I’ll try to answer as best I can.

Advertisements

One thought on “Developing Content 101 – INI Files

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s