Canned script not working - "Software installed or uninstalled" gives false positives

I created a monitor using the canned script: “Software installed or uninstalled”. I wanted to see if any new software was installed or uninstalled on any of my nodes.
Unfortunately, this script doesn’t work. And I figured out why.

The script seems to export a list of installed software on the first run.
on subsequent runs, it exports again and compares to the export of previous runs.

This has 2 negative effects:

1.) On the first run, it will always generate a false positive alert that new software has been installed.
2.) Because the comparison goes line by line instead of app by app, it will compare one app to another app from the previous files previous line number. therefore it will tall yu that one app “updated” to a new “version” or another app.

Ex:

"Endpoint Manager Communication Client 6.27.25138.19040
has Updated to Stamps.com Web Postage Plug-in 1.2.0.99

Java Auto Updater 2.8.201.9
Lower version is replaced with Intel(R) Chipset Device Software 10.1.17541.8066

Intel(R) Chipset Device Software 10.1.17541.8066
has Updated to Realtek Card Reader 10.0.17763.31244

Realtek Card Reader 10.0.17763.31244
Lower version is replaced with Google Update Helper 1.3.34.11

Google Update Helper 1.3.34.7
has Updated to Intel(R) Trusted Connect Services Client 1.48.197.0"

Here is the original ITArian canned script code:

=========================================
import os,sys,_winreg,re,socket,difflib,filecmp
workdir=os.environ[‘PROGRAMDATA’]+r’\c1_temp’
if not os.path.isdir(workdir):
os.mkdir(workdir)
path=“C:\ProgramData\c1_temp\Installed.txt”
path2=“C:\ProgramData\c1_temp\Installed2.txt”
fnd=0
fnd1=0
val=0
val1=0
def alert(arg):
sys.stderr.write("%d%d%d" % (arg, arg, arg))
def files():
file_name = “Installed.txt”
cur_dir = “C:\ProgramData\c1_temp”
file_list = os.listdir(cur_dir)
parent_dir = os.path.dirname(cur_dir)
if file_name in file_list:
global fnd
fnd=1
else:
print “File not found”
global fnd1
fnd1=1

def collectprograms(rtkey,pK,kA):
import _winreg
import os
list=[]
store=[]
oK=_winreg.OpenKey(rtkey,pK,0,kA)
i=0
if fnd==1:
File2=open(path2,“a+”)
elif fnd1==1:
File1=open(path,“a+”)
while True:
try:
bkey=_winreg.EnumKey(oK,i)
vkey=os.path.join(pK,bkey)
oK1=_winreg.OpenKey(rtkey,vkey,0,kA)
try:
DN,bla=_winreg.QueryValueEx(oK1,‘DisplayName’)
DV,bla=_winreg.QueryValueEx(oK1,‘DisplayVersion’)
inlist=[DN.strip(), DV.strip()]
if inlist[1]==“None”:
gh=0
else:
if fnd==1:
File2.write(inlist[0]+" “+inlist[1]+”
“)
elif fnd1==1:
File1.write(inlist[0]+” “+inlist[1]+”
")
except:
pass
i+=1
except:
break
_winreg.CloseKey(oK)

def swchanges():
list1=[]
ale=0
v=filecmp.cmp(path,path2)
if False==0:
with open(path) as file:
data=file.read()
with open(path2) as file:
data2=file.read()
text1Lines = data.splitlines(1)
text2Lines = data2.splitlines(1)
diffInstance = difflib.Differ()
diffList = list(diffInstance.compare(text2Lines, text1Lines))
for line in diffList:
if line[0] == ‘-’:
print “Installed softwares are :”
list1.append(line)
print line
ale=ale+1

diffList = list(diffInstance.compare(text1Lines, text2Lines))
for line in diffList:
if line[0] == ‘-’:
print “Uninstalled softwares are :”
print line
list1.append(line)
ale=ale+1
if v==True:
print "No changes in Softwares at end point "

if len(text1Lines)==len(text2Lines):
count=1
for i in range(0,len(text2Lines)):
v=cmp(text1Lines[i],text2Lines[i])
if v==0:
continue
elif v==1:
print text1Lines[i]+ " Lower version is replaced with “+text2Lines[i]
elif v== -1:
print text1Lines[i]+” has Updated to "+text2Lines[i]
k=[]
for i in list1:
j = i.replace(’- ‘,’’)
k.append(j)
for i in text1Lines:
for j in k:
if i==j:
text1Lines.remove(i)
for i in text2Lines:
for j in k:
if i==j:
text2Lines.remove(i)
if len(text1Lines)==len(text2Lines):
count=1
for i in range(0,len(text2Lines)):
v=cmp(text1Lines[i],text2Lines[i])
if v==0:
continue
elif v==1:
print text1Lines[i]+ " Lower version is replaced with "+text2Lines[i]
elif v== -1:
print text1Lines[i]+"Updated to "+text2Lines[i]
if ale>0:
alert(1)
else:
alert(0)

def programsinstalled():
print"
"
uninstallkey=‘SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall’
if ‘PROGRAMFILES(X86)’ in os.environ.keys():
rklist=[(_winreg.HKEY_LOCAL_MACHINE,uninstallkey,_winreg.KEY_WOW64_32KEY | _winreg.KEY_READ),
(_winreg.HKEY_LOCAL_MACHINE,uninstallkey,_winreg.KEY_WOW64_64KEY | _winreg.KEY_READ),
(_winreg.HKEY_CURRENT_USER,uninstallkey,_winreg.KEY_WOW64_32KEY | _winreg.KEY_READ),
(_winreg.HKEY_CURRENT_USER,uninstallkey,_winreg.KEY_WOW64_64KEY | _winreg.KEY_READ)]
else:
rklist=[(_winreg.HKEY_LOCAL_MACHINE,uninstallkey,_winreg.KEY_READ),
(_winreg.HKEY_CURRENT_USER,uninstallkey,_winreg.KEY_READ)]
collected=’’
uninstalled=’’
error=’’
blacklisted=’’
hasnoss=[]
ic=0
uc=0
ec=0
for i in rklist:
col=collectprograms(i[0], i[1], i[2])

name=os.environ[‘username’]
print 'PC-NAME : '+name
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.connect((“8.8.8.8”, 80))
print "IP-ADDRESS : " + (s.getsockname()[0])

files()
programsinstalled()
swchanges()
os.remove(path2)

Thank you for pointing this out @nnsit . We forwarded your observation to the script developers to let them further analyze the script / procedure.

@nnsit ,

Our Scripts Team confirmed, that your above explanation is correct. On the first run, it will generate a false positive alert that new software has been installed. It will work perfectly from 2nd hit since comparison then occurs. The comparison does not happen line with line, It’s a line with all lines on the other file. Thus, probability wise, it will give you the correct result.

Can you amend the script to exit after the first run by testing the fnd or fnd1 global from the files() function output? I haven’t gone through the script in detail, but it looks as though fnd1 is the result of the test whether the installed.txt file already exists, and, if it does, then this is not the first run.

So running the functions would be something like:

files()
programsinstalled()

    If fnd1==1:

      swchanges()

    os.remove(path2)