This post provides information on a solution to provide audit logs and summary information on printer usage on a Windows print server. This will provide daily and monthly printer event logs, and summary results based on one or more log files.
Pre-requisites:
- A scheduled task that runs every day to collect and process the logs, it doesn’t have to be on the print server. 
 
- 'Log Spooler Information Events' on the printer spooler in question, which will write Event ID 10 entries every time someone prints through the spooler 
 
- A system event log big enough to capture at least one day's logs 
 
Create a batch file that contains the following commands. Note that you will need to modify the variables or to reference paths as appropriate, eg for dumpel.exe and the VBScript, and the print/log dir.
Set PrintDir=c:\Print
Set LogDir=C:\logs
for /f "tokens=1-8 delims=/:. " %%i in ('echo %date%') do Set DateFlat=%%l%%k%%j
dumpel -s \\%print_server% -l System -e 10 -m Print -d 1 >> %logDir%\%server%_jobs_%DateFlat%.csv
for /f "tokens=3,4 delims=/ " %%i in ('echo %date%') do copy %server%_jobs_%%j%%i??.csv %PrintDir%\PrintJobs_%%j%%i.csv /y
cscript ProcessPrinterLogs.wsf /f:%LogDir%
If you create a scheduled task to run this batch file every day at the same time, these commands will: 
- Dump the event logs for the past day to a daily log file with YYYYMMDD suffix. 
 
- Collate the daily log files into a monthly log file, by appending each daily file. For each day in a month, this command will overwrite the previous monthly log, until it runs on the last day of the month. 
 
- The script processes the dumpel log entries, providing different views in the form of per-printer, per-user, per-day totals of jobs/pages/bytes (useful for graphics), as well as summary totals of the information. 
 
This has the following advantages:
- It’s simple and not very intensive. A SQL database with a recurring DTS job to import the logs and then using SQL Reporting Services would be a lot prettier, but really not that much more functional or useful. 
 
- You will have a permanent set of log files, one for each month that you can store for historical purposes, while purging the daily log file directory every so often.
 
The ProcessPrinterLogs.vbs script that does all the work is listed below. To run:
cscript ProcessPrinterLogs.vbs /f:%logDir%
Const ForReading = 1, ForWriting = 2, ForAppending = 8
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objShell = CreateObject("WScript.Shell")
Main()
Sub Main()
    If WScript.Arguments.Named.Exists("f") Then
        sSource = Wscript.Arguments.Named("f")
    Else
        Wscript.Arguments.ShowUsage()
        Wscript.Echo "Source file or directory must be supplied"
        Wscript.Quit(2)
    End If
    If Wscript.Arguments.Named.Exists("o") Then
        sOutputFile = Wscript.Arguments.Named("o")
    Else
        dNow = Now    
        dLogDate = DatePart("yyyy", dNow) 
        dLogDate = dLogDate & String(2 - Len(DatePart("m", dNow)),"0") & DatePart("m", dNow)
        dLogDate = dLogDate & String(2 - Len(DatePart("d", dNow)),"0") & DatePart("d", dNow)    
        sOutputFile = objShell.ExpandEnvironmentStrings("%Temp%")
        sOutputFile = sOutputFile & "\" & Left(WScript.ScriptName, InStrRev(WScript.ScriptName,".vbs")-1) & "_" & dLogDate & ".csv"
    End If
    wscript.echo "Input file/dir: '" & sSource & "'"
    wscript.echo "Output file: '" & sOutputFile & "'"
    If objFSO.FileExists(sSource) Then 
        sFileSet = sSource                                        ' Process a single file
        wscript.echo "Single file specified - " & sFileSet
    ElseIf objFSO.FolderExists(sSource) Then
        wscript.echo "Source specified was a directory, reading files from '" & sSource & "'"
        sFileSet = ""
        Set oFolder = objFSO.GetFolder(sSource)                                ' Get the folder
        Set oFiles = oFolder.Files
        For Each oFile in oFiles                                    ' For each file
            sFileset = sFileset & vbCRLF & oFile.Path                         ' Append to the fileset
        Next
        If Len(sFileSet) > Len(vbCRLF) Then sFileSet = Right(sFileSet, Len(sFileSet) - Len(vbCRLF))    ' Trim the leading CRLF
    End If
    Set dPrinters  = CreateObject("Scripting.Dictionary")                            ' Create the dictionary objects
    Set dusers = CreateObject("Scripting.Dictionary")
    Set dDates = CreateObject("Scripting.Dictionary")
    Set dJobs = CreateObject("Scripting.Dictionary")
    For Each sFile in Split(sFileset, vbCRLF)                                ' For Each file
        wscript.echo "Processing '" & sFile & "'"
        sBuffer = ""
           Set objTextStream = objFSO.OpenTextFile(sFile, ForReading)      
        sBuffer = objTextStream.ReadAll
        For Each sLine in Split(sBuffer, vbCRLF)                            ' For each line in this file
            Call ProcessLogEntry(sLine, dPrinters, dUsers, dDates, dJobs)                ' Process the log entry
        Next
    Next
    Call ProduceOutput(sOutput, dPrinters, dUsers, dDates, dJobs)                        ' Produce the output
    Set objTextStream = objFSO.OpenTextFile(sOutputFile, ForWriting, True)
    objTextStream.Write sOutput
    wscript.echo "Output saved to '" & sOutputFile & "', " & Len(sOutput) & " characters."
