Tracking Print Jobs

While tooling around on the internets I came across some logging information on Windows Print jobs. Our current setup shoots all of the company print jobs through a couple of Windows print servers and it turns out it is easy to turn on logging and track who is printing what, when, where and how many. First on the windows server you can enable tracking for print jobs (off by default) here: Event viewer->Applications and services Logs->Microsoft->Windows->PrintService Right click on Operational and choose enable log. There are a couple of events that show up but we are interested in Event ID 307 which will give us logs such as the following:

Document 90, Print Document owned by EmployeeOne on Workstation-10 was printed on BIG_COLOUR_PRINTER through port 10.77.1.211.  Size in bytes: 58920. Pages printed: 7. No user action is required.

Assuming you are picking it up via Winlogbeats, here is a Sidecar configuration that would make sure the print job is snagged - note how I am dropping eventID 801,805, and 842 since they aren’t’ relevant to this and I don’t want to fill my Graylog with anything uninteresting…

# Needed for Graylog
fields_under_root: true
fields.collector_node_id: ${sidecar.nodeName}
fields.gl2_source_collector: ${sidecar.nodeId}

output.logstash:
   hosts: ["${user.BeatsInput}"]
path:
  data: C:\Program Files\Graylog\sidecar\cache\winlogbeat\data
  logs: C:\Program Files\Graylog\sidecar\logs
tags:
 - windows
logging.metrics.enabled: false
winlogbeat:
  event_logs:
   - name: Application
   - name: System
   - name: Security
   - name: Microsoft-Windows-PrintService/Operational
     processors:
       - drop_event.when:
           or:
             - equals.winlog.event_id: "801"
             - equals.winlog.event_id: "805"
             - equals.winlog.event_id: "842"

Beats does a good job of picking things out but doesn’t give them pretty fieldnames so I have a pipeline rule these logs pass through as follows:

rule "Printer_Tracking"
when
    // Function converts generic fields names to useful ones
    // then removes the unhelpful fieldnames because we don't want them
    to_string($message.winlog_event_id) == "307"
then
    // change fields to something that makes sense.

    set_field("print_user",              $message.winlog_user_data_Param3);
    set_field("printed_from",            $message.winlog_user_data_Param4);
    set_field("printer_name",            $message.winlog_user_data_Param5);
    set_field("printed_from_ip",         $message.winlog_user_data_Param6);
    set_field("page_count",      to_long($message.winlog_user_data_Param8));
    remove_field("winlog_user_data_Param1"); // document number
    remove_field("winlog_user_data_Param2"); // action i.e.  "Print Document"
    remove_field("winlog_user_data_Param3");
    remove_field("winlog_user_data_Param4");
    remove_field("winlog_user_data_Param5");
    remove_field("winlog_user_data_Param6");
    remove_field("winlog_user_data_Param7");  //size in bytes
    remove_field("winlog_user_data_Param8"); 
    remove_field("winlog_process_thread_id"); // who cares about the thread id? Not me. 
    remove_field("winlog_process_pid");       // who cares about the pid?       Also Not me. 
    remove_field("winlog_opcode"); //  
    // Pull out for reporting
    route_to_stream("Printing_reports_stream");      

end

SIDE NOTE: You could manage renaming the fields in the collector if you want - follow instructions here

And you can end up with something like this barely redacted page: