Guerrilla Event Log archiving: why and how.

I am quite positive that there are as many solutions (both paid and unpaid) for handling Win32 Syslogs as there are SysAdmins out there. On my *NIX machines syslogs are a simple thing, configure Syslog-ng and move on. My Windows Syslogs are a whole different story.
First off, shame on you Microsoft for not providing built in syslogd integration capabilities. With the volume of BSD code in Windows there is just no acceptable reason for this.
But that doesn’t help me. The long term goal is of course to get a central Syslog server set up that will handle and archive log entries from all of my machines (*NIX and Win32), but that is going to take two things:
- Time I don’t have.
- Money I don’t have.
I need a solution for archiving my Windows event logs right now, in a central location, until I can get the central Syslog server set up. As I mentioned, most of the solutions for doing this on Windows machines (the ones I feel comfortable entrusting my event logs to anyway) cost somewhere in the neighborhood of an arm, a leg, and most of an ear, so those are not viable options. Now what do you do?
Well if you’re me, you roll your own solution. I’ve got several WS2003 servers that I need to log the event data from, because, well to be quite honest, because this network was built by someone that is more of a *NIX SysAdmin, and didn’t set up the Windows side correctly, so there are quite a few odd bugs in this network that will take quite a while to work out.
Now I could go through and manually export the event logs to a file once a month, but that is way too much work. I decided to script the solution to this problem using VBScript (as it is available on all of the Servers I need event log info from).
I give you logArchive.vbs:
If you are having issues copy & pasting this script from Fire Fox you can grab it from here.
'#==============================================================================
'#==============================================================================
'# SCRIPT.........: logArchive.vbs
'# AUTHOR.........: Joe Glessner
'# EMAIL..........: jglessner@gmail.com
'# VERSION........: 1.0
'# DATE...........: 30JUL07
'# COPYRIGHT......: 2008, Joe-IT.com
'# LICENSE........: Freeware
'# REQUIREMENTS...:
'#
'# DESCRIPTION....: This script backs up all of the event logs on the
'# designated computer, to the specified file server.
'# Optionally this script can also clear the event logs once
'# they are archived.
'#
'# NOTES..........:
'#
'# CUSTOMIZE......:
'#==============================================================================
'# REVISED BY.....:
'# EMAIL..........:
'# REVISION DATE..:
'# REVISION NOTES.:
'#
'#==============================================================================
'#==============================================================================
'**Start Encode**
'#==============================================================================
'# START OF SCRIPT
'#==============================================================================
'Option Explicit
'On Error Resume Next
'#--------------------------------------------------------------------------
'# SCRIPT CONFIGURATION SECTION
'#--------------------------------------------------------------------------
'# OPTIONS:
'# strComputer = The name of the computer that generated the
'# event logs (e.g. fs01 - use "." for the local
'# machine.
'# objDir2 = The destination directory on the file server.
'# clearEVTLogs "No" does not clear the event logs. "Yes"
'# will clear the event logs once the current
'# logs are archived.
'#--------------------------------------------------------------------------
DIM strComputer, objDir2
strComputer = "dc1"
objDir2 = "\\SyslogServer\EventLogs$\" & strComputer
clearEVTLogs = "Yes"
'#--------------------------------------------------------------------------
'# Declare Remaining Variables
'#--------------------------------------------------------------------------
Dim current: current = Now
Dim strDateStamp: strDateStamp = dateStamp(current)
DIM objDir1: objDir1 = "\\" & strComputer & "\c$\EVT"
'#--------------------------------------------------------------------------
'# Ensure that the Scratch directory exists on the source computer.
'#--------------------------------------------------------------------------
Set filesys=CreateObject("Scripting.FileSystemObject")
If Not filesys.FolderExists(objDir1) Then
createDir(objDir1)
End If
'#--------------------------------------------------------------------------
'# Ensure that the destination directory exists on the file server.
'#--------------------------------------------------------------------------
If Not filesys.FolderExists(objDir2) Then
createDir(objDir2)
End If
'#--------------------------------------------------------------------------
'# Make create backups of the event logs to the Scratch directory.
'#--------------------------------------------------------------------------
strPath = objDir2 & "\"
Set objWMIService = GetObject("winmgmts:" _
& "{impersonationLevel=impersonate, (Backup, Security)}!\\" _
& strComputer & "\root\cimv2")
Set colLogFiles = objWMIService.ExecQuery _
("Select * from Win32_NTEventLogFile")
For Each objLogfile in colLogFiles
strCopyFile = strDateStamp & "_" & strComputer & "_" _
& objLogFile.LogFileName & ".evt&"
strBackupFile = "c:\EVT\" & strDateStamp & "_" _
& strComputer & "_" & objLogFile.LogFileName & ".evt"
strBackupLog = objLogFile.BackupEventLog _
(strBackupFile)
'WScript.Echo objLogFile.LogFileName & " backed up to " _
' & strBackupFile
'#----------------------------------------------------------------------
'# Copy the event logs to the file server.
'#----------------------------------------------------------------------
call copyAFile(objDir1, strPath, strCopyFile)
'#----------------------------------------------------------------------
'# Clear the event logs, or not.
'#----------------------------------------------------------------------
If clearEVTLogs = "Yes" then
objLogFile.ClearEventLog()
End If
Next
'#==============================================================================
'# SUBROUTINES/FUNCTIONS/CLASSES
'#==============================================================================
'#--------------------------------------------------------------------------
'# FUNCTION.........: dateStamp(ByVal dt)
'# PURPOSE..........: Generate an 8-character date stamp from the current
'# VBScript date.
'# ARGUMENTS........: dt = The date stamp to convert.
'# EXAMPLE..........: Dim current: current = Now
'# WScript.Echo dateStamp(current)
'# REQUIREMENTS.....:
'# NOTES............: The above example will produce output of 20080730 if
'# run on 07/30/08.
'#--------------------------------------------------------------------------
Function dateStamp(ByVal dt)
Dim y, m, d
y = Year(dt)
m = Month(dt)
If Len(m) = 1 Then m = "0" & m
d = Day(dt)
If Len(d) = 1 Then d = "0" & d
dateStamp = y & m & d
End Function
'#--------------------------------------------------------------------------
'# FUNCTION........: copyAFile()
'# ARGUMENTS.......: strScourceFolder = The folder containing the files to
'# be copied.
'# strTargetFolder = The Destination Folder
'# strFileName = The name and file extension of the file
'# to be copied.
'# PURPOSE.........: General purpose file copying function.
'# EXAMPLE.........: Wscript.Echo copyAFile("C:\", "\\Server\Share", _
'# & "fileName.txt")
'# NOTES...........: strSourceFolder folder must exist
'# strTargetFolder folder must exist
'# strFileName file must exist in strSourceFolder folder
'#--------------------------------------------------------------------------
Function copyAFile( Byval strSourceFolder, Byval strTargetFolder, _
Byval strFileName)
Dim objFSO, booOverWrite, strResult
Set objFSO = CreateObject("Scripting.FileSystemObject")
If objFSO.FileExists( strSourceFolder & "\" & strFileName) _
And UCase( strSourceFolder) UCase( strTargetFolder) Then
If objFSO.FolderExists( strTargetFolder) Then
Else
strResult = "The destination folder does not exist!"
'copyAFile = strResult
Exit Function
End If
If objFSO.FileExists( strTargetFolder & "\" & strFileName) Then
strResult = "The file exists, overwritten"
booOverWrite = vbTrue
Else
strResult = "The file does not exist, created"
booOverWrite = vbFalse
End If
objFSO.CopyFile strSourceFolder & "\" _
& strFileName, strTargetFolder & "\", booOverWrite
Else
strResult = "The source file does not exist, or " _
& "identical Source and Target folders!"
End If
'copyAFile = strResult
End Function
'#--------------------------------------------------------------------------
'# FUNCTION.......: createDir(strDir)
'# ARGUMENTS......: strDir = UNC path of the directory to create.
'# PURPOSE........: Creates directories.
'# EXAMPLE........: createDir("c:\WSH_TEST\")
'# createDir("c:\WSH_TEST\" & "Files\")
'# NOTES..........: If creating a subdirectory of a directory that does
'# not exist, the parent directory must be created
'# first, as shown in the example.
'#--------------------------------------------------------------------------
Function createDir(strDir)
set filesys=CreateObject("Scripting.FileSystemObject")
Set objFSO = CreateObject("Scripting.FileSystemObject")
If Not filesys.FolderExists(strDir) Then
Set objFolder = objFSO.CreateFolder(strDir)
End If
End Function
'#==============================================================================
'# END OF FILE
'#==============================================================================
So, What does it do? This script will copy the event logs (well technically it creates a backup it doesn’t actually copy the data per se) from the target system to a directory defined by the user, and optionally clear the logs.
You can then use the built in Windows Event Log viewer to open the resulting file and search the event logs for the time period in the file.
How I use this:
I have several copies of this script set up in Windows’ Task Scheduler to run on the first of every month at exactly midnight, with the option to clear the event logs turned on. This allows me to create a Monthly archive of event logs for each Server that it is run against, and when I get a cryptic event log message like “Windows has previously logged the source of this error”, I can go back and search for the referenced previous entry.
Like I said before, this is a temporary system designed to do one thing: archive all of the Event logs from all of my Windows servers to a central location until I can get a proper central Syslog server in place. It works flawlessly for the task it was designed to do.



November 14, 2008 - 6:32 pm
Install Splunk on one of your Linux boxes, and Snare on your Windows PCs.
Click to Reply to This Comment.
November 15, 2008 - 11:59 am
I run almost the exact same script at the beginning of each month to clear al my server logs and archive them centrally.
I also run a daily script from Redmond Magazine (http://redmondmag.com/columns/article.asp?EditorialsID=1653) that emails me a log of all the error and warning events on all my servers for the past 24 hours. You need to customize it to get rid of the noise, but it works well. It has alerted me to problems before they became critical and allowed me to resolve them without downtime.
Click to Reply to This Comment.
November 25, 2008 - 7:05 am
I’m getting an error when I run this:
Line 150
Char: 41
Error: Expected ‘Then’
Any ideas?
Click to Reply to This Comment.
Karl L. Gechlik | AskTheAdmin.com Reply:
November 25th, 2008 at 7:41 am
It runs ok over here. How did you copy the script Jon?
Click to Reply to This Comment.
Joe Glessner Reply:
November 25th, 2008 at 10:37 am
Karl,
As I noted below, the formatting is not showing up correct on this post in FireFox (I’m thinking there is something that needs to be tweaked in the CSS for this page.
I could correct it by making the font smaller with some HTML tags, but then on the IE page it would be tiny and unreadable ;)
Click to Reply to This Comment.
November 25, 2008 - 7:44 am
I just highlighted it all and put it in notepad. Looks like it copied fine. I even tried ultraedit. Maybe I could just get your copy? I also don’t understand the config, mostly this part:
DIM objDir1: objDir1 = “\\” & strComputer & “\c$\EVT”
I already had set the path at the objDir2 variable.
Click to Reply to This Comment.
November 25, 2008 - 10:34 am
By any chance are you viewing the post in Firefox? The reason I ask, is that for some odd reason when I view this page in FF the formatting is broken, and some of the lines wrap (in scripts this is very bad).
If you look around line 150 in the script on this page in Firefox, you’ll notice that there is a “then” just floating (got pushed down by word wrap).
Now if you copy that, it may retain the odd formatting in your text editor. You can find this post on my blog at http://joeit.wordpress.com/2008/11/10/guerrilla-event-log-archiving-why-and-how/, with correct formatting.
As to the line of code you call out:
DIM objDir1: objDir1 = “\\” & strComputer & “\c$\EVT”
This creates a variable that allows the script to create a temporary directory on the remote machine for the event logs to be exported to (the Windows EventLog API security prevents you making copies of the event logs to remote machines directly, all copies must be saved locally or not at all).
objDir2 on the other hand is the destination of the files after then have been copied to objDir1 (basically objDir1 is on whatever machine you run this against, and objDir2 is the final destination for the files).
Hope that gets you where you need to be!
Click to Reply to This Comment.
Karl L. Gechlik | AskTheAdmin.com Reply:
November 25th, 2008 at 12:10 pm
Thanks Joe! I will throw your link into the post for reference. And will take a look at the css.
Click to Reply to This Comment.
Rever75 Reply:
June 15th, 2009 at 6:25 am
Ok can get it to archive all the Event Logs, clear them and create the directory on the Remote machine but not copy the actual logs. I was getting errors at line 149 or 150 until I removed this part from line 150.
And UCase( strSourceFolder) And UCase( strTargetFolder)
After that all worked except the actual copying of the file.
Click to Reply to This Comment.
Rever75 Reply:
June 15th, 2009 at 6:26 am
I added the second And since it would error with and Expected ‘Then’ until I added it.
Click to Reply to This Comment.
June 15, 2009 - 5:19 am
I am getting an issue at Line 150 Char 41 Expected ‘Then’ looks like it is not excepting the 2 Ucases
Click to Reply to This Comment.
JoeG Reply:
June 15th, 2009 at 12:08 pm
Ok, so There is a formatting error here. I believe that I can tract the error to a pervious version of Wordpress, because I was able to correct it on my blog.
Just in case I’ve also taken a screenshot of the offending function, as it should appear. Here is a link to the post where I’ve fixed it: http://www.laoae.com/2008/11/guerrilla-event-log-archiving-why-and-how/
Now then, apologies to all that have had issues with this script (apparently this is the most popular post I’ve ever written, as I’ve had commentary on this issue from several different sources), my bad for not vetting it after it was posted.
I’m working on a better way of posting code to Wordpress so that this doesn’t happen in the future.
Click to Reply to This Comment.
Rever75 Reply:
June 15th, 2009 at 12:32 pm
Thanks for the reply this script is awesome. I no longer get the error message but oddly it will create the directory on my File Server but never places the backed up logs in it.
Click to Reply to This Comment.
Karl L. Gechlik | AskTheAdmin.com Reply:
June 16th, 2009 at 11:49 am
Thanks for following up Joe!
I am looking at some plugins for windows live writer that format code properly… I will let you know how it goes!
We would love to see some new Admin’s Arsenal posts :)
Click to Reply to This Comment.
JoeG Reply:
June 15th, 2009 at 12:11 pm
Oh and an interesting note here; the error was actually on like 151, however (for reasons known only to Microsoft) when the VBScript interpreter catches an error in a function, it lists the line number where the Function breaks, not necessarily where the problem is.
Click to Reply to This Comment.
December 15, 2009 - 8:50 pm
precitat cely blog, docela dobrej
Click to Reply to This Comment.