0

I'm working on the first steps towards creating a powershell script that will read through printer logs (probably using get-WMI cmdlet), and parse through the logs. Afterwards, I plan on having the script output to a .txt file the name of the printer, a counter of the number of times a printer was used (if possible), and specific info found in the logs.

In order to do this, I've decided to try working backwards. Below is a small portion of what the logs will look like:

10         Document 81, A361058/GPR0000151814_1: owned by A361058 was printed on R3556 via port IP_***.***.***.***.  Size in bytes: 53704; pages printed: 2                                                                  20130219123105.000000-300  
10         Document 80, A361058/GPR0000151802_1: owned by A361058 was printed on R3556 via port IP_***.***.***.***.  Size in bytes: 53700; pages printed: 2   

Working backwards and just focusing on parsing first, I'd like to be able to specifically get the "/GRP", "R3446 (in general, R** as this is the printer name)", and get a counter that shows how often a specific printer appeared in the log files.

It has been a while since I last worked with Powershell, however at the moment this is what I've managed to create in order to try accomplishing my goal:

Select-String -Path "C:\Documents and Settings\a411882\My Documents\Scripts\Print Parse Test.txt" -Pattern "/GPR", " R****" -AllMatches -SimpleMatch 

The code does not produce any errors, however I'm also unable to get any output to appear on screen to see if I'm capturing the /GRP and printer name. At the moment I'm trying to just ensure I'm gathering the right output before worrying about any counters. Would anyone be able to assist me and tell me what I'm doing wrong with my code?

Thanks!

EDIT: Fixed a small error with my code that was causing no data to appear on screen. At the moment this code outputs the entire two lines of test text instead of only outputting the /GPR and server name. The new output is the following:

My Documents\Scripts\Print Parse Test.txt:1:10         Document 81, A361058/GPR0000151814_1: owned by A361058 was printed on
 R3556 via port IP_***.***.***.***.  Size in bytes: 53704; pages printed: 2                                                  
                20130219123105.000000-300  
My Documents\Scripts\Print Parse Test.txt:2:10         Document 80, A361058/GPR0000151802_1: owned by A361058 was printed on
 R3556 via port IP_***.***.***.***.  Size in bytes: 53700; pages printed: 2  

I'd like to try having it eventually look something like the following:

/GPR, R****, count: ## (although for now I'm less concerned about the counter)
Valrok
  • 1,514
  • 7
  • 30
  • 49
  • Remove `Write-Host |` . You can't pipeline an empty command into another command. `Select-String` will output results by it's own – Frode F. Feb 21 '13 at 18:31
  • Graimer: I originally tried without write-host, however whenever I do this I am not getting any output displayed as well, so I thought that I have to use Write-Host in some method – Valrok Feb 21 '13 at 18:36
  • 1
    If `select-string` returns no objects it's because it didn't find anything. The reason it didn't find anything is because you misspelled "GPR". "/GRP" is not "/GPR" :-) – Frode F. Feb 21 '13 at 18:48
  • Aha!! I knew it was something silly I was missing but just could not see it =P Now I'm getting info to appear, however at the moment it is only re-writing the entire 2 lines of testing txt. I want to only output the /GPR, and server name for now – Valrok Feb 21 '13 at 18:50

2 Answers2

1

You can try this. It only returns a line when /GPR (and "on" from "printed on") is present.

Get-Content .\test.txt | % { 
    if ($_ -match '(?:.*)(/GPR)(?:.*)(?<=on\s)(\w+)(?:.*)') {
        $_ -replace '(?:.*)(/GPR)(?:.*)(?<=on\s)(\w+)(?:.*)', '$1,$2'
    }
}

Output:

/GPR,R3556
/GPR,R3556

I'm sure there are better regex versions. I'm still learning it :-)

EDIT this is easier to read. The regex is still there for extraction, but I filter out lines with /GPR first using select-string instead:

Get-Content .\test.txt | Select-String -SimpleMatch -AllMatches -Pattern "/GPR" | % {
    $_.Line -replace '(?:.*)(/GPR)(?:.*)(?<=on\s)(\w+)(?:.*)', '$1,$2'
}
Frode F.
  • 52,376
  • 9
  • 98
  • 114
  • Oh wow... regular expressions.. If it's not too much to ask for, could you explain the code a little? I've never seen powershell written out so heavily based on regular expressions. Here's what I think it's doing and was wondering if you could correct me so I'll understand the code: – Valrok Feb 21 '13 at 19:31
  • it's searching for /GPS and for the word after "on ", "on\s" maybe "on ", "\w+" may mean the next word, I'm not sure I understand what the '$1,$2' is present for however. – Valrok Feb 21 '13 at 19:32
  • 1
    stuff inside parantheses are a group. some are capturing(store value), some not. The first group matches everything before the next group(/GPR) and throws it away. The second matches /GPR and keeps it. The third is equal to the first. then I search for "on " and throws it away(just to search for the place with R3556). Then I get the next word(which is R3556) and keep it, then it matches the rest of the line. Since everything in the line is matched, all will be replaced with what i specify. I specified '$1,$2' which means the 2 groups I kept with a comma in the middle. Hard to explain short :P – Frode F. Feb 21 '13 at 19:51
  • I've added another example that finds the strings with "/GPR" first using `select-string`, and then uses regex for extraction only. It's prettier :) – Frode F. Feb 21 '13 at 19:54
  • After some playing with the method you did your code and slightly modifying it, I think I'm starting to understand how it works. :) If I want to add more things that I want to search (ex. another is DEV) for then will I simply have to add (?:.*)(DEV)(?:.*) and a $3? – Valrok Feb 21 '13 at 20:39
  • And the (DEV) would be another group ($3) that the script would search for throughout the log files. I'm trying to make sure I understand how things work as well since I've never done regex before and it's neat :) – Valrok Feb 21 '13 at 20:41
  • If DEV is behind it on the same line, then yes it might work. I'd recommend using something like http://gskinner.com/RegExr/ to test out regex. It has a list of most if not all operators you can use and a few examples. Also it does real-time testing with sampletext that you provide. Try to google ex. "getting started with regex" to find some tutorials – Frode F. Feb 21 '13 at 21:03
0

I generally start with an example of the line I'm matching, and build a regex from that, substituting regex metacharacters for the variable parts of the text. This makes makes the regex longer, but much more intuitive to read later.

Assign the regex to a variable, and then use that variable in subsequent code to keep the messy details of the regex from cluttering up the rest of the code:

[regex]$DocPrinted = 
'Document \d\d, \w+/(\D{3})[0-9_]+: owned by \w+ was printed on (\w+) via port IP_[0-9.]+  Size in bytes: \d+; pages printed: \d+'

get-content <log file> |

foreach {
 if ($_ -match $DocPrinted)
   {
     $line -match $docprinted  > $null 
     $matches 
   }
 }                                                           
mjolinor
  • 66,130
  • 7
  • 114
  • 135