At long last I think I'm ready to post my solution to inventorying/viewing installed software across a network.

I'm using 4.10, 4.02, and KixForms 2.0.3

There are three phases to the process.

First the data collection which is done by the SoftwareUDF.kix script. It's in the form of a UDF so it can be used for "scanning" remote computers. It hangs when it cannot connect to the remote host so when I use it I work a ping in there to test network connectivity.

Example:
Computer($computer,$logpath)

The $computer var should not contain "\\" and the $logpath should end in a "\".
code:
Function Software($Computer,$LogPath)
Dim $programs
Dim $Subkeys
$index = 0
While @error = 0
ReDim preserve $subkeys[Ubound($subkeys)+1]
$index = $index+1 ?$computer
$subkeys[Ubound($subkeys)] = EnumKey("\\$Computer\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall",$index)
Loop
$nul = ReDirectOutput ("$logpath$computer.log",1)
For Each $key in $subkeys
$Displayname = ReadValue ("\\$Computer\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$key","Displayname")
If $Displayname <> ""
ReDim preserve $programs[Ubound ($programs)+1]
$programs[Ubound($programs)] = $Displayname
EndIf
Next
join($programs,"~*~")
$nul = ReDirectOutput("")
EndFunction

Second phase is parsing all of the .log files obtained from the first script and adding the data to a microsoft access data base.

You'll need to create an access database with one table called TBL_PROGRAM. In the table there should be two columns, first "Computer" second "Program".

Since I'm no expert on COM scripting, this script will only work with 4.02. Props to Breaker since I only modified his script. I should also add that any program name with a ' in it will have it striped out.

