PowerShell Script: Get a list of printed documents

I thought I would share something I did a few months ago and turned out to be pretty useful… a little PowerShell script to get a list of printed documents.

Intro

So I was asked if I could get a list of printed documents for a specific printer between a certain date range. The easiest and quickest way to do this I thought was through a PowerShell script. The script simply searches the Print Service event log on the print server and returns printed document events. The script then sifts through the results to get the data we need.

The Script

Ok so lets get straight to the script and then I will explain a few things…

Getting the Events

First off the most important thing is to search the print server’s event log for all Print Job Status events (Event ID 307) between the date range required.

To do this we use the Get-WinEvent PowerShell Cmdlet and store all of the results within the $Results variable:


$Results = Get-WinEvent -FilterHashTable @{LogName="Microsoft-Windows-PrintService/Operational"; ID=307; StartTime=$StartTime; EndTime=$EndTime;} -ComputerName "print-01"

Using the FilterHashTable property, we are able to determine the following search criteria:

  • Log Name – The log we want to search. In this case it is the Microsoft Windows Print Service Log
  • Event ID – The one we need is event 307, which as mentioned before is the Print Job Status events
  • Start & End Time – This is based on the $StartTime and $EndTime variables

Note: Due to the nature of Get-WinEvent and the Print Services event log, this script will only run on Windows 2008, Windows 7 and newer.

Processing the results

So now all of the print job status events between our date range have been collected and stored within the $Results variable. Now we need to process the results and return only the printed documents that are related to the printer we are looking for (in this case HP-4350-01).

Quick Side Note: At this point you could skip searching for only a particular printer and rather store all of the results in a database or an excel spreadsheet.

I actually modified this script and did exactly this and now store all printed documents and their details in a database table which is now easily searchable via SQL queries.

This is a really good idea if your company is looking at reducing their printing costs as you can give management some real concrete figures as to printing per month, per department, even per user.

Ok, so how do we search for a particular printer (if you want to)…. we use a simply ForEach loop and then use an If statement to find only the events from the printer we need