End Sub
Function ProduceOutput(ByRef sOutput, ByRef dPrinters, ByRef dUsers, ByRef dDates, ByRef dJobs)
    Dim strPrinter, strPort, dtmDate, strUser, strserver, strDocumentName, intSize, intPages, strInformation, strTotal
    Dim strUserTotal, strPrinterTotal, strDateTotal, strJobTotal, aJobTotal
    sOutput = ""
    For Each strPrinter in dPrinters.Keys        
        sOutput = sOutput & vbCRLF & strPrinter & "," & dPrinters.Item(strPrinter)
    Next
    sOutput = sOutput & vbCRLF
    For Each strUser in dUsers.Keys
        sOutput = sOutput & vbCRLF & strUser & "," & dUsers.Item(strUser)
    Next
    sOutput = sOutput & vbCRLF
    For Each dtmDate in dDates.Keys
        sOutput = sOutput & vbCRLF & dtmDate & "," & dDates.Item(dtmDate)
    Next
    sOutput = sOutput & vbCRLF
    For Each strTotal in dJobs.Keys
        strJobTotal = dJobs.Item(strTotal)
        aJobTotal = Split(strJobTotal, ",")
        sOutput = sOutput & vbCRLF & "Total Jobs," & aJobTotal(0)
        sOutput = sOutput & vbCRLF & "Total Pages," & aJobTotal(1)
        sOutput = sOutput & vbCRLF & "Total Size (MB)," & aJobTotal(2)
    Next
    sOutput = sOutput & vbCRLF
    strUserTotal = UBound(dUsers.Keys)+1
    strPrinterTotal = UBound(dPrinters.Keys)+1
    strDateTotal = UBound(dDates.Keys)+1
    sOutput = sOutput & vbCRLF & "Printers," & strPrinterTotal 
    sOutput = sOutput & vbCRLF & "Users," & strUserTotal 
    sOutput = sOutput & vbCRLF & "Days," & strDateTotal 
    aJobTotal = Split(strJobTotal, ",")
    sOutput = sOutput & vbCRLF
    sOutput = sOutput & vbCRLF & "Average jobs/person," & CInt(aJobTotal(0)/strUserTotal)
    sOutput = sOutput & vbCRLF & "Average pages/person," & CInt(aJobTotal(1)/strUserTotal)
    sOutput = sOutput & vbCRLF & "Average pages/person/day," & CInt(CInt(aJobTotal(1)/strUserTotal) / strDateTotal)
    sOutput = sOutput & vbCRLF & "Average pages/minute," & CInt(aJobTotal(1) / (strDateTotal * 8 * 60))
End Function
Function ProcessLogEntry(ByRef sLine, ByRef dPrinters, ByRef dUsers, ByRef dDates, ByRef dJobs)
    Dim strPrinter, strPort, dtmDate, strUser, strserver, strDocumentName, intSize, intPages, strInformation 
    Dim aPrintJob, intOffset, strTemp, aTemp
    aPrintJob = Split(sLine, vbTAB)
    If UBound(aPrintJob) = 9 Then
        dtmDate = aPrintJob(0) ' & " " & aPrintJob(1)
        aTemp = Split(dtmDate, "/")
        dtmDate = Right("00" & Trim(aTemp(1)), 2) & "/" & Right("00" & Trim(aTemp(0)), 2) & "/" & aTemp(2)        ' Trim, pad and switch to dd/mm/yyyy instead of mm/dd/yyyy
        strServer = aPrintJob(8)
        strInformation = Trim(aPrintJob(9))
        strInformation = Right(strInformation, Len(strInformation) - InStr(strInformation, " "))    ' Remove the job ID
        intOffset = InStrRev(strInformation, " ")
        intPages = Right(strInformation, Len(strInformation) - intOffset)        ' Extract the number of pages from the end
        strInformation = Left(strInformation, intOffset-1)                ' Trim the string
    
        intOffset = InStrRev(strInformation, " ")
        intSize = Right(strInformation, Len(strInformation) - intOffset)        ' Extract the number of bytes from the end
        strInformation = Left(strInformation, intOffset-1)                ' Trim the string    
    
        intOffset = InStrRev(strInformation, " ")
        strPort = Right(strInformation, Len(strInformation) - intOffset)        ' Extract the port from the end
        strInformation = Left(strInformation, intOffset-1)                ' Trim the string    
    
        intOffset = InStrRev(strInformation, " ")
        strPrinter = Right(strInformation, Len(strInformation) - intOffset)        ' Extract the printer from the end
        strInformation = Left(strInformation, intOffset-1)                ' Trim the string    
    
        intOffset = InStrRev(strInformation, " ")
        strUser = Right(strInformation, Len(strInformation) - intOffset)        ' Extract the user from the end
        strInformation = Left(strInformation, intOffset-1)                ' Trim the string    
    
        strDocumentName = strInformation
        If dPrinters.Exists(strPrinter) Then                         ' Does this printer already exist in the dictionary?
            aTemp = Split(dPrinters.Item(strPrinter), ",")                ' Find the existing printer job/page count
            aTemp(0) = aTemp(0) + 1                            ' Increment the job count
            aTemp(1) = aTemp(1) + CInt(intPages)                    ' Add to the page count
            aTemp(2) = aTemp(2) + CInt(intSize/1024/1024)                ' Add to the byte count
            dPrinters.Item(strPrinter) = Join(aTemp, ",")                ' Update the dictionary
        Else
            aTemp = Array(1, intPages, CInt(intsize /1024/1024))            ' Start the job/page count
            dPrinters.Add strPrinter, Join(aTemp, ",")                ' Create this item
        End If
    
        If dUsers.Exists(strUser) Then                             ' Does this user already exist in the dictionary?
            aTemp = Split(dUsers.Item(strUser), ",")                ' Find the existing user job/page count
            aTemp(0) = aTemp(0) + 1                            ' Increment the job count
            aTemp(1) = aTemp(1) + CInt(intPages)                    ' Add to the page count
            aTemp(2) = aTemp(2) + CInt(intSize/1024/1024)                ' Add to the byte count
            dUsers.Item(strUser) = Join(aTemp, ",")                    ' Update the dictionary
        Else
            aTemp = Array(1, intPages, CInt(intsize /1024/1024))            ' Start the job/page count
            dUsers.Add strUser, Join(aTemp, ",")                    ' Create this item
        End If
        If dDates.Exists(dtmDate) Then                             ' Does this date already exist in the dictionary?
            aTemp = Split(dDates.Item(dtmDate), ",")                ' Find the existing date job/page count
            aTemp(0) = aTemp(0) + 1                            ' Increment the job count
            aTemp(1) = aTemp(1) + CInt(intPages)                    ' Add to the page count
            aTemp(2) = aTemp(2) + CInt(intSize/1024/1024)                ' Add to the byte count
            dDates.Item(dtmDate) = Join(aTemp, ",")                    ' Update the dictionary
        Else
            aTemp = Array(1, intPages, CInt(intsize /1024/1024))            ' Start the job/page count
            dDates.Add dtmDate, Join(aTemp, ",")                    ' Create this item
        End If
        If dJobs.Exists(JOB_TOTAL) Then                         ' Does the total already exist in the dictionary?
            aTemp = Split(dJobs.Item(JOB_TOTAL), ",")                ' Find the existing total counts
            aTemp(0) = aTemp(0) + 1                            ' Increment the job count
            aTemp(1) = aTemp(1) + CInt(intPages)                    ' Add to the page count
            aTemp(2) = aTemp(2) + CInt(intSize/1024/1024)                ' Add to the byte count
            dJobs.Item(JOB_TOTAL) = Join(aTemp, ",")                ' Update the dictionary
        Else
            aTemp = Array(1, intPages, CInt(intsize /1024/1024))            ' Start the job/page count
            dJobs.Add JOB_TOTAL, Join(aTemp, ",")                    ' Create this item
        End If
    Else
        wscript.echo "skipped '" & sLine & "'"
    End If
End Function
* Please don’t print this post :) *
Wayne's World of IT (WWoIT), Copyright 2008 Wayne Martin.
Read more!