in reply to unpacking wmic command's unicode output
I learned some things while working on this little problem, so I thought I'd share. update: changed $ARGV[0] for @ARGV per discussion.
The first thing is that wmi doesn't necessarily use the same fixed headers on different machines. My first attempt was a simple batch file and worked on my machine:
@echo off wmic process |find /i "Caption" |perl -CS -ne "($caption,$commandline, +$ppid,$pid)=unpack('a[21] a[270] @798a[17] @899a[11]',$_);print '}',$ +caption,'-',$ppid,'-',$pid,'-',$commandline,'{',$/;" |find /i "parent +" wmic process |find /i "%1" |perl -CS -ne "($caption,$commandline,$ppid +,$pid)=unpack('a[21] a[270] @798a[17] @899a[11]',$_);print '}',$capti +on,'-',$ppid,'-',$pid,'-',$commandline,'{',$/;" |find /v /i "find"
So, I ended up turning it inside-out. Instead of using perl in a batch file I used the wmic command in a perl script. I ended up opening a file (well, pipe) like almut suggested, but using BrowserUK's command line option to cover the unicode issue.
#!/usr/bin/perl -WCD use strict; use warnings; use Data::Dumper; $\ = $/; my $debug = 1; #array of fields to display my @processFields = ('Caption','ParentProcessId','ProcessId','CommandL +ine'); #ARGV processing #my $searchfor = $ARGV[0] ? join(' ',@ARGV) : die("I need a process to + look for."); # corrected, per bug in discussion below. You might also check out th +e style discussion not changed here. my $searchfor = @ARGV ? join(' ',@ARGV) : die("I need a process to loo +k for."); #set up handle - note -CD arg, above open (PROCINFO, "wmic process |")||die("Can't open wmic for process in +fo pipe!"); #loop my $template=''; while (<PROCINFO>) { #first time get header, find position of columns, build unpack tem +plate unless ($template) { while (@processFields) { my @allFields = split; my $field = pop @processFields; my $fieldIndex; for ($fieldIndex=0; $fieldIndex<=$#allFields; $fieldIndex+ ++) { if ($allFields[$fieldIndex] eq $field) { last; } #assert: found $field in @allfields with index $fieldI +ndex } pos=undef; /\b$field\b/g or die("Could not find field $field"); my $fieldPos = pos; $fieldPos = $fieldPos - length($field); my $nextFieldPos; if ($fieldIndex+1 <= $#allFields) { pos=undef; /\b$allFields[$fieldIndex+1]\b/g or die("Could not fin +d next field $allFields[$fieldIndex+1]"); $nextFieldPos = pos; $nextFieldPos = $nextFieldPos - length($allFields[$fie +ldIndex+1]); } else { $nextFieldPos = length($_)+1; } my $fieldlength = $nextFieldPos - $fieldPos; $template = '@'.$fieldPos.'a['.$fieldlength.'] '.$template +; } #do it once for the header row my $fieldVal; my $outLine=''; foreach $fieldVal (unpack($template, $_)) { $outLine .= ($outLine?'-':'}').$fieldVal; } $outLine .= '{'; print $outLine; #all other times look for, unpack and display if matches arg } if (/$searchfor/) { my $fieldVal; my $outLine=''; foreach $fieldVal (unpack($template, $_)) { $outLine .= ($outLine?'-':'}').$fieldVal; } $outLine .= '{'; print $outLine; } } close(PROCINFO);
If I were to spend more time on it I would get the common code (to get the position of a field and also to constuct the output lines) out into functions. Also, I've rethunk how to get the length of the fields by looking for something like /\G(\b)/gc, but it's a fairly strightforward little throw-away script, so I'm not going to spend that much more time on it.
Back to lessons learned:
- if you're searching for 'ProcessID' you'll find it in 'ParentProcessID' (duh!); this messed me up for a little bit and drove me to put all that $nextField logic in (again, I've rethunk it and think it would be more elegant with \G).
- -CS worked on the command line, but when I added it to the she-bang (#!/usr/bin/perl -CS -W) it complained about an 'Unknown Unicode option letter'. I finally figured out I had to combine things in the command options as #!/usr/bin/perl -WCS. In retrospect, there are other problems in my past that are explained by this and I never knew it.
- I had to pos=undef; to get the search to reset, since it didn't search backwards from the previous match.
- $#ARGV is 0 whether there are zero or 1 arguments. This led me to the $ARGV[0] ? : solution.
- I was worried about getting the output fields in the order I want and was happy to learn that using @location in the template let me bounce around in the string and still return the fields in the order they appreared in the template.
I'm sure there are other lessons here and many wasy to improve my little script, but as I said, I probably won't spend any more time on it (the script that is; I'll happily spend time learning form any feedback I get here). I hope the lessons learned are helpful.
|
|---|
| Replies are listed 'Best First'. | |
|---|---|
|
Re^2: unpacking wmic command's unicode output
by ikegami (Patriarch) on Nov 12, 2008 at 17:58 UTC | |
by goibhniu (Hermit) on Nov 12, 2008 at 18:33 UTC | |
by ikegami (Patriarch) on Nov 12, 2008 at 19:10 UTC | |
by goibhniu (Hermit) on Nov 12, 2008 at 19:21 UTC | |
by ikegami (Patriarch) on Nov 12, 2008 at 19:48 UTC | |
| |
by goibhniu (Hermit) on Nov 12, 2008 at 18:36 UTC | |
by ikegami (Patriarch) on Nov 12, 2008 at 19:15 UTC |