Message from discussion
MBSACLI 2.0 /xmlout Parsing Script
Date: Mon, 11 Jul 2005 18:02:42 +0200
From: "Torgeir Bakken \(MVP\)" <Torgeir.Bakken-s...@hydro.com>
Organization: Gjett to ganger
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.6) Gecko/20040113
X-Accept-Language: en-us
MIME-Version: 1.0
Subject: Re: MBSACLI 2.0 /xmlout Parsing Script
References: <lutoc1hmhs2lib90n9c8g3q36rlfpk2qck@4ax.com>
In-Reply-To: <lutoc1hmhs2lib90n9c8g3q36rlfpk2qck@4ax.com>
Content-Type: text/plain; charset=us-ascii; format=flowed
Content-Transfer-Encoding: 7bit
Message-ID: <edBIeKjhFHA.3652@TK2MSFTNGP10.phx.gbl>
Newsgroups: microsoft.public.security.baseline_analyzer
NNTP-Posting-Host: 44-49-164-136.hydro.com 136.164.49.44
Path: g2news1.google.com!news4.google.com!newshub.sdsu.edu!msrtrans!TK2MSFTNGP08.phx.gbl!TK2MSFTNGP10.phx.gbl
Lines: 1
Andrew Aronoff wrote:
> I have written a VBS script that runs MBSACLI 2.0 with the /xmlout
> option and parses the XML output file to produce a readable text file.
>
> The script can be downloaded here:
> http://www.silentrunners.org/MBSACLI%20XML%20Parser.vbs
> (snip)
Hi,
Further down in this post is another mbsacli.exe /xmlout parse script
(that I have written).
Some comment first:
In the thread "MBSACLI 2.0 XML tags", you wrote:
"BTW, I noticed that when Windows Update Agent 2.0 is not installed,
nothing is added to the XML file. That's too bad."
The reason for this is that the error messages from mbsacli.exe goes
to StdErr, while you only redirect StdOut (where all the "normal"
output goes to.
To redirect StdErr to a separate file, use " 2>SomeFile", here is a
snippet from the full script below:
'--------------------8<----------------------
' As the ShortPath property have been used for all paths, extra
' quotes are not needed
sCmd = "%comspec% /c " & sMBSAFilePath & " " & sMBSACmdSwitches _
& " >" & sXMLFilePath & " 2>" & sStdErrFilePath
'--------------------8<----------------------
One small issue here is that mbsacli adds header information to this
error file even when no errors have arised, so you will need to skip
the first 4 lines in that file. See the use of the function CheckStdErr
below for how I have handled this.
Also, I have used Microsoft's XML DOM (MSXML2.DOMDocument) to parse
the XML file.
Here is the full script:
'--------------------8<----------------------
Option Explicit
' Script that parses the output from MBSA 2.0's mbsacli.exe
' (using the /xmlout switch). Any errors in the StdErr is
' also picked up.
'
' Script is reporting both installed and missing updates. See
' the comments for the sXPath variable on how to change it to
' report only on installed or missing updates.
'
' Author: Torgeir Bakken
' Date: 2005-07-11
Const OverwriteIfExist = -1
Const OpenAsASCII = 0
Dim sReportFile, sXMLFilePath, sXPath, oXMLDoc, oErr, oFSO, oShell
Dim sMsgBoxTitle, sStdErr, sStdErrFilePath, sMBSAFilePath
Dim sCabFilePath, sMBSACmdSwitches, sCmd
' ------- Section with variables you can/must change -------
' Path and name of status text file to be created
' Environment variables allowed
sReportFile = "%tmp%\UpdateStatus.txt"
' Path and name of mbsacli.exe, environment variables allowed
sMBSAFilePath = "C:\mbsa2\mbsacli.exe"
' Path and name of wsusscan.cab, environment variables allowed.
' Note that microsoft does not support placement on a network drive.
' Set it to "" if you do not want to use the /catalog switch
' If this string is not empty (""), /catalog <cab file path> will
' be added to the command line of mbsacli.exe
sCabFilePath = "C:\mbsa2\wsusscan.cab"
' Command line switches to be used for mbsacli.exe
' Using /xmlout to run in updates only mode using only mbsacli.exe
' and wusscan.dll. Only these switches can be used with this option:
' /catalog, /wa, /wi, /nvc, /unicode
sMBSACmdSwitches = "/xmlout /nvc"
sXPath = "//UpdateData"
' To list only installed updates, use this one instead:
'sXPath = "//UpdateData[@IsInstalled='true']"
' To list only missing updates, use this one instead:
'sXPath = "//UpdateData[@IsInstalled='false']"
' Title to be used by MsgBox commands
sMsgBoxTitle = "MBSA Update Check"
' ------- Section that prepares for running mbsacli.exe -------
Set oShell = CreateObject("WScript.Shell")
Set oFSO = CreateObject("Scripting.FileSystemObject")
sMBSAFilePath = oShell.ExpandEnvironmentStrings(sMBSAFilePath)
If oFSO.FileExists(sMBSAFilePath) Then
sMBSAFilePath = oFSO.GetFile(sMBSAFilePath).ShortPath
Else
MsgBox sMBSAFilePath & " does not exist!", _
vbCritical + vbSystemModal, sMsgBoxTitle
WScript.Quit
End If
If sCabFilePath <> "" Then
sCabFilePath = oShell.ExpandEnvironmentStrings(sCabFilePath)
If oFSO.FileExists(sCabFilePath) Then
sCabFilePath = oFSO.GetFile(sCabFilePath).ShortPath
sMBSACmdSwitches = sMBSACmdSwitches & " /catalog " & sCabFilePath
Else
MsgBox sCabFilePath & " does not exist!", _
vbCritical + vbSystemModal, sMsgBoxTitle
WScript.Quit
End If
End If
' Get a temporary file name for xml file MbsaCli.exe creates
Do
sXMLFilePath = oFSO.GetSpecialFolder(2).ShortPath _
& "\" & oFSO.GetTempName
Loop While oFSO.FileExists(sXMLFilePath)
' Get a temporary file name for the stderr file MbsaCli.exe creates
Do
sStdErrFilePath = oFSO.GetSpecialFolder(2).ShortPath _
& "\" & oFSO.GetTempName
Loop While oFSO.FileExists(sStdErrFilePath)
' As the ShortPath property have been used for all paths, extra
' quotes are not needed
sCmd = "%comspec% /c " & sMBSAFilePath & " " & sMBSACmdSwitches _
& " >" & sXMLFilePath & " 2>" & sStdErrFilePath
' ------- Section that runs mbsacli.exe and checks the result -------
oShell.Run sCmd, 0, True
sStdErr = CheckStdErr(sStdErrFilePath)
On Error Resume Next
oFSO.DeleteFile sStdErrFilePath
On Error Goto 0
If sStdErr <> "" Then
MsgBox "MBSA failed, error was:" & vbNewLine & vbNewLine & sStdErr, _
vbCritical + vbSystemModal, sMsgBoxTitle
On Error Resume Next
oFSO.DeleteFile sXMLFilePath
On Error Goto 0
WScript.Quit
End If
' ------- Section that parses the output in the xml file -------
Set oXMLDoc = CreateObject("MSXML2.DOMDocument")
oXMLDoc.SetProperty "SelectionLanguage", "XPath"
oXMLDoc.Async = False
oXMLDoc.Load sXMLFilePath
If (oXMLDoc.parseError.errorCode <> 0) Then
Set oErr = oXMLDoc.ParseError
MsgBox "Could not load file " & sXMLFilePath _
& " , error: " & oErr.Reason, _
vbCritical + vbSystemModal, sMsgBoxTitle
WScript.Quit
End If
Dim dicElements, oNodes, oElement
Dim sGUID, sKBID, sBulletinID, iType, iSeverity, bRestartRequired
Dim bIsInstalled, sTitle, sBulletinURL, sInformationURL, sDownloadURL
Dim sType, sSeverity
' use a dictionary object to filter out double entries (will
' exist e.g. for WSUS scans).
Set dicElements = CreateObject("Scripting.Dictionary")
dicElements.CompareMode = vbTextCompare
Set oNodes = oXMLDoc.DocumentElement.SelectNodes(sXPath)
On Error Resume Next
For Each oElement in oNodes
sGUID = "" ' init value
sGUID = oElement.getAttribute("GUID")
If Not dicElements.Exists(sGUID) Then
' init values
sKBID = "": sBulletinID = "": iType = "": iSeverity = ""
bIsInstalled = "": bRestartRequired = "": sTitle = ""
sBulletinURL = "": sInformationURL = "": sDownloadURL = ""
sType = "": sSeverity = ""
sKBID = oElement.getAttribute("KBID")
sBulletinID = oElement.getAttribute("BulletinID")
iType = CInt(oElement.getAttribute("Type"))
Select Case iType
Case 1
sType = "Security Update"
Case 2
sType = "Service Pack"
Case 3
sType = "Update Rollup"
End Select
iSeverity = CInt(oElement.getAttribute("Severity"))
Select Case iSeverity
Case 0
sSeverity = "(no rating)"
Case 1
sSeverity = "Low"
Case 2
sSeverity = "Moderate"
Case 3
sSeverity = "Important"
Case 4
sSeverity = "Critical"
End Select
bIsInstalled = CBool(oElement.getAttribute("IsInstalled"))
bRestartRequired = CBool(oElement.getAttribute("RestartRequired"))
sTitle = oElement.selectSingleNode("Title").text
sBulletinURL = oElement.selectSingleNode _
("References/BulletinURL").text
sInformationURL = oElement.selectSingleNode _
("References/InformationURL").text
sDownloadURL = oElement.selectSingleNode _
("References/DownloadURL").text
' using the GUID value as dictionary key
dicElements.Add sGUID, _
Array( _
sKBID, _
sBulletinID, _
sType, _
sSeverity, _
bIsInstalled, _
bRestartRequired, _
sTitle, _
sBulletinURL, _
sInformationURL, _
sDownloadURL)
End If
Next
oFSO.DeleteFile sXMLFilePath
On Error Goto 0
' ------- Section that creates the report file -------
If dicElements.Count = 0 Then
WScript.Echo "No updates found"
Else
Dim f
Set f = oFSO.CreateTextFile( _
oShell.ExpandEnvironmentStrings(sReportFile), _
OverwriteIfExist, OpenAsASCII)
f.WriteLine "Report on update status run at " & Now
f.WriteLine "---------------------------------" _
& "---------------------------------"
f.WriteLine
f.WriteLine "Total number of update entries found: " _
& dicElements.Count
f.WriteLine "---------------------------------" _
& "---------------------------------"
f.WriteLine
f.WriteLine "Installed updates:" & vbNewLine
ListElements (True)
f.WriteLine "---------------------------------" _
& "---------------------------------"
f.WriteLine
f.WriteLine "Missing updates:" & vbNewLine
ListElements (False)
f.Close
oShell.Run "notepad.exe " & """" & sReportFile & """", 1, False
End If
' Start functions and subs
Function CheckStdErr(ByVal sFile)
Const OpenAsASCII = 0
Const FailIfNotExist = 0
Const ForReading = 1
Dim oFSO, fFile, i, sValue, sLine
Set oFSO = CreateObject("Scripting.FileSystemObject")
If oFSO.GetFile(sFile).Size = 0 Then
CheckStdErr = "Something is wrong, StdErr file size is 0 byte!"
Exit Function ' ----->
End If
Set fFile = oFSO.OpenTextFile(sFile, ForReading, _
FailIfNotExist, OpenAsASCII)
' Skip first 4 lines that always just contains the same header info
For i = 1 To 4
fFile.SkipLine
Next
sValue = "" ' init value
'Parse the rest of the text file
Do While Not fFile.AtEndOfStream
sLine = fFile.Readline
If sLine <> "" Then
If sValue = "" Then
sValue = sLine
Else
sValue = sValue & vbNewLine & sLine
End If
End If
Loop
fFile.Close
CheckStdErr = sValue
End Function
Sub ListElements(ByVal bInstallStatus)
Dim sDicElement
For Each sDicElement In dicElements
If dicElements.Item(sDicElement)(4) = bInstallStatus Then
f.WriteLine "KB ID: " & dicElements.Item(sDicElement)(0)
f.WriteLine "Bulletin ID: " & dicElements.Item(sDicElement)(1)
f.WriteLine "Type: " & dicElements.Item(sDicElement)(2)
f.WriteLine "Severity: " & dicElements.Item(sDicElement)(3)
If bInstallStatus Then
f.WriteLine "Restart Required: " _
& dicElements.Item(sDicElement)(5)
End If
f.WriteLine "Title: " & dicElements.Item(sDicElement)(6)
f.WriteLine "Bulletin URL: " & dicElements.Item(sDicElement)(7)
f.WriteLine "Information URL: " & dicElements.Item(sDicElement)(8)
f.WriteLine "Download URL: " & dicElements.Item(sDicElement)(9)
f.WriteLine
End If
Next
End Sub
'--------------------8<----------------------
--
torgeir, Microsoft MVP Scripting and WMI, Porsgrunn Norway
Administration scripting examples and an ONLINE version of
the 1328 page Scripting Guide:
http://www.microsoft.com/technet/scriptcenter/default.mspx