$Loggpath should point to the directory where the .dat files are located (should end in "\"). $DBPATH should point to where the data base is located (should end in "\"). $DBFile should be the name of your data base file.

code:
$Loggpath = "H:\loggs\"
$DBPath = "H:\loggs\"
$DBFile = "inventory.mdb"

$RC=SetOption("WrapAtEOL","On")
$DSN="Driver={Microsoft Access Driver (*.mdb)}; DBQ=$DBPath$DBFile"
$Connection = CreateObject("ADODB.Connection")
$Command = CreateObject("ADODB.Command")
$Recordset = CreateObject("ADODB.Recordset")
If $Connection
? "Connected"
$Connection.ConnectionString = $DSN
$Connection.Open()
$Command.ActiveConnection = $Connection
$Recordset.CursorType = 3
$Recordset.LockType = 3
$Recordset.ActiveCommand = $Command
$file = Dir("$loggPath*.log")
While $file <> "" AND @error = 0
$computer = SubStr($file,1,InStr($file,".log")-1)
$nul = Open(1,"$loggpath$file") If @error <> 0 ?@serror Exit EndIf
$ProgArray = ReadLine(1) If @error <> 0 ?@serror Gosub End EndIf
$ProgArray = Split($ProgArray,"~*~")
For Each $program in $ProgArray
If InStr($Program,"'") <> 0 $A = Split($Program,"'") For Each $B in $A $C=$C+$B Next $Program = $C $C="" EndIf
$CHECK_ENTRY_PROGRAM = "SELECT * FROM TBL_PROGRAM WHERE COMPUTER='$computer' AND PROGRAM='$program';"
$Command.CommandText = $CHECK_ENTRY_PROGRAM
$Recordset.Open($Command)
If $Recordset.RecordCount < 1
$Recordset.AddNew If @ERROR <> 0 ?@SERROR EndIf
$Recordset.Fields("Computer").Value = "$computer" If @ERROR <> 0 ?@SERROR EndIf
$Recordset.Fields("Program").Value = "$program" If @ERROR <> 0 ?@SERROR EndIf
EndIf
$Recordset.Update
$Recordset.Close()
Next
?"$computer Completed Successfully"
:End
$nul=Close(1)
$file = Dir()
Loop
$Connection.Close()
$Connection = 0
$Recordset = 0
$Command = 0
Else
Goto error
EndIf
:end
?$numarr
Exit 321
:error
Exit

Last phase is the feedback form. Basically there’s two ways to view the information in the data base. First is a list of all computers in the DB, as you select a computer name it shows what software is installed on that computer. Second is list of all software on the computers you collected data from. As you select a software name it returns a list of computers that software is installed on.

Since the current release of KixForm does not automatically sort the listbox, the software listbox is a bit of a mess. I'm hoping the KixForm 2.0.4 release will include the Sorted property which will make the software list much easier to navigate through. I could use one of the sort array UDF's, but that will dramatically lengthen the time between clicking on "Search for Software by Computer" and the list popping up. Because this process is already lengthy (longer depending on how many computers you collected data from) I've added a progress bar so you don't think the script is hanging.

$DBPath should point to where you data base is located (should end in "\"). $DBFile is the name of your data base.

code:
Break on

Dim $SearArr
$DBPath = "h:\loggs\"
$DBFile = "inventory.mdb"

$FORM = CreateObject("Kixtart.FORM")

$FORM.CAPTION = "Software Inventory"
$FORM.HEIGHT = 200
$FORM.WIDTH = 210
$FORM.FONTNAME = "Arial"
$FORM.FONTSIZE = 9
$FORM.CENTER

$SoftButton = $FORM.CommandButton("Search for Software by Computer",3,3,$FORM.Width-12,$FORM.Height/2-34)
$CompButton = $FORM.CommandButton("Search for Computer by Software",3,$SoftButton.Height+7,$FORM.Width-12,$FORM.Height/2-34)
$QuitButton = $FORM.CommandButton("Quit",3,$CompButton.Top + $CompButton.Height + 4,$FORM.Width-12,30)
$SoftButton.OnClick = '$$CompForm.Show if ubound($$ReturnData) = -1 $$ReturnData=GetDBData() CompForm($$ReturnData) endif'
$CompButton.OnClick = '$$SoftForm.Show if ubound($$ReturnData2) = -1 $$ReturnData2=GetDBData() SoftForm($$ReturnData2) endif'
$QuitButton.OnClick = 'Quit()'


$CompForm = CreateObject("Kixtart.FORM")
$CompForm.CAPTION = "Search for Software by Computer"
$CompForm.HEIGHT = 437
$CompForm.WIDTH = 337
$CompForm.FONTNAME = "Arial"
$CompForm.FONTSIZE = 9
$CompForm.CENTER
$FraComp = $CompForm.Frame("",5,5,320,402)
$SelCompTxt = $FraComp.Label("Select a Computer:",10,20,150,20)
$SelCompBox = $FraComp.ListBox(,10,40,150,150)
$InsProTxt = $FraComp.Label("Installed Programs:",10,200,150,20)
$InsProBox = $FraComp.ListBox(,10,220,300,150)
$ExitButton = $FraComp.CommandButton("Exit",165,40,150-2,30)
$ProgComp = $FraComp.ProgressBar(,10,375,300,20)
$ProgComp.Min = 0
$ExitButton.OnClick = '$$CompForm.Show(0)'

$SoftForm = CreateObject("Kixtart.FORM")
$SoftForm.CAPTION = "Search for Computer by Software"
$SoftForm.HEIGHT = 437
$SoftForm.WIDTH = 337
$SoftForm.FONTNAME = "Arial"
$SoftForm.FONTSIZE = 9
$SoftForm.CENTER
$FraSoft = $SoftForm.Frame("",5,5,320,402)
$SelProgTxt = $FraSoft.Label("Select Software:",10,20,150,20)
$SelProBox = $FraSoft.ListBox(,10,40,300,150)
$InsCompTxt = $FraSoft.Label("Installed on this Computer:",10,200,150,20)
$InsCompBox = $FraSoft.ListBox(,10,220,150,150)
$ExitButton2 = $FraSoft.CommandButton("Exit",165,220,150-2,30)
$ProgSoft = $FraSoft.ProgressBar(,10,375,300,20)
$ExitButton2.OnClick = '$$SoftForm.Show(0)'

$FORM.Show
$Form.SetFocus

While $FORM.Visible OR $CompForm.Visible OR $SoftForm.Visible
$=Execute($FORM.DoEvents)
Loop

Function CompForm($ReturnData)
$1=1
$0=0
$CompForm.SetFocus
$ProgComp.Max = Val(Ubound($ReturnData[0]))
$SelCompBox.List = StripCopies($ReturnData[0])
$SelCompBox.OnClick = '$$InsProBox.List = GetInfo($$SelCompBox.Value,$$0,$$1,$$ReturnData)'
EndFunction

Function SoftForm($ReturnData)
$1=1
$0=0
$SoftForm.SetFocus
$ProgSoft.Max = Val(Ubound($ReturnData[1]))
$SelProBox.List = StripCopies($ReturnData[1])
$SelProBox.OnClick = '$$InsCompBox.List = GetInfo($$SelProBox.Value,$$1,$$0,$$ReturnData2)'
EndFunction

Function GetDBData()
Dim $CompArr
Dim $ProgArr
Dim $DBArr[2]
$connect = CreateObject("ADODB.Connection")
$connectstring = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=$DBPath$DBFile"
$connect.Open($connectstring)
$queryDB = "SELECT * FROM TBL_PROGRAM"
$queryDB = $connect.Execute($queryDB)
While NOT $queryDB.EOF
$dataComp=$queryDB.Fields("Computer").value
$dataProg=$queryDB.Fields("Program").value
$queryDB.movenext
ReDim preserve $CompArr[Ubound($CompArr)+1]
ReDim preserve $ProgArr[Ubound($ProgArr)+1]
$CompArr[Ubound($CompArr)] = $dataComp
$ProgArr[Ubound($ProgArr)] = $dataprog
Loop
$connect.Close
$DBArr[0] = $CompArr
$DBArr[1] = $ProgArr
$GetDBData = $DBArr
EndFunction

Function GetInfo($SearchFor,$SMultiNum,$RMultiNum,$Array)
Dim $InfoArray
$inter = 0
For Each $find in $Array[$SMultiNum]
If $find = "$SearchFor"
ReDim preserve $InfoArray[Ubound($InfoArray)+1] $InfoArray[Ubound($InfoArray)] = $Array[$RMultiNum][$inter]
EndIf
$inter = $inter + 1
Next
$GetInfo = $InfoArray
EndFunction

Function StripCopies($striArray)
$on = 1
Dim $searArr
For Each $add in $StriArray
If Ubound($SearArr) = -1
ReDim $searArr[0] $SearArr[0] = $add
EndIf
$counter = 0
While Ubound($SearArr)+1 <> $counter
If $add = $searArr[$counter]
$on = 1
EndIf
$counter = $counter + 1
Loop
$counter = 0
If $on = 0 ReDim preserve $SearArr[Ubound($SearArr)+1] $SearArr[Ubound($SearArr)] = $add EndIf
$on = 0
$ProgComp.Value = $ProgComp.Value+1
$ProgSoft.Value = $ProgSoft.Value+1
Next
$ProgComp.Value = 0
$ProgSoft.Value = 0
$StripCopies = $SearArr
EndFunction

Don't know why I bother but here are the pics hosted from geocities.

 -
 -
 -

If those don't work just go here http://www.geocities.com/greenmaze/ and take a look at menu.jpg sbc.jpg and cbs.jpg.

Let me know how to improve this. Thanks.