The Result
The final script is a combination of the original static HTML, the functions I created, and the inline script code I created. Merging everything results in the working event log Web viewer.
Event Log Viewer
Listing 22.1 shows the final event log viewer, in its entirety.
Listing 22.1. Event.asp. Displays local and remote event logs in a Web browser.
<%
'Was the form submitted?
If Request.Form("SUBMIT") = "" Then
'No - set up the form
'Start by getting the local computer name
Set oNet =CreateObject("WScript.Network")
sCompName=oNet.Computername
Response.Write "Computer: " & compname & "<BR>"
Set oNet = Nothing
'Now display the HTML form
%>
<FORM ACTION="event.asp" METHOD="POST">
<Table cellpadding=2 cellspacing=2 border=0>
<TR>
<TD>
<INPUT type="text" name="ComputerName"
value="<% Response.Write CompName%>">
</TD>
<TD>Computer:</TD>
</TR>
<TR>
<TD>
<SELECT name="LogName">
<OPTION value="application">Application</OPTION>
<OPTION value="system">System</OPTION>
<OPTION value="security">Security</OPTION>
</SELECT>
</TD>
<TD>Log</TD>
</TR>
<TR>
<TD><INPUT type="text" name="Source"></TD>
<TD>Event Source</TD>
</TR>
<TR>
<TD>
<SELECT name="Type">
<OPTION value="">All</option>
<OPTION value="information">Information</OPTION>
<OPTION value="warning">Warning</OPTION>
<OPTION value="error">Error</OPTION>
</SELECT>
</TD>
<TD>Type</TD>
</TR>
<TR>
<TD><input type="text" name="EventCode"></TD>
<TD>Event Code</TD>
</TR>
<TR>
<TD><input type="text" name="UserName"</TD>
<TD>User Name</TD>
</TR>
<TR>
<TD><input type="password" name="Password"></TD>
<TD>Password</TD>
</TR>
<TR>
<TD COLSPAN=2 Align=center>
<INPUT type="submit" NAME="Submit" VALUE="Submit">
</TD>
</TR>
</TABLE>
</FORM>
<%
'Here's the end of the original If...Then
'This is executed if the form was submitted
Else
'declare variables
Dim oServices, oResultset, oRecord
Dim sComputerName, sLogFile, sQuery
Dim dtDate, dtTime
'get the network object
set oNet =CreateObject("WScript.Network")
'get a WMI locator
set oLocator = CreateObject("WbemScripting.SWbemLocator")
'get the local computer name
sComputerName = oNet.ComputerName
'build the WMI query
sQuery = "SELECT * FROM Win32_NTLogEvent WHERE Logfile="
'computer name specified?
If(Request("ComputerName") <> "") Then
sComputerName = Request("ComputerName")
End If
'log filename specified?
If(Request("LogName")<> "") Then
sLogFile = Request("LogName")
End If
'append computer name and log file
'to WMI query
sQuery = sQuery & """" & sLogFile & """"
'add source, type, and code to query
If(Request("Source")<> "") Then
sQuery = sQuery & " AND SourceName=" & """" & _
Request("Source") & """"
End If
If(Request("Type") <>"") Then
sQuery = sQuery & " AND Type=" & """" & _
Request("Type") & """"
End If
If(Request("EventCode") <>"") Then
sQuery = sQuery & " AND EventCode=" & _
"""" & Request("EventCode") & """"
End If
'username is blank?
If Request.form("UserName") <> "" Then
'no - connect to local machine
Set oServices = oLocator.ConnectServer(sComputerName, _
"root\default", Request.form("UserName"), _
Request.Form("Password"))
Else
'yes = connect to local computer
Set oServices = oLocator.ConnectServer(sComputerName )
End If
'execute query
Set oResultset = oServices.ExecQuery(sQuery)
'any results?
If(oResultset.Count = 0) Then
'no
Response.Write "<b>Query returned 0 records.</b>"
Else
'yes - display results
'build table header
Response.Write "<TABLE cellspacing=0 cellpadding=3 border=1>"
'build first table row
Response.Write "<TR>"
Response.Write "<TH>Record</TH>"
Response.Write "<TH>Type</TH>"
Response.Write "<TH>Date</TH>"
Response.Write "<TH>Time</TH>"
Response.Write "<TH>Source</TH>"
Response.Write "<TH>Category</TH>"
Response.Write "<TH>Cat Strg</TH>"
Response.Write "<TH>Event</TH>"
Response.Write "<TH>Usr</TH>"
Response.Write "<TH>Computer</TH>"
Response.Write "<TH>Msg</TH>"
Response.Write "</TR>"
'go through each event entry
For Each oRecord In oResultset
'Format the date and time of the entry
dtDate = CDateWMI(oRecord.TimeGenerated)
dtTime = CTimeWMI(oRecord.TimeGenerated)
'write row tag
Response.Write "<TR>"
'write cell tag & record information
Response.Write "<TD>" & oRecord.RecordNumber &" </TD>" & _
"<TD>" & oRecord.Type & "</TD>" & _
"<TD>" & dtDate & "</TD>" & _
"<TD>" & dtTime & "</TD>" & _
"<TD>" & oRecord.SourceName & "</TD>" & _
"<TD>" & oRecord.Category & "</TD>" & _
"<TD>" & oRecord.CategoryString & "</TD>" & _
"<TD>" & oRecord.EventCode & "</TD>" & _
"<TD>" & oRecord.User & "</TD>" & _
"<TD>" & oRecord.ComputerName & "</TD>" & _
"<TD>" & oRecord.Message & "</TD></TR>"
Next
'close the table
Response.Write "</TABLE> </FONT>"
End If
'custom functions
Function CDateWMI(cim_DateTime)
'declare variables
Dim sDateTime, iYear, iMonth, iDay
'convert the date to a string
sDateTime = CStr(cim_DateTime)
'get the year, month, and day
iYear = CInt(Mid(sDateTime, 1, 4))
iMonth = CInt(Mid(sDateTime, 5, 2))
iDay = CInt(Mid(sDateTime, 7, 2))
'reformat into a normal date
CDateWMI = CDate(Join(Array(iMonth, iDay, iYear), "/"))
End Function
Function CTimeWMI(cim_DateTime)
'declare variables
Dim sDateTime, iHours, iMinutes, iSeconds
'convert the time into a string
sDateTime = CStr(cim_DateTime)
'get the hours, minutes, and seconds
iHours = CInt(Mid(sDateTime, 9, 2))
iMinutes = CInt(Mid(sDateTime, 11, 2))
iSeconds = CInt(Mid(sDateTime, 13, 2))
'reformat into a normal time
CTimeWMI = TimeSerial(iHours, iMinutes, iSeconds)
End Function
End If
%>
You shouldn't have to make any changes to this code to get it running in your environment. Just make sure you're using the appropriate user credentials.
NOTE
This script transmits passwords in clear text from your Web browser to the Web server. I don't advise using this script outside of a lab environment unless you secure the connection with a VPN or by using SSL encryption on the Web server. Because you'll be providing administrative passwords, anyone with a network sniffer could intercept the password and wreak havoc on your network.
Event Log Viewer-Explained
The script starts out by seeing whether the form was submitted.
<%
'Was the form submitted?
If Request.Form("SUBMIT") = "" Then
If the form wasn't submitted, I first retrieve the local computer name. This allows me to display that as a default selection. To get the name, I use the WScript.Network object.
'No - set up the form
'Start by getting the local computer name
Set oNet =CreateObject("WScript.Network")
sCompName=oNet.Computername
Response.Write "Computer: " & compname & "<BR>"
Set oNet = Nothing
The script continues by displaying the main HTML form. Notice that I've inserted the local computer name as the default value for the "ComputerName" text box. I've highlighted that code in boldface. I often make little tweaks like this to my static HTML just to make a page a bit easier to use, if I can.
'Now display the HTML form
%>
<FORM ACTION="event.asp" METHOD="POST">
<Table cellpadding=2 cellspacing=2 border=0>
<TR>
<TD>
<INPUT type="text" name="ComputerName"
value="<% Response.Write CompName%>">
</TD>
<TD>Computer:</TD>
</TR>
<TR>
<TD>
<SELECT name="LogName">
<OPTION value="application">Application</OPTION>
<OPTION value="system">System</OPTION>
<OPTION value="security">Security</OPTION>
</SELECT>
</TD>
<TD>Log</TD>
</TR>
<TR>
<TD><INPUT type="text" name="Source"></TD>
<TD>Event Source</TD>
</TR>
<TR>
<TD>
<SELECT name="Type">
<OPTION value="">All</option>
<OPTION value="information">Information</OPTION>
<OPTION value="warning">Warning</OPTION>
<OPTION value="error">Error</OPTION>
</SELECT>
</TD>
<TD>Type</TD>
</TR>
<TR>
<TD><input type="text" name="EventCode"></TD>
<TD>Event Code</TD>
</TR>
<TR>
<TD><input type="text" name="UserName"</TD>
<TD>User Name</TD>
</TR>
<TR>
<TD><input type="password" name="Password"></TD>
<TD>Password</TD>
</TR>
<TR>
<TD COLSPAN=2 Align=center>
<INPUT type="submit" NAME="Submit" VALUE="Submit">
</TD>
</TR>
</TABLE>
</FORM>
<%
'Here's the end of the original If...Then
'This is executed if the form was submitted
Else
This is the end of the static HTML. If the form wasn't submitted, this is the last thing the script executes. On the other hand, if the form was submitted, everything after Else is the first thing that is executed.
I start by declaring a handful of variables that I'll use later.
'declare variables
Dim oServices, oResultset, oRecord
Dim sComputerName, sLogFile, sQuery
Dim dtDate, dtTime
Next, I get a reference to the WScript.Network object. Didn't I already do this? Yes, but in the section of code that is called when the form wasn't submitted. That code hasn't executed this time around, because the form was submitted. Therefore, I need to get the object reference.
'get the network object
set oNet =CreateObject("WScript.Network")
I also need to get a WMI locator so that I can find whatever computer I plan to connect to.
'get a WMI locator
set oLocator = CreateObject("WbemScripting.SWbemLocator")
Now I can use the WScript.Network object to retrieve the local computer name.
'get the local computer name
sComputerName = oNet.ComputerName
I've declared a string variable to store the WMI query; I'll populate that variable with the first part of the query. Notice how I leave the query hanging at the end; I'll append more information as the script runs.
'build the WMI query
sQuery = "SELECT * FROM Win32_NTLogEvent WHERE Logfile="
If the user provides a computer name in the form, I want to pull that into a variable. Similarly, if the user specifies a log name, I want to pull that into a variable, too.
'computer name specified?
If(Request("ComputerName") <> "") Then
sComputerName = Request("ComputerName")
End If
'log filename specified?
If(Request("LogName")<> "") Then
sLogFile = Request("LogName")
End If
Now I can add on to the WMI query by adding the log filename.
'append computer name and log file
'to WMI query
sQuery = sQuery & """" & sLogFile & """"
The user can optionally specify an event source, type, and event code to filter on. If any of those three are specified, I need to add the appropriate criteria to the query.
'add source, type, and code to query
If(Request("Source")<> "") Then
sQuery = sQuery & " AND SourceName=" & """" & _
Request("Source") & """"
End If
If(Request("Type") <>"") Then
sQuery = sQuery & " AND Type=" & """" & _
Request("Type") & """"
End If
If(Request("EventCode") <>"") Then
sQuery = sQuery & " AND EventCode=" & _
"""" & Request("EventCode") & """"
End If
Next, I need to see whether the user name was filled in. If it wasn't, I use the WMI locator to connect to the appropriate remote machine, providing the user name and password that the user typed. Otherwise, I force WMI to connect to the local computer, using the computer name I got from the WScript.Network object.
'username is blank?
If Request.form("UserName") <> "" Then
'no - connect to machine
Set oServices = oLocator.ConnectServer(sComputerName, _
"root\default", Request.form("UserName"), _
Request.Form("Password"))
Else
'yes = connect to local computer
Set oServices = oLocator.ConnectServer(sComputerName )
End If
Now I can execute the WMI query against the computer I connected to. This returns a WMI result set, hopefully consisting of one or more event log entries.
'execute query
Set oResultset = oServices.ExecQuery(sQuery)
I cannot safely assume that any entries came back. After all, the log might be empty, or perhaps no entries matched the criteria provided. So, I check to see if the result set is empty, and if it is, I display a message to that effect. If the result set isn't empty, the script continues to execute.
'any results?
If(oResultset.Count = 0) Then
'no
Response.Write "<b>Query returned 0 records.</b>"
Else
'yes - display results
First, I have to write out the HTML table header. I already worked out this HTML code earlier; this is using Response.Write to produce the code into the stream of HTML being sent to the Web browser.
'build table header
Response.Write "<TABLE cellspacing=0 cellpadding=3 border=1>"
'build first table row
Response.Write "<TR>"
Response.Write "<TH>Record</TH>"
Response.Write "<TH>Type</TH>"
Response.Write "<TH>Date</TH>"
Response.Write "<TH>Time</TH>"
Response.Write "<TH>Source</TH>"
Response.Write "<TH>Category</TH>"
Response.Write "<TH>Cat Strg</TH>"
Response.Write "<TH>Event</TH>"
Response.Write "<TH>Usr</TH>"
Response.Write "<TH>Computer</TH>"
Response.Write "<TH>Msg</TH>"
Response.Write "</TR>"
Next, I'll use a For Each…Next loop to go through each result in the result set. Each result represents a single record, or event log entry.
'go through each event entry
For Each oRecord In oResultset
Each entry has a TimeGenerated property that's a combination date and time. I already wrote functions to reformat this data into something more legible, so I'll call those functions now.
'Format the date and time of the entry
dtDate = CDateWMI(oRecord.TimeGenerated)
dtTime = CTimeWMI(oRecord.TimeGenerated)
Now I can write the HTML code for the data row. I'll just write out the appropriate <TD> and </TD> tags, along with the desired properties from the oRecord object, which is used to represent the current event log entry.
'write row tag
Response.Write "<TR>"
'write cell tag & record information
Response.Write "<TD>" & oRecord.RecordNumber &" </TD>" & _
"<TD>" & oRecord.Type & "</TD>" & _
"<TD>" & dtDate & "</TD>" & _
"<TD>" & dtTime & "</TD>" & _
"<TD>" & oRecord.SourceName & "</TD>" & _
"<TD>" & oRecord.Category & "</TD>" & _
"<TD>" & oRecord.CategoryString & "</TD>" & _
"<TD>" & oRecord.EventCode & "</TD>" & _
"<TD>" & oRecord.User & "</TD>" & _
"<TD>" & oRecord.ComputerName & "</TD>" & _
"<TD>" & oRecord.Message & "</TD></TR>"
That's almost it. I can close up the For Each loop, and after all records have been processed, write out the HTML tags that close the table.
Next
'close the table
Response.Write "</TABLE> </FONT>"
End If
Finally, I've thrown in the two custom functions I wrote. These were used earlier in the script. The first one simply starts by pulling the date and time data into a string variable. Then, it uses substring functions (Mid()) to pull out the year, month, and day. It ends by using string array functions to create a normal-looking date from the results.
'custom functions
Function CDateWMI(cim_DateTime)
'declare variables
Dim sDateTime, iYear, iMonth, iDay
'convert the date to a string
sDateTime = CStr(cim_DateTime)
'get the year, month, and day
iYear = CInt(Mid(sDateTime, 1, 4))
iMonth = CInt(Mid(sDateTime, 5, 2))
iDay = CInt(Mid(sDateTime, 7, 2))
'reformat into a normal date
CDateWMI = CDate(Join(Array(iMonth, iDay, iYear), "/"))
End Function
For more information on substrings, see "Working with Substrings" in Chapter 8. For more information on array handling, see "Working with Arrays" in Chapter 9.
The next function does substantially the same thing, only it pulls data from different locations to get the hours, minutes, and seconds portion of the event entry's creation date.
Function CTimeWMI(cim_DateTime)
'declare variables
Dim sDateTime, iHours, iMinutes, iSeconds
'convert the time into a string
sDateTime = CStr(cim_DateTime)
'get the hours, minutes, and seconds
iHours = CInt(Mid(sDateTime, 9, 2))
iMinutes = CInt(Mid(sDateTime, 11, 2))
iSeconds = CInt(Mid(sDateTime, 13, 2))
'reformat into a normal time
CTimeWMI = TimeSerial(iHours, iMinutes, iSeconds)
End Function
End If
%>
That's it! One complete Web page script, ready to go.
|