Reputation: 1
I am trying to figure out who has been printing from a 2008 print server. I generated a log file from server manager and now have this information in a csv file. My goal is to parse through this info and export it to a new csv to find out the only the associates user ID
, computer host name
and printer name
, all included in the csv log file so I can determine who is printing from this server and make sure I can map them to our new print server. The csv consists of one column of data which has a pattern.
Each row in the csv follows the below pattern, but the wording is different for each row since the job name is longer/shorter or other bits of information that I don't want.
The overall pattern is:
Document #, job name owned by **user ID** on **computer host name** was printed on **printer name** through port ********
More information I don't want
My problem is that I can't hard code something like ignore the first 5 words of each row then the 6th word would be the user ID etc, since the format is different on each row.
What is the best way for me to ignore all words up until either the phrase "owned by", or even better, user ID, save that to a new csv in, then do the same thing for the computer host name and printer name?
Upvotes: 0
Views: 888
Reputation: 16612
This is not an answer for how to extract information from the message text but rather how to avoid having to deal with formatted text in the first place. It appears you are trying to parse the message for Event Log events with ID 307. This code is adapted from PowerShell One-Liner to Audit Print Jobs on a Windows based Print Server.
Using the Get-WinEvent
cmdlet you can query a specific log (Microsoft-Windows-PrintService/Operational
) for specific events (307
), and then it's just a matter of retrieving and adding a meaningful name to each property...
$eventFilter = @{
LogName = 'Microsoft-Windows-PrintService/Operational';
ID = 307;
}
Get-WinEvent -FilterHashTable $eventFilter `
| Select-Object -Property `
'TimeCreated', `
@{ Name = 'JobId'; Expression = { $_.Properties[0].Value }; }, `
@{ Name = 'JobName'; Expression = { $_.Properties[1].Value }; }, `
@{ Name = 'UserName'; Expression = { $_.Properties[2].Value }; }, `
@{ Name = 'MachineName'; Expression = { $_.Properties[3].Value }; }, `
@{ Name = 'PrinterName'; Expression = { $_.Properties[4].Value }; }, `
@{ Name = 'PortName'; Expression = { $_.Properties[5].Value }; }, `
@{ Name = 'ByteCount'; Expression = { $_.Properties[6].Value }; }, `
@{ Name = 'PageCount'; Expression = { $_.Properties[7].Value }; }
For an event with a message like this...
Document 1, Print Document owned by UserName on \\MachineName was printed on Microsoft Print to PDF through port X:\Directory\File.ext. Size in bytes: 12345. Pages printed: 1. No user action is required.
...the above code will output an object like this...
TimeCreated : 3/28/2019 5:36:41 PM
JobId : 1
JobName : Print Document
UserName : UserName
MachineName : \\MachineName
PrinterName : Microsoft Print to PDF
PortName : X:\Directory\File.ext
ByteCount : 12345
PageCount : 1
You could pipe the above command into Export-CSV
to create your CSV file, or even just use Out-GridView
to view and filter the data directly in PowerShell. Either way, no parsing necessary.
Upvotes: 0
Reputation: 25031
TheMadTechnician's Answer already covers a majority of this.
$a = Get-Content original.csv
$a[0] += ",Data"
$a | Set-Content updated.csv
$csv = Import-Csv updated.csv
$data = $csv.where({$_."Event ID" -eq 307}) | Select-String -pattern "(?<=owned by )(?<user>[^ ]+)(?: on )(?<host>.*?)(?: was printed on )(?<printer>.*?)(?= through )"
$(ForEach ($m in $data.matches) {
[pscustomobject][ordered]@{"User"=$m.groups["user"].value
"Host"=$m.groups["host"].value
"Printer"=$m.groups["printer"].value
}
}) | Export-Csv Output.csv -notypeinformation
There are some issues with the CSV that is exported from the Windows print server. If the numbered issues below do not matter in this case, then I can just remove this answer.
Import-Csv
command will be useless. The first four lines of the code cover adding the Data
header to that file. So you can either use code to fix that or just open the file, add the column name, and save.My method here is really no different than the other posted answer. I'm just matching less strings and access those matches with named indexes.
Upvotes: 1
Reputation: 36332
This could be done easily enough using Regular Expression matching. Regular Expressions use pattern matching, so you could do something like:
Get-Content LogFile.csv | Where{$_ -match "^(.*?),.+? owned by (.+?) on (.+?) was printed on (.+?) through port (.+)"} | ForEach{
[PSCustomObject]@{
JobNumber=$Matches[1]
UserId=$Matches[2]
ComputerName=$Matches[3]
PrinterName=$Matches[4]
Port=$Matches[5]
}
}|Export-Csv NewLogFile.csv -NoTypeInfo
That would give you a CSV you could open in Excel or something with just the job number, user ID, the computer they used, the printer it went to, and the port it went on.
Upvotes: 1