If($PrinterName.Contains("HP-4350-01")){

Storing the results

Finally, the results we actually care about we store first in a PS-Object and then nest that PS-Object within the $aPrinterList array. The reason why I use a PS-Object is because it acts the same way as a hash-table, however it allows you to easily nest it within an array. That way each array element has a number of properties to it (e.g. DocName, UserName, etc). This makes it really easy to retrieve and present array data.

Presenting the data to the user

So now we need to output this data into some meaningful format that you can send to your manager or the requesting client. To do this, we pipe the $aPrinterList array into the Export-Csv cmdlet.


$aPrinterList | Export-Csv -LiteralPath "C:\TempPrintAudit.csv"

Final Thoughts

This is a pretty neat idea on how to collect print events from a printer server. The other awesome thing is that this script is almost a template that you can re-use to collect and present any events from any log using Get-WinEvent. All you need to do is make a few tweaks and there you have it, you will be collecting and outputting event data in no time.

If you have any questions, problems, queries or improvements please let me know in the comments below.

Thanks
Luca

Comments

    1. Hi mahmoud,
      Can you please send me a list of the results you are getting and I can have look for you. You can send it to admin@9to5IT.com. Also check the event in the event viewer to ensure there is a page count being collected by the print server.

  1. Hi there, great scripts you got here 🙂

    I have a noobie question, when you create the psobject, how do you know i.e that “MachineName” equals to “Event.UserData.DocumentPrinted.Param4” ?

    I’m asking because i’m trying to adapt the script to extract specific infos from event_id 4624 (logons). Im figuring i should do something like:


    ForEach($Result in $Results){
    $ProperyData = [xml][/xml]$Result.ToXml()
    $userid = $ProperyData.Event.UserData.???????.Param??????

    If($userid.Contains(“ABCDEFG”)){
    ….

    Best Regards,
    Massimo

    1. Hi Max, thanks very much. If you open the event you are wanting to extract the data from (in your case 4624) in Event Viewer and then click on the Details tab and then select XML View you will see two major elements – System and User, each have a number of child-elements.
      The system child-elements data can be accessed by simply using the element’s name – e.g. $Result.TimeCreated or $Result.EventID.
      The user child-elements data is actually stored in a number of paramaters and have to be accessed like this:

      $ProperyData = [xml][/xml]$Result.ToXml()
      $ProperyData.Event.UserData.DocumentPrinted.Param8

      The number Param number corresponds to the Param number in the XML View of the event using Event Viewer. I hope this helps. If you got any more questions, send me an email (admin@9to5IT.com) and I am glad to help you further. Thanks Luca

  2. Thanks for the script, it has been quite useful. Is it possible to get the actual document name? In the DocName field it only shows the same generic printdocument as the name for every job.

    1. Hi Craig,

      The best way would be to look at EventID 307 in the Print logs in Event Viewer. From there you can see all of the information that it logged. You can then easily manipulate the script to collect that information.

      You can then add a line between lines 14-19 to collect that additional information.

      Hope this helps.
      Luca

  3. Hi Luca,

    Need you help !

    I have list of 170 print servers , do we have any script to check the total jobs printed for last 3 months from all the print queues hosted in all the print servers.

    Regards
    Swaroop Kumar

    1. Hi Swaroop,

      You could achieve this by storing a list of your print servers into a csv file. Then by using the Import-csv cmdlet you can pull the list of servers into a variable.

      Next you just need to wrap the script with a ForEach($Server in $Servers){} (assuming the $Servers is the variable you used to store the list of servers from the csv file).

      The only other thing you would need to do is remove the if statement on line 12 as you want all printers and not a single one. You may also want to add the print server name to each PS-Object so that you can track the event with a particular print server.

      Hope this helps

      Luca

  4. Hi ,

    I want to sent alert mail to users and system admin when the users printing page size exceeds the limit. Can u help me on this.

    1. Hi Raja,

      Best thing to do is to the PowerShell Script: Get a list of printed documents and just modify it to check for the page size. Once the page size for a job exceeds the limit you have set, you can send an email.

      To send an email, have a look at the last function in my PowerShell Logging Functions script. You can find it here >>> PowerShell: How to easily create log files for your scripts.

      Hope that helps
      Luca

      1. Any way to write data into eventdata section? I have a script that i want to push variables to the event it creates.

  5. Thanks Luca,

    However after spending 3 days googling and attempting to get a working example in powershell I believe that there is no native exposure to the API that allows us to manipulate that part of the event log. I have found examples I other languages so my next attempt would be to launch a script from powershell..

    Thanks,
    Fahad

  6. Hi luca,

    Do you have any powershell script to extract the printer status and job processed from LPS Status Client in the Loftware server.

    Thanks,
    Somya

    1. Hi Somya,

      Sorry I don’t have a script for that. Shouldn’t be too hard to create though if you follow the similar steps I have taken in my script and just look for a different set of properties than mine.

      Hope this helps
      Luca

  7. Hi, great script however there is a issue, event 307 always shows pages count as 1. So if you print 10 copies pages printed is still only going to show as 1 page. You know of any way to get it to show the number of copies? After some googling someone said event 805 shows the copies but it only shows 1 copy for me regardless. Running on Win Server 2008 R2. Hope you can help, been scratching my head for awhile now.

    1. Hi Michael,

      I was running my script against a Windows 2008 R2 Print Server as well without any issues. Is your environment just a standard Windows Print Server?

      Is it just happening for one particular printer or different types of printers as well? The other thing to check would be to create the print queue on another print server and see if that issue is occurring. Seems weird to me that you are only getting 1 page as the count. I think this has more to do with the printer than the printer server. What printer is it?

      Thanks

  8. Hi, same issue here.
    Both with wmi and with and in the log i’m getting copies 1. Not always tho.. same printer but different document ( word = bad , excel seems ok ).

    could you double check on your environment? thx

  9. Fantastic, Thanks so much
    I would appreciate if we could add computer name where we printed the job on?

Leave a Comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.