Inventory script
From WPKG | Open Source Software Deployment and Distribution
This Autoit script can be used to read the per client XML files that get copied to a network share once wpkg.js has finished running (I use the 'Execute after' option) [1]
To have the latest version of wpkg.xml copied to the server, you can either: use WPKG client, and copy this file as "Execute after" action, in config.xml, configure wpkg.js to save this file on the server.
The script also reads in the 'master' package XML files. It then compares the 'revision=' of the master to the clients 'revision=' and flags up any differences that can be emailed to whoever using the third party tool mailsend.exe [2]. It also creates a per client pc CSV file in a subdirectory on the server share where the client XML files are saved (\invent\) and concats all the CSV files into a single all.csv file.
The output of a client invent XML files looks like:
PC NAME,DATE OF XML FILE,DESCRIPTION,PACKAGE ID NAME,PRIORITY,INSTALLED REVISION,MASTER XML REVISION,UPGRADE/DOWNGRADE/BLANK=NOTHING REQUIRED RECOVERY,09/05/2011_15:37,7-Zip,7zip,10,920,920, RECOVERY,09/05/2011_15:37,Activation MS Office 2010,msoffice2010-activation,71,1,1, RECOVERY,09/05/2011_15:37,Adobe Acrobat 9,acrobat9,17,944,944, RECOVERY,09/05/2011_15:37,Adobe Shockwave Player 11,shockwave,50,11.5.7.601,11.5.7.609,Upgrade required
Autoit script
Compile and cmd exe
#Region ;**** Directives created by AutoIt3Wrapper_GUI **** #AutoIt3Wrapper_Outfile=wpkg_invent_chk.exe #AutoIt3Wrapper_Change2CUI=y #EndRegion ;**** Directives created by AutoIt3Wrapper_GUI **** #include <File.au3> #include <Array.au3> #include <Date.au3> #include <Constants.au3> ; *********************************************************************************************************************** ; ; Script to look at the WPKG generated XML files that get copied to the \win-info\wpkg-xml\ share after WPKG has run on ; each pc and compare the installed packages to the master set of SML files on \wpkg\server\WPKG-1.1.2\packages\. A per ; pc csv file is created showing what is installed on that pc. Another csv file is made concatting all the indervidual ; csv files. This 'all' csv file is then read in and all pakcages that require up or downgrading are noted and if required, ; can be emailed to whoever is specified as the first argument to the exe of this script. ; ;C. Mortimer May 2011 ; ; *********************************************************************************************************************** Dim $master_or_computer_path, $master_or_computer_invent_array, $invent $pc_xml_path = EnvGet("LOGONSERVER") & "\win-info\wpkg-xml" $master_xml_path = EnvGet("LOGONSERVER") & "\wpkg\server\WPKG-1.1.2\packages" If @Compiled = 1 Then If $CmdLine[0] > 0 Then If ($CmdLine[1] = "/?") OR ($CmdLine[1] = "?") Then ConsoleWrite("Usage" & @CRLF & @CRLF & "Program to produce a report file per machine name showing the installed WPKG packages as stored in the auto created WPKG files in" & _ " " & $pc_xml_path & "\[machine name].xml. These files are copied from \\[machine name]\c$\windows\temp\wpkg.xml to " & $pc_xml_path & " when ever the wpkg.js scipt has " & _ "finished running. The report files are stored in " & $pc_xml_path & "\invent\. " & $pc_xml_path & "\invent\all.csv is a concat of all the csv files. If this script is " & _ "is passed an argument of an email address, a report of any machines with packages out of sync with the master WPKG XML file (" & $master_xml_path & "\ can be emailed to whoever." & _ @CRLF & @CRLF & "C. Mortimer May 2011" & @CRLF) Exit ElseIf StringInStr($CmdLine[1], "@") Then $email_address = $CmdLine[1] Else $email_address = "" EndIf Else $email_address = "" EndIf Else $email_address = "foo@gmail.com" EndIf $csv_title_txt = "PC Name,Date of XML File,Description,Package ID Name,Priority,Installed Revision,Master XML Revision,Upgrade/Downgrade/blank=Nothing Required" $downgrade_string = "Downgrade required" $upgrade_string = "Upgrade required" $mailsend = EnvGet("LOGONSERVER") & "\netlogon\bin\mailsend.exe" $s_domain = "somewhere" $s_SmtpServer = "smtp.somewhere.cam.ac.uk" $s_FromName = "" $s_FromAddress = "wibble@gmail.com" $s_ToAddress = "-t " & $email_address $s_Subject = "PC's with missmatched WPKG programs" If FileExists($pc_xml_path) = 0 Then ConsoleWrite("Error. Unable to read files in " & $pc_xml_path & ", exiting" & @CRLF) Exit ElseIf FileExists($master_xml_path) = 0 Then ConsoleWrite("Error. Unable to read files in " & $master_xml_path & ", exiting" & @CRLF) Exit EndIf If Not FileExists($pc_xml_path & "\invent\*") Then DirCreate($pc_xml_path & "\invent\") ; Lets work out the current master revision numbers for each id $invent = "" _make_xml_array($master_xml_path) ; Now work out the list of installed packages for each machine generated xml file... $filedelete = FileDelete($pc_xml_path & "\invent\*.csv") ;~ ConsoleWrite ("deleted files = " & $filedelete & @CRLF) _make_xml_array($pc_xml_path) ;Write to the console a list of csv files in $pc_xml_path & "\invent\ $csv_files = _FileListToArray($pc_xml_path & "\invent\", "*.csv", 1) ConsoleWrite(@CRLF) For $r = 1 To $csv_files[0] Step 1 ConsoleWrite(StringUpper($csv_files[$r]) & @CRLF) Next ConsoleWrite(@CRLF & "The list of CSV files above are the files in " & $pc_xml_path & "\invent\ showing the inventory of the WPKG programs installed. " & _ "'ALL.CSV' is a concatination of all the indervidual CSV files." & @CRLF & @CRLF) ; Now sort out the mailing of the machines needing up/downgrading $error_list = $csv_title_txt & @CRLF If FileExists($pc_xml_path & "\invent\all.csv") Then Dim $all_csv_file _FileReadToArray($pc_xml_path & "\invent\all.csv", $all_csv_file) $all_error_occurance_id = _ArrayFindAll($all_csv_file, "grade required", "", "", "", 1) If @error < 1 Then For $o = 0 To _ArrayMaxIndex($all_error_occurance_id) Step 1 $error_list = $error_list & $all_csv_file[$all_error_occurance_id[$o]] & @CRLF Next ConsoleWrite("Machines and packages that differ from the Master XML files = " & @CRLF & @CRLF & $error_list & @CRLF) If StringLen($email_address) > 0 Then If FileExists($mailsend) Then $wpkg_invent_email_file = EnvGet("temp") & "\wpkg_invent_email.txt" $write2file = FileOpen($wpkg_invent_email_file, 2) FileWriteLine($write2file, $error_list) FileClose($write2file) $sendmail = $mailsend & " -v -d " & $s_domain & " -smtp " & $s_SmtpServer & " " & $s_ToAddress & " -f " & $s_FromAddress & _ " -sub """ & $s_Subject & """ +cc +bc -m """ & $wpkg_invent_email_file & """,text/plain,i" $std_run_reg = Run($sendmail, "", "", $STDERR_CHILD + $STDOUT_CHILD) $q = 1 $timewatch = TimerInit() ; Make a note of the current time While $q = 1 $std_out_read = StdoutRead($std_run_reg) $std_err_read = StderrRead($std_run_reg) If (StringLen($std_out_read) > 0) OR (StringLen($std_err_read) > 0) Then ConsoleWrite(@CRLF & @CRLF & "Email sent" & @CRLF) $q = 2 EndIf If TimerDiff($timewatch) > 5000 Then $q = 2 ConsoleWrite(@CRLF & @CRLF & "Error sending email :(" & @CRLF) EndIf WEnd Sleep(1000) FileDelete($wpkg_invent_email_file) Else ConsoleWrite("The file '" & EnvGet("LOGONSERVER") & "\netlogon\bin\mailsend.exe' is missing, unable to send any email" & @CRLF) EndIf EndIf Else ConsoleWrite("All of the pcs are up to date with their WPKG packages" & @CRLF) EndIf Else ConsoleWrite("The file '" & $pc_xml_path & "\invent\all.csv' is missing, unable to send any email or write to STDOUT the list of out of date pcs" & @CRLF) EndIf ; ======================================================================================================================= Func _make_xml_array($master_or_computer_path) $xml_files = _FileListToArray($master_or_computer_path, "*.xml", 1) ; make an array listing each master xml file ;~ _ArrayDisplay ($xml_files) For $p = 1 To $xml_files[0] Step 1 ; for each xml file... If $master_or_computer_path = $pc_xml_path Then ;~ ConsoleWrite ("pc = " & StringReplace($xml_files[$p], ".xml", "") & @CRLF) $invent = "" EndIf Dim $xml_file_contents _FileReadToArray($master_or_computer_path & "\" & $xml_files[$p], $xml_file_contents) ; create an array, $xml_file_contents listing its contents ;~ _ArrayDisplay ($xml_file_contents) $occurance_id = _ArrayFindAll($xml_file_contents, " revision=", "", "", "", 1) ; in the array $xml_file_contents, return all the indices (lines) containing ' revision=' ;~ _ArrayDisplay ($occurance_id) For $o = 0 To _ArrayMaxIndex($occurance_id) Step 1 $id_line = FileReadLine($master_or_computer_path & "\" & $xml_files[$p], $occurance_id[$o]) Do ; replace tabs with a single space $id_line = StringReplace($id_line, " ", " ") Until @extended = 0 Do ; replace double space with a single space $id_line = StringReplace($id_line, " ", " ") Until @extended = 0 Do ; replace a space at the start of the line with null If StringLeft($id_line, 1) = " " Then $id_line = StringTrimLeft($id_line, 1) Until StringLeft($id_line, 1) <> " " Do ; replace <wpkg> at the start of the line with null If StringLeft($id_line, 6) = "<wpkg>" Then $id_line = StringTrimLeft($id_line, 6) Until StringLeft($id_line, 6) <> "<wpkg>" ;~ ConsoleWrite ("$id_line = " & $id_line & @CRLF) ; Now make an array and run a For loop to replace the %version%/%shortversion%/%subversion% int he XML file with it's variable value Dim $_aArray[3] $_aArray[0] = "shortversion" $_aArray[1] = "version" $_aArray[2] = "subversion" For $ver In $_aArray If StringInStr($id_line, "%" & $ver & "%") Then ;~ ConsoleWrite("line number = " & $occurance_id[0] & "(" & $ver & ")" & @CRLF) $doloop = 1 $doloop_line_no = $occurance_id[$o] Do $find_version = FileReadLine($master_or_computer_path & "\" & $xml_files[$p], $doloop_line_no + 1) ; Read the line 1 line after the line containing ' revision=' in the xml file ;ConsoleWrite("$find_version = " & $find_version & " on line " & $doloop_line_no & @CRLF) If StringInStr($find_version, "<variable name=""" & $ver & """") Then ; If this '1 line after revision=' contains $ver (%version%, %shortversion% or %subversion%... $find_version_split = StringSplit($find_version, '""') ; make an array of this line... If @error = 1 Then $find_version_split = StringSplit($find_version, '''') ; if no double quotes are used, split using single quotes. $find_version_value = $find_version_split[_ArraySearch($find_version_split, "value=", "", "", "", 1) + 1] ; and note the value set in the array indice one after 'value=' ;ConsoleWrite("$find_version_value = " & $find_version_value & @CRLF) $doloop = 2 ;ConsoleWrite($id_line & @CRLF) ;_ArrayDisplay($find_version_split) EndIf $doloop_line_no = $doloop_line_no + 1 ; increment $doloop_line_no by one and run the Do loop again, this time looking for the next line down. Until $doloop = 2 $id_line = StringReplace($id_line, "%" & $ver & "%", $find_version_value) ;~ ConsoleWrite("$id_line = " & $id_line & @CRLF) EndIf Next ;~ ConsoleWrite("$id_line = " & $id_line & @CRLF) If $master_or_computer_path = $master_xml_path Then $id_line_split = StringSplit($id_line, '""') ; split the line with double quotes as the deliminator. If @error = 1 Then $id_line_split = StringSplit($id_line, '''') ; if no double quotes are used, split using single quotes. $invent = $invent & "," & $id_line_split[_ArraySearch($id_line_split, "id=", "", "", "", 1) + 1] ; Create a string $invent contianing the id name... $invent = $invent & "," & $id_line_split[_ArraySearch($id_line_split, "revision=", "", "", "", 1) + 1] ; and the revision number. If StringLeft($invent, 1) = "," Then $invent = StringTrimLeft($invent, 1) ; If the first character on the left if a ',' remove it. ;~ ConsoleWrite("$invent after reading master files = " & $invent & @CRLF) $master_or_computer_invent_array = StringSplit($invent, ",") ; Turn the string $invent into an array. ElseIf $master_or_computer_path = $pc_xml_path Then $id_line_split = StringSplit($id_line, '""') ;~ _ArrayDisplay ($id_line_split) $invent = $invent & StringReplace($xml_files[$p], ".xml", "") ; start creating the indevidual package csv line by obtaining the pc name... $time = FileGetTime($master_or_computer_path & "\" & $xml_files[$p], 0, 0) ; then the date and time the pc's xml file was created $invent = $invent & "," & $time[2] & "/" & $time[1] & "/" & $time[0] & "_" & $time[3] & ":" & $time[4] $invent = $invent & "," & $id_line_split[_ArraySearch($id_line_split, "name=", "", "", "", 1) + 1] ; then add the 'name' text... $id = _ArraySearch($id_line_split, "id=", "", "", "", 1) $invent = $invent & "," & $id_line_split[$id + 1] ; then the 'id' for the package... $invent = $invent & "," & $id_line_split[_ArraySearch($id_line_split, "priority=", "", "", "", 1) + 1] $revision = _ArraySearch($id_line_split, "revision=", "", "", "", 1) $invent = $invent & "," & $id_line_split[$revision + 1] ; then the revision number... $master_revision = $master_or_computer_invent_array[_ArraySearch($master_or_computer_invent_array, $id_line_split[$id + 1], "", "", "", 0) + 1] ; now add the revision number for the same id but from the master xml files $invent = $invent & "," & $master_revision If $id_line_split[$revision + 1] = $master_revision Then $invent = $invent & "," & "" ElseIf $id_line_split[$revision + 1] > $master_revision Then $invent = $invent & "," & $downgrade_string ElseIf $id_line_split[$revision + 1] < $master_revision Then $invent = $invent & "," & $upgrade_string EndIf $invent = $invent & @CRLF EndIf Next ; Now save each output to a per machine name file and concat all of the output into one file If $master_or_computer_path = $pc_xml_path Then ConsoleWrite("Inventory of installed packages on " & StringUpper ($xml_files[$p]) & " = " & @CRLF & @CRLF & $csv_title_txt & @CRLF & $invent & @CRLF) ;~ ConsoleWrite ("FileReadLine (" & $pc_xml_path & "\invent\" & StringReplace($xml_files[$p], ".xml", "") & ".csv, 1) = " & FileReadLine ($pc_xml_path & "\invent\" & StringReplace($xml_files[$p], ".xml", "") & ".csv", 1) & @CRLF) If FileReadLine($pc_xml_path & "\invent\" & StringReplace($xml_files[$p], ".xml", "") & ".csv", 1) = "" Then $save_csv = FileOpen($pc_xml_path & "\invent\" & StringReplace($xml_files[$p], ".xml", "") & ".csv", 1) FileWrite($save_csv, StringUpper($csv_title_txt) & @CRLF) FileClose($save_csv) ;~ ConsoleWrite ("writing title to " & $pc_xml_path & "\invent\" & StringReplace($xml_files[$p], ".xml", "") & ".csv" & "(" & FileReadLine ($pc_xml_path & "\invent\" & StringReplace($xml_files[$p], ".xml", "") & ".csv", 1) & ")" & @CRLF) EndIf $save_csv = FileOpen($pc_xml_path & "\invent\" & StringReplace($xml_files[$p], ".xml", "") & ".csv", 1) ;~ ConsoleWrite ("now saving $invent to " & StringReplace($xml_files[$p], ".xml", "") & ".csv" & @CRLF) FileWrite($save_csv, $invent) FileClose($save_csv) ;~ ConsoleWrite ("FileReadLine (" & $pc_xml_path & "\invent\all.csv, 1) = " & FileReadLine ($pc_xml_path & "\invent\all.csv", 1) & @CRLF) If FileReadLine($pc_xml_path & "\invent\all.csv", 1) = "" Then $save_csv_all = FileOpen($pc_xml_path & "\invent\all.csv", 1) FileWrite($save_csv_all, StringUpper($csv_title_txt) & @CRLF) FileClose($save_csv_all) ;~ ConsoleWrite ("writing title to " & $pc_xml_path & "\invent\all.csv" & "(" & FileReadLine ($pc_xml_path & "\invent\all.csv", 1) & ")" & @CRLF) EndIf $save_csv_all = FileOpen($pc_xml_path & "\invent\all.csv", 1) ;~ ConsoleWrite ("now saving $invent to " & $pc_xml_path & "\invent\all.csv" & @CRLF) FileWrite($save_csv_all, $invent) FileClose($save_csv_all) EndIf Next EndFunc ;==>_make_xml_array