Trevor Sullivan's Tech Room

Minding the gap between administration and development

Windows 2003 Print Log Parsing Script [PowerShell]

Posted by Trevor Sullivan on 2009/11/06


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:

  1. Retrieve list of all print entries from server event log
  2. Parses information from each log entry and creates an object in memory representing it
  3. Builds a hash table from all objects
  4. 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
Advertisements

10 Responses to “Windows 2003 Print Log Parsing Script [PowerShell]”

  1. Noscriptingskills said

    Hi Trevor,
    I’ve been googling how to parse the print server event log into a easier to read format. Is there a way to run this script against an exported log file? I don’t feel comfortable running it on our print server. Also, what syntax would be used to run the script?

    Thanks!

  2. PrinterLogger said

    Great script!

    I got only one issue with it, it uses comma for delimiter instead of semicolumn which is system setting.
    But since you use Export-Csv it’s not your fault. I just search and replace “,” with “;” in csv.

    Regards

  3. Fer said

    Dear Trevor,

    great script and it does exactly what I need. But some of our usernames has a . in the username.
    Your script removes those names and they are nog displayed in the csv file.

    Is there a way I can fix this. Then I can use the script for 100%

    Cheers,
    Fer

  4. HeM said

    how do i do this if i save event log in txt files ..

  5. HeM said

    Hi i am usering same script with 1 change in $PrintEntries = .\psloglist.exe \\ -s -h 1 System -i 10
    all my script is working only Problem is Time values are not generating ..

    can you pls guide me for the same ..

  6. HeM said

    its worked for me

  7. Punit said

    gr8 script …very useful ..

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

 
%d bloggers like this: