VB script or PowerShell script for auditing Win2k8 Print server
-
Monday, December 21, 2009 12:44 PMHi I am looking for a VB script or PowerShell script for auditing the Usage of my WIN2K8 print server (users,pages,date time etc)
I got lot of scripts from google but nothing is working out for Windows 2008.
scripts I tried
http://waynes-world-it.blogspot.com/2008/04/audit-windows-2003-print-server-usage.html
http://www.isbgroup.com/PrinterAudit/ - good one for wink3 not working out for windows 2008 as log format and architecture is different.
https://blogs.sans.org/windows-security/2009/06/30/dump-windows-event-logs-to-csv-text-vbscript/ - able to parse application,system etc but unable to do the print services
Help anyone !
Merry Christmas!
Thanks in advance
Ashok Vikram
All Replies
-
Wednesday, January 27, 2010 3:41 PMModerator
Hi Ashok.
WMI Supports a couple of Printer related classes. Using PowerShell, you can get instances of WMI classes through the Get-WmiObject CmdLet. With the -ComputerName parameter you can access remote computers.
If you want to get information about printers you could use the Win32_Printer class.Get-WmiObject Win32_Printer
for specific details you can pipe the command to Select-Object
Get-WmiObject Win32_Printer | Select Name, ServerName, PrinterStatus
If you want information regarding the Print queue you could use the Win32_PerfFormattedData_Spooler_PrintQueue class.
Get-WmiObject Win32_PerfFormattedData_Spooler_PrintQueue
hope this helps.
Niklas Goude Blog: www.powershell.nu Twitter: @Ngoude- Marked As Answer by IamMredMicrosoft Employee, Owner Friday, February 05, 2010 5:48 PM
-
Wednesday, January 27, 2010 7:20 PM
This method is not perfect as Windows doesn't record the copy count of any print jobs going through the system; you would need a proper print accounting product for that. It also will only account for printing through Windows, any LPR printing won't generally record the number of pages. It also relies upon reading the exact text from the Event Log (which having just checked is different on Windows Server 2008 compared to previous versions!).
First you'll need to open Control Panel | Printers then choose File | Server Properties | Advanced and enable "Log spooler information events". This will capture all printing activity to the event log.
Then run the following script which will write to the screen and to a log file C:\ProgramData\PRINTLOG.CSV all print activity. This CSV will list time/datestamp, queue name, job name, job owner, number of pages (excluding the aforementioned copy count).
There's nothing to clear the log down though.
I've testing this on an English language o/s as it relies heavily on reading the correct text so apologies if you have a different local language, it will need editing (in hindsight I should also have used regular expressions to find the details). Here's an example entry from the Event Log which gets "parsed" by this script, bold bits should be read by the script:
"Document 5, Test Page owned by Administrator was printed on My New Print Queue through port NULL. Size in bytes: 134956. Pages printed: 1. No user action is required.
To stop logging information events for the print spooler, in Control Panel, open Printers, right-click a blank area of the window, click Run as Administrator, click Server Properties, click the Advanced tab, and then clear the Log spooler information events check box."
And here's the VBScript:Const ForWriting = 2 strComputer = "." strLogfile = "C:\ProgramData\PRINTLOG.CSV" Set objFSO = CreateObject("Scripting.FileSystemObject") Set objLogFile = objFSO.CreateTextFile(strLogfile, ForWriting, True) Set objWMIService = GetObject("winmgmts:{(Security)}\\" & strComputer & "\root\cimv2") Set colEvents=objWMIService.ExecQuery("Select * from Win32_NTLogEvent WHERE EventCode=10 And SourceName='Microsoft-Windows-PrintSpooler'") For Each objEvent in colEvents Job1=ptrEnd(objEvent.Message,", ") Job2=ptrStart(objEvent.Message," owned by ") User1=ptrEnd(objEvent.Message," owned by ") User2=ptrStart(objEvent.Message," was printed on ") Queue1=ptrEnd(objEvent.Message," was printed on ") Queue2=ptrStart(objEvent.Message," through port") Pages1=ptrEnd(objEvent.Message,"Pages printed: ") Pages2=Instr(Pages1,objEvent.Message,".") strJob=Mid(objEvent.Message,Job1,Job2-Job1) strUser=Mid(objEvent.Message,User1,User2-User1) strQueue=Mid(objEvent.Message,Queue1,Queue2-Queue1) numPages=CInt(Mid(objEvent.Message,Pages1,Pages2-Pages1)) strDetails=Chr(34) & WMIDateStringToDate(objEvent.TimeWritten) & Chr(34) & "," strDetails=strDetails & Chr(34) & strQueue & Chr(34) & "," strDetails=strDetails & Chr(34) & strJob & Chr(34) & "," strDetails=strDetails & Chr(34) & strUser & Chr(34) & "," strDetails=strDetails & Chr(34) & numPages & Chr(34) WScript.Echo strDetails objLogFile.WriteLine strDetails Next objLogFile.Close Function WMIDateStringToDate(dtmBootup) WMIDateStringToDate = CDate(Mid(dtmBootup, 5, 2) & "/" & _ Mid(dtmBootup, 7, 2) & "/" & Left(dtmBootup, 4) _ & " " & Mid (dtmBootup, 9, 2) & ":" & _ Mid(dtmBootup, 11, 2) & ":" & Mid(dtmBootup, _ 13, 2)) End Function Function ptrEnd(strSource, strSearch) ptrEnd=InStr(1,strSource,strSearch,0)+Len(strSearch) End Function Function ptrStart(strSource, strSearch) ptrStart=InStr(1,strSource,strSearch,0) End Function- Marked As Answer by IamMredMicrosoft Employee, Owner Friday, February 05, 2010 5:48 PM
-
Wednesday, February 10, 2010 12:36 PMHi Cat,
Thanks for the response and the script.
The script is fine for Windows 2008 SP2
But the script is not working for WINDOWS 2008 R2 Edition also I can't see Control Panel | Printers| File | Server Properties | Advanced and enable "Log spooler information events option in Windows 2008 R2 to enable it. I can see that there is difference in the log path for windows 2008 R2 compared to Windows 2008 SP2.
I am not familiar with Windows Scripting
Any ideas!
Thanks in advance
Ashok Vikram
-
Wednesday, February 10, 2010 12:50 PM
Unfortunately I haven't got a Windows 2008 R2 to hand to check out the differences, and as I mentioned it requires the exact text.
Maybe someone who knows scripting and has an R2 box can modify the script above to make it work?
Regardless you'll need to enable the log spooler events option anyway - so find where MS have hidden that. If you can get that working then print something, open the Event Log, and capture the text for a printed event. On Windows 2008 SP2 this will be have an Event Code of 10 and the Source will be "Microsoft-Windows-PrintSpooler" so maybe the Source name has changed? Send me the text produced from the event.
All this script is doing is collecting all the printed events and parsing them to extract the individual print job details, although as I pointed out this cannot return copy counts of the print jobs.- Proposed As Answer by Sh_Con Friday, February 12, 2010 11:20 PM
-
Friday, February 12, 2010 11:48 PM
I am by no means a Powershell expert, but I modified my server 2003 printserver script to the following (in powershell) when we upgraded our print server to 2008 r2 (last week).
First, you have to enable the Print Service's Operational logging..
Right click My Computer -> Manage -> Diagnostics -> Event Viewer -> Applications and Service Logs -> Microsoft -> Windows -> Print Service -> Operational -> Enable log (on the right)You have to run the following script from a machine running Vista or above. It works for us fairly well. It can take about a half hour or so and we only have about a week's worth of logs. I'm worried about the time it'll take when the log grows...
This script gets all printjobs with a date "-ge yesterday". If you want a different timespan, modify the $Date variable, or omit it for all logs. If you aren't using AD or don't want to convert the usernames to full names, omit the "Get full name from AD" section.
Don't forget to change the servername to your server!
I threw the variables at the bottom so you can see the output.
If anyone has suggestions on speeding this up or enhancing the code, please let me know.
$Date = (get-date) - (new-timespan -day 1)
$PrintEntries = get-winevent -computername <servername> -logname Microsoft-Windows-PrintService/Operational | where {$_.timecreated -ge $Date} | where {$_.Id -eq 307}ForEach ($PrintEntry in $PrintEntries)
{
#Get date and time of printjob from TimeCreated
$Date_Time = $PrintEntry.TimeCreated#get Message from printjob.
$rawMessage = $PrintEntry.Message#parse $rawMessage to get owner
$rxUserName = [regex]"owned by ([0-9a-zA-Z]{1,}) on"
$rawUser = $rxUserName.Match($rawMessage)
$Username = $rawUser.Groups[1].Value#parse $rawMessage to get document name
$rxDocumentName = [regex]", ([a-zA-Z-_:/\[#\]\?\\\=\d\.\s\(\)&-,]{1,}) owned by"
$rxMatches = $rxDocumentName.Match($rawMessage)
$docName = $rxMatches.Groups[1].Value#parse $rawMessage to get printername
$rxPrinterName = [regex]"was printed on ([0-9a-zA-Z\-]{1,}) through"
$rxMatches = $rxPrinterName.Match($rawMessage)
$PrinterName = $rxMatches.Groups[1].Value#parse $rawMessage to get print size
$rxPrintSize = [regex]"Size in bytes: ([0-9]+)."
$rxMatches = $rxPrintSize.Match($rawMessage)
$PrintSize = $rxMatches.Groups[1].Value#parse $rawMessage to get number of pages
$rxPageCount = [regex]"Pages printed\: ([0-9]+)."
$rxMatches = $rxPageCount.Match($rawMessage)
$PrintPages = $rxMatches.Groups[1].Value#Get full name from AD
if ($UserName -gt "")
{
$DirectorySearcher = New-Object System.DirectoryServices.DirectorySearcher
$LdapFilter = "(&(objectClass=user)(samAccountName=${UserName}))"
$DirectorySearcher.Filter = $LdapFilter
$UserEntry = [adsi]"$($DirectorySearcher.FindOne().Path)"
$ADName = $UserEntry.displayName
}
$Date_Time
#$rawMessage
$UserName
$ADName
$PrinterName
$PrintSize
$PrintPages
$docName
}- Edited by Sh_Con Friday, February 12, 2010 11:56 PM Updated
-
Monday, February 22, 2010 12:23 PMHi Sh_Con




,
Thanks for your script let me check it out.. -
Monday, February 22, 2010 4:42 PM"""I am by no means a Powershell expert, but I modified my server 2003 printserver script to the following (in powershell) when we upgraded our print server to 2008 r2 (last week). """"
Are you having any problems with the Spooler.exe hogging memory? Are you having any performance issues? Is your 2008 box VM or physical.
At my organization, we are experience a HEAVY performance issue
I'm looking at 2 MS KB articles i found from microsoft. KB951638 and KB952178
Something that does concern me though is even thought the KB951638 fix is for spoolsv.exe verision 6.0.6001.22200, upon looking at my 2008 SP2 32bit server, it's version is 6.0.6002.18005
Any help is great appreciated. Our next is to contact Premier Support for MS, but i'm trying to find a fix first..
Thanks!! -
Monday, February 22, 2010 6:12 PMHave you posted to the Print-Fax forum? http://social.technet.microsoft.com/Forums/en/winserverprint/threads
There are several really helpful and (more importantly!) knowledgeable MS people who respond on that forum.
It may be that it's a driver problem rather than the Spooler per se. -
Tuesday, February 23, 2010 11:14 AM
Hi Sh_con,
I am getting this error when I ran the Powershell script
I added my print server name to the script as well as enabled the print log on the server as you mentioned.http://xs.to/thumb-C1E0_4B83B2D1.jpg
Hi Cat Given Below is the print server log in Windows 2008r2Log Name: Microsoft-Windows-PrintService/Operational
Source: Microsoft-Windows-PrintService
Date: 20-02-2010 13:15:01
Event ID: 307
Task Category: Printing a document
Level: Information
Keywords: Classic Spooler Event,Document Print Job
User: Domain\User
Computer: printserver.domain.com
Description:
Document 154, Full page fax print owned by user was printed on T1-1FA0 through port 10.xx.x.xx Size in bytes: 321011. Pages printed: 1. No user action is required.
Appericiate if you can guide me.Thanks
Ashok Vikram- Edited by AshokVikram Tuesday, February 23, 2010 11:21 AM change link
-
Tuesday, February 23, 2010 11:16 AM
Hi Cat Given Below is the print server log in Windows 2008r2
Log Name: Microsoft-Windows-PrintService/Operational
Source: Microsoft-Windows-PrintService
Date: 20-02-2010 13:15:01
Event ID: 307
Task Category: Printing a document
Level: Information
Keywords: Classic Spooler Event,Document Print Job
User: Domain\User
Computer: printserver.domain.com
Description:
Document 154, Full page fax print owned by user was printed on T1-1FA0 through port 10.xx.x.xx Size in bytes: 321011. Pages printed: 1. No user action is required. -
Tuesday, February 23, 2010 11:29 AMBizarre - it looks right, but the Event ID is different! It always used to be 10 for a successful print, but yours is 307. And the source name is also different.
Change line 8 of the original VBScript to:
Set colEvents=objWMIService.ExecQuery("Select * from Win32_NTLogEvent WHERE EventCode=307 And SourceName='Microsoft-Windows-PrintService'")
Sh_Con's PS version should have worked though (and it's a nice touch getting the AD displayName out as well). -
Thursday, February 25, 2010 3:29 AMHello Ashok Vikram,
I tried to view the screenshot you sent, but the image is a thumbnail and not legible when zoomed in. Could you repost the image in full size?
In the mean-time, you could try removing each of the parse sections and try running it again. If it works, add each back until you see where it's failing. In other words, try the following:
$Date = (get-date) - (new-timespan -day 1)
$PrintEntries = get-winevent -computername <servername> -logname Microsoft-Windows-PrintService/Operational | where {$_.timecreated -ge $Date} | where {$_.Id -eq 307}ForEach ($PrintEntry in $PrintEntries)
{
#Get date and time of printjob from TimeCreated
$Date_Time = $PrintEntry.TimeCreated
$Date_Time
#$rawMessage
#$UserName
#$ADName
#$PrinterName
#$PrintSize
#$PrintPages
#$docName
}
Then add each section one at a time until you see where it fails. Don't forget to remove the # sign in front of each variable when you add the section.
In the mean-time, I will keep an eye out for your new image link. -
Friday, February 26, 2010 11:59 AMHi Sh_con,
Here is the screeshot. Any way let me try after editing the script..
Thanks alot.
[IMG]http://i45.tinypic.com/30bn1b5.jpg[/IMG] -
Friday, February 26, 2010 3:30 PMIn Powershell, you always need to use the full path to the ps1 file (even if you're in the Powershell application). I like to use quotes in the path just in case there are spaces. In your case, the commandline would be:
powershell.exe "c:\PrintSc.ps1"
Please let me know how this works out for you...
Good Luck! -
Tuesday, May 03, 2011 9:37 PM
I've got an improved version of the PowerShell script Sh_con wrote. This one uses FilterHashTable which is faster to filter out specific events. No need for all the costly regex parsing either -- now it directly pulls the needed data from the UserData parameters. It also fixes the parsing bug for the document name, as the existing regex would some times fail resulting in no name being outputted.
This script has been tested on Windows 2008 R2.
Write-Host "collecting event logs..." $Date = (get-date) - (new-timespan -day 1) $PrintEntries = Get-WinEvent -ea SilentlyContinue -ComputerName SERVERNAME -FilterHashTable @{ProviderName="Microsoft-Windows-PrintService"; StartTime=$Date; ID=307} $strOutput = "" $File = "Printing Audit - " + (Get-Date).ToString("yyyy-MM-dd") + ".csv" write-output "Date|Username|Full Name|Client|Printer Name|Print Size|Pages|Document" | Out-File $File write-Host "Parsing event log entries..." ForEach ($PrintEntry in $PrintEntries) { #Get date and time of printjob from TimeCreated $Date_Time = $PrintEntry.TimeCreated $entry = [xml]$PrintEntry.ToXml() $docName = $entry.Event.UserData.DocumentPrinted.Param2 $Username = $entry.Event.UserData.DocumentPrinted.Param3 $Client = $entry.Event.UserData.DocumentPrinted.Param4 $PrinterName = $entry.Event.UserData.DocumentPrinted.Param5 $PrintSize = $entry.Event.UserData.DocumentPrinted.Param7 $PrintPages = $entry.Event.UserData.DocumentPrinted.Param8 #Get full name from AD if ($UserName -gt "") { $DirectorySearcher = New-Object System.DirectoryServices.DirectorySearcher $LdapFilter = "(&(objectClass=user)(samAccountName=${UserName}))" $DirectorySearcher.Filter = $LdapFilter $UserEntry = [adsi]"$($DirectorySearcher.FindOne().Path)" $ADName = $UserEntry.displayName } #$rawMessage $strOutput = $Date_Time.ToString()+ "|" +$UserName+ "|" +$ADName+ "|" +$Client+ "|" +$PrinterName+ "|" +$PrintSize+ "|" +$PrintPages+ "|" +$docName write-output $strOutput | Out-File $File -append }
- Edited by BSOD2600 Tuesday, May 03, 2011 9:41 PM additional info
-
Saturday, June 04, 2011 5:59 AM
-
Tuesday, October 04, 2011 10:14 PM
Hello, hoping you may be able to provide an answer, very new to powershell but came across your script and I am getting an error. Running against a 2k8 R2 print server. Copied the script just as it is above and didn't see that I needed to change anything but I get the following errors
collecting event logs...
Get-WinEvent : The RPC server is unavailable
At C:\Scripts\printeraudit.ps1:3 char:29
+ $PrintEntries = Get-WinEvent <<<< -ea SilentlyContinue -ComputerName SERVERNAME -FilterHashTable @{ProviderName="Micros
oft-Windows-PrintService"; StartTime=$Date; ID=307}
+ CategoryInfo : NotSpecified: (:) [Get-WinEvent], EventLogException
+ FullyQualifiedErrorId : System.Diagnostics.Eventing.Reader.EventLogException,Microsoft.PowerShell.Commands.GetWinEv
entCommand
Parsing event log entries...
You cannot call a method on a null-valued expression.
At C:\Scripts\printeraudit.ps1:13 char:33
+ $entry = [xml]$PrintEntry.ToXml <<<< ()
+ CategoryInfo : InvalidOperation: (ToXml:String) [], RuntimeException
+ FullyQualifiedErrorId : InvokeMethodOnNull
You cannot call a method on a null-valued expression.
At C:\Scripts\printeraudit.ps1:32 char:34
+ $strOutput = $Date_Time.ToString <<<< ()+ "|" +$UserName+ "|" +$ADName+ "|" +$Client+ "|" +$PrinterName+ "|" +$PrintSiz
e+ "|" +$PrintPages+ "|" +$docName
+ CategoryInfo : InvalidOperation: (ToString:String) [], RuntimeException
+ FullyQualifiedErrorId : InvokeMethodOnNullAny help is greatly appreciated, from what I can see is this for anything older than 1 day?
- Edited by jrwms2 Tuesday, October 04, 2011 10:32 PM
-
Tuesday, October 04, 2011 10:27 PM
This topic has ben closed for many months now.
Can you please start a new topic.
jv -
Tuesday, October 04, 2011 11:25 PM
This is the source of your problem: Get-WinEvent : The RPC server is unavailable
Once you figure out why that's breaking, the rest should work. Running it locally on the print server? firewall blocking rpc traffic?
I've also got a different version of this script which extracts the fields and stores them into a MS SQL database.
-
Wednesday, October 05, 2011 12:36 AMIf I needed a BSOD back in 09 I would have asked for it..
jv -
Wednesday, April 11, 2012 5:04 PM
So you need to enable the operational print log on 2008 R2 and i had created a realy nice script that hooks into event 307 which is the job printed event
http://gallery.technet.microsoft.com/New-PrintJob-2f43062f
not sure if this is still an issue, but just came across this thread looking for something else.
Jeffrey S. Patton Assistant Director of IT School of Engineering Computing Services University of Kansas 1520 West 15th Street Lawrence, KS. 66045-7621 | http://patton-tech.com
-
Wednesday, April 11, 2012 7:42 PMheh, since my original script posting, I've got an updated one which parses more than EventID 307 (other print admin events, etc) and uploads them to a SQL database. Your script looks handy though.
-
Thursday, April 12, 2012 3:28 PMdo you have yours available in the gallery? i would be interested in seeing it. I'm currently logging user traffic to sql and it hadn't occurred to me to toss the print job info over there. At that point you could also most like get an idea of average print time and print queue length which have recently become interesting to me.
Jeffrey S. Patton Assistant Director of IT School of Engineering Computing Services University of Kansas 1520 West 15th Street Lawrence, KS. 66045-7621 | http://patton-tech.com
-
Sunday, April 15, 2012 1:55 AMI haven't published it, but will look into doing so next week.
-
Sunday, April 15, 2012 3:11 AM
I haven't published it, but will look into doing so next week.
I thought I saw you say that back in the last century, We will all be buried before...¯\_(ツ)_/¯
-
Monday, September 10, 2012 4:59 PM
Hi,
FYI, I wrote a script to do print server accounting after finding this thread last year. Thanks to Sh_Con and BSOD2600 for starting points and ideas based on what they posted above.
The script I wrote is here: http://gallery.technet.microsoft.com/Script-to-generate-print-84bdcf69
Regards,
Tim Miller Dyck PeaceWorks Computer Consulting Waterloo, ON, Canada
-
Monday, September 10, 2012 8:18 PM
Thanks for the reminder.
My updated version of this script which stores the Events into SQL is now published - http://gallery.technet.microsoft.com/Print-Events-to-SQL-618dd5d4

