Hello everyone,
Since I’m not aware of any tools that visually log print server information, I wrote a script that parses the log entries from the system event log of a Windows 2003 print server. Apparently I never got around to posting this online, but I hope that someone is able to benefit from it.
Basically, the process flow of the script looks like this:
- Retrieve list of all print entries from server event log
- Parses information from each log entry and creates an object in memory representing it
- Builds a hash table from all objects
- Iterates over the hash table and writes each print log entry to an Excel document
If you have any questions about it, please feel free to let me know.
FYI, I commented out the line near the bottom that does the Excel output, so that it could be executed on a server without Excel installed.
################################################################################# # # # Author: Trevor Sullivan # # # Date: February 10th, 2009 # # # Purpose: This script is meant for running against a Windows 2003 event log. # The verbage for the print log entries has changed for Windows Vista. # # ################################################################################# Function GetPrintEntriesFromTextFile($tFileName) { Get-Content $tFileName } Function GetPrintEntriesFromLog() { $PrintEntries = Get-EventLog -LogName System | Where-Object { $_.EventId -eq 10 -and $_.Source -eq "Print" -and $_.TimeGenerated.Month -eq (Get-Date).Month -and $_.TimeGenerated.Year -eq (Get-Date).Year } return $PrintEntries } # Parses username from a Windows 2003 Print log message Function GetUserName($PrintEntry) { If ($PrintEntry -eq "" -or $PrintEntry -eq $null) { return $null } $rxUserName = [regex]"owned by ([0-9a-zA-Z]{7})" $rxUserName = [regex]"owned by ([0-9a-zA-Z]{1,}) was" $rxMatches = $rxUserName.Match($PrintEntry) return $rxMatches.Groups[1].Value } Function GetPrinterName($PrintEntry) { If ($PrintEntry -eq "" -or $PrintEntry -eq $null) { return $null } #Write-Host "Parsing printer name" $rxPrinterName = [regex]"printed on ([0-9a-zA-Z-_\s]{5,}) via" $rxMatches = $rxPrinterName.Match($PrintEntry) return $rxMatches.Groups[1].Value } Function GetPrintSize($PrintEntry) { If ($PrintEntry -eq "" -or $PrintEntry -eq $null) { return $null } #Write-Host "Getting print size" $rxPrintSize = [regex]"Size in bytes: ([0-9]+);" $rxMatches = $rxPrintSize.Match($PrintEntry) return $rxMatches.Groups[1].Value } Function GetPageCount($PrintEntry) { If ($PrintEntry -eq "" -or $PrintEntry -eq $null) { return $null } #Write-Host "Getting page count" $rxPageCount = [regex]"pages printed\: ([0-9]+)" $rxMatches = $rxPageCount.Match($PrintEntry) return $rxMatches.Groups[1].Value } Function GetDocumentName($PrintEntry) { If ($PrintEntry -eq "" -or $PrintEntry -eq $null) { return $null } #Write-Host "Getting print size" $rxDocumentName = [regex]", ([a-zA-Z-_:/\[#\]\?\\\=\d\.\s\(\)&-,]{1,}) owned by" $rxMatches = $rxDocumentName.Match($PrintEntry) return $rxMatches.Groups[1].Value } # Retrieves user's full name from AD Function GetUserFullName($UserId) { if ($UserId -gt "") { $DirectorySearcher = New-Object System.DirectoryServices.DirectorySearcher $LdapFilter = "(&(objectClass=user)(samAccountName=${UserId}))" #Write-Host "Filter is: ${LdapFilter}" $DirectorySearcher.Filter = $LdapFilter $UserEntry = [adsi]"$($DirectorySearcher.FindOne().Path)" #Write-Host $UserEntry.displayName return $UserEntry.displayName } return } Function CreatePrintJob() { $PrintJob = New-Object PsObject Add-Member -Force -InputObject $PrintJob -MemberType NoteProperty -Name PageCount -Value $null Add-Member -Force -InputObject $PrintJob -MemberType NoteProperty -Name UserName -Value $null Add-Member -Force -InputObject $PrintJob -MemberType NoteProperty -Name DocumentName -Value $null Add-Member -Force -InputObject $PrintJob -MemberType NoteProperty -Name Size -Value $null Add-Member -Force -InputObject $PrintJob -MemberType NoteProperty -Name Printer -Value $null Add-Member -Force -InputObject $PrintJob -MemberType NoteProperty -Name Time -Value $null Add-Member -Force -InputObject $PrintJob -MemberType NoteProperty -Name UserFullName -Value $null return $PrintJob } Function ParsePrintEntry($PrintEntry) { $NewPrintJob = CreatePrintJob if ($PrintEntry.GetType() -eq [System.String]) { $NewPrintJob.PageCount = GetPageCount $PrintEntry $NewPrintJob.UserName = GetUserName $PrintEntry $NewPrintJob.DocumentName = GetDocumentName $PrintEntry $NewPrintJob.Size = GetPrintSize $PrintEntry $NewPrintJob.Printer = GetPrinterName $PrintEntry $NewPrintJob.UserFullName = GetUserFullName $NewPrintJob.UserName } elseif ($PrintEntry.GetType() -eq [System.Diagnostics.EventLogEntry]) { $NewPrintJob.PageCount = GetPageCount $PrintEntry.Message $NewPrintJob.UserName = GetUserName $PrintEntry.Message $NewPrintJob.DocumentName = GetDocumentName $PrintEntry.Message $NewPrintJob.Size = GetPrintSize $PrintEntry.Message $NewPrintJob.Printer = GetPrinterName $PrintEntry.Message $NewPrintJob.Time = $PrintEntry.TimeGenerated.ToString() $NewPrintJob.UserFullName = GetUserFullName $NewPrintJob.UserName } return $NewPrintJob } Function Main() { $PrintEntries = GetPrintEntriesFromLog #$PrintEntries = GetPrintEntriesFromTextFile "${env:USERPROFILE}\Documents\Powershell Scripts\Print Log Parser\PrintLog.txt" $Global:ParsedEntries = @{}; $i = 0 ForEach ($PrintEntry in $PrintEntries) { $ParsedEntries.Add($i, $(ParsePrintEntry $PrintEntry)) #$ParsedEntries += (ParsePrintEntry $PrintEntry) $i++ if ($i % 100 -eq 0) { Write-Host "Processed $i records" } } # Export information to CSV or Excel document $ParsedEntries.Values | Export-Csv "c:\$((Get-Date).Month).csv" -NoTypeInformation #WriteToExcel $ParsedEntries } Function WriteToExcel($tEntries) { # Load Excel interop assembly [Void] [Reflection.Assembly]::LoadWithPartialName("Microsoft.Office.Interop.Excel") # Create Excel application, workbook, and worksheet objects $Excel = New-Object Microsoft.Office.Interop.Excel.ApplicationClass $Workbook = $Excel.Workbooks.Add() $Worksheet = $Workbook.Worksheets.Add() # Write Excel worksheet headers $Worksheet.Cells.Item(1, 1).Value2 = "Username" $Worksheet.Cells.Item(1, 2).Value2 = "Full Name" $Worksheet.Cells.Item(1, 3).Value2 = "Time" $Worksheet.Cells.Item(1, 4).Value2 = "Page Count" $Worksheet.Cells.Item(1, 5).Value2 = "Printer" $Worksheet.Cells.Item(1, 6).Value2 = "Size (bytes)" $Worksheet.Cells.Item(1, 7).Value2 = "Document Name" # End writing Excel worksheet headers # Iterate over each print entry $row = 2 ForEach ($key in $tEntries.Keys) { $Worksheet.Cells.Item($row, 1).Value2 = $tEntries[$key].UserName $Worksheet.Cells.Item($row, 2).Value2 = $tEntries[$key].UserFullName $Worksheet.Cells.Item($row, 3).Value2 = $tEntries[$key].Time $Worksheet.Cells.Item($row, 4).Value2 = $tEntries[$key].PageCount $Worksheet.Cells.Item($row, 5).Value2 = $tEntries[$key].Printer $Worksheet.Cells.Item($row, 6).Value2 = $tEntries[$key].Size $Worksheet.Cells.Item($row, 7).Value2 = $tEntries[$key].DocumentName $row++ } # Do some formatting # AutoFit the columns [Void] $Excel.ActiveCell.CurrentRegion.Columns.AutoFit() # Add table styling and auto-filtering [Void] $Excel.ActiveCell.CurrentRegion.Select() $ListObject = $Excel.ActiveSheet.ListObjects.Add([Microsoft.Office.Interop.Excel.XlListObjectSourceType]::xlSrcRange, $Excel.ActiveCell.CurrentRegion, $null ,[Microsoft.Office.Interop.Excel.XlYesNoGuess]::xlYes) $ListObject.Name = "TableData" $ListObject.TableStyle = "TableStyleLight9" # Show the Excel window after writing data to spreadsheet $Excel.Visible = $true } Main