Use Regular Expressions to Audit the Printer Name and IP Address from Event Logs

I came across this question in the PowerShell forums earlier today that asked how to pull the printer name and associated IP address from the Print Server logs in the System log (Event Id 10).  The first thing I thought was, this sounds like a simple job for Regular Expressions!  An important thing with using regular expressions is that you need to know exactly what it is you are trying to match. As regular expressions can quickly grow more complex than required, it is important to try and keep it as simple as possible. And because I have been working on another project, I really haven’t had the time to put a blog together recently and this sounded like something fun to write about and share with everyone.

With that in mind, I am not a regular expression expert, but I am capable of using them to gather the data that I need when necessary.

With that, this is the message in the event log that we need to pull the data from using regular expressions:

Document 158, wordDocument.doc owned by user1 was printed on PRI-A100-HPCLJ4600 via port IP_192.168.1.4. Size in bytes: 748288; pages printed: 1

The data needed out of the log is the Printer name and the IP address of the printer. The solution that I provided via regular expressions is below:

“(?<Printer>(?:\w+-){2}\w+) via port IP_(?<IPAddress>(?:\d{1,3}\.){3}\d{1,3})”

Lets break down what is going on with the regular expressions:

Printer Name

(?<Printer>(?:\w+-){2}\w+)

This is a very specific match for the printer name. I know that my printer naming standard will always follow this guidance. If a printer had an extra character or pattern of any kind, it would like fail that portion of the match.

(?<Printer>)

By using the parenthesis, anything that fits inside the () is a grouped match. By adding the ?<Printer>, we have created a named capture that is accessible by looking at the $Matches.

Here is a quick example showing a named capture:

"555-5555" -match "(?<PhoneNumber>\d{3}-\d{4})"
$Matches

image

(?:\w+-){2}\w+

Again, we are using the () to specify a group. The \w matches a letter, number and underline and by including the “+”, we are saying that 1 more characters can be matched. The “-“ is a literal item that is matched. Now that we have the a group, we want to match 2 instances of the grouped match by specifying {2}. Lastly, I want to match 1 more or characters of the remaining part of the printer name using \w+. By adding the “?:” right after the opening parenthesis, I am saying that I want to exclude this group from being captured in the regular expression.

Here is a quick example of using the ?:, first without it:

"555-5555" -match "(\d{3})-(\d{4})"
$Matches

image

Here you see that not only is the whole set of numbers is being matched, but also everything that is in both of the parenthesis as well.

Now lets use the ?: to remove the matched groups and only show the whole number:

"555-5555" -match "(?:\d{3})-(?:\d{4})"
$Matches

image

Now only the whole number set is showing up in the $matches.

IP Address

via port IP_(?<IPAddress>(?:\d{1,3}\.){3}\d{1,3})

Now to match the IP address from the event log.

via port IP_

This is pretty self explanatory. We need to match up to this point before we can start pulling the IP address. Since this will not change at all, I chose to leave it as just the literal text.

(?<IPAddress>)

Again, another named capture for the IPAddress.

(?:\d{1,3}\.){3}\d{1,3})

Here we have the complete matching group for an IP address. Note that this is a very generic pattern for matching an IPv4 address. It is assumed that since the IP address for the printer has to be legal, otherwise there would be a more complex regular expression used to not only match an IP, but to match a legal IP at that.

The \d matches a number and as we saw earlier, the {1,3} will match between 1 to 3 instances of a digit. We do have to escape the “”.” using a backslash as a “.” in regular expression means to match any single character.  We finish up the group match by looking for 3 instances of that grouped match using {3} which covers the first 3 octets. We finish up with another \d{1,3} to match the last octet of the IP address.

Wrapping up

Putting all of this together allows us to pull the printer name and associated IP address from the specified event log.

When run in the PowerShell console, you can see that it does indeed pull the information that we were looking for.

$String = "Document 158, wordDocument.doc owned by user1 was printed on PRI-A100-HPCLJ4600 via port IP_192.168.1.4. Size in bytes: 748288; pages printed: 1"
$pattern = "(?<Printer>(?:\w+-){2}\w+) via port IP_(?<IPAddress>(?:\d{1,3}\.){3}\d{1,3})"

$string -match $pattern
New-Object PSObject -Property @{
    Printer = $Matches['Printer']
    IP = $Matches['IPAddress']
}

image

This entry was posted in powershell, scripts and tagged , , , . Bookmark the permalink.

1 Response to Use Regular Expressions to Audit the Printer Name and IP Address from Event Logs

  1. Daniel Petcher says:

    This is a great way to explore RegEx, but the data you seek are already awkwardly present in the EventLog record.

    For Server 2008 (and later) print servers:
    Get-WinEvent -FilterHashtable @{LogName = "Microsoft-Windows-PrintService/Operational"; ID=307; StartTime = $StartTime} -ComputerName $Server |
    # Select-Object -first 200 | Select-Object @{Name="Time";Expression={$_.TimeCreated}},
    @{Name=”User”;Expression={$.Properties.Value[2]}},@{Name="Workstation";Expression={$_.Properties.Value[3]}},
    @{Name=”Printer”;Expression={$
    .Properties.Value[4]}},`
    @{Name=”Port”;Expression={$_.Properties.Value[5]}}

    For 2003 (and possibly earlier) print servers:
    Get-EventLog -LogName System -Source Print -ComputerName $Server | Where-Object {$_.EventID -eq 10} |
    #Select-Object -first 100 | Select-Object @{Name="Time";Expression={$_.TimeGenerated}},
    @{Name=”File”;Expression={$.ReplacementStrings[1]}},
    @{Name=”User”;Expression={($
    .UserName).Replace(“NT AUTHORITY\”,””)}},@{Name="Printer";Expression={$_.ReplacementStrings[3]}},
    @{Name=”Port”; Expression={$_.ReplacementStrings[4]}}

    Despite my attempt to filter the data as early as possible, this query still limps painfully slowly across a WAN. I strongly recommend using PowerShell’s Remote execution techniques if you can. Un-comment the Select-Object clause while you’re debugging your surrounding script.

    I used these queries in a script that checked who was still using a set of print servers that I wanted to retire. Most of my printer fleet uses DHCP and hostname addressing, so I did not need to answer your original question regarding the printers’ IP addresses. That data is also present in the “Properties” or “ReplacementStrings” hashtables, though.

    It looks like I’ll be learning RegExes from you as well as WPF….
    Thanx!

Leave a comment