Colorize matching output in the pipeline
The other day I was looking for an option to colorize certain rows when using Format-* cmdlets. None of the cmdlets (including out-host, out-default) gives you the option to do that unless you define a custom PowerShell format/view file (ps1xml). I wish the Format-* cmdlets had a scriptblock parameter to which I can pass a piece of code that will colorize certain rows based on a criteria (maybe I'll fill a suggestion on Microsoft connect).
The major drawback of this custom format files is that you have to build them (requires some experience) for each type you want to print out, loading them into your environment via Update-FormatData and then executing them with the -view parameter of the format-table or format-custom cmdlets.
This method involves too much configuration and I was looking for a way to make the process more portable, depend less and operatable on any given command-let, so I can easily use it on any PowerShell machine or script.
Lets say you want to colorize all text file names that begins with "s".
PS C:\Scripts> Get-ChildItem $env:WINDIR *.txt
Directory: Microsoft.PowerShell.Core\FileSystem::C:\WINDOWS
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a--- 7/28/2007 3:25 PM 8184 ModemLog_Agere Systems HDA Modem.txt
-a--- 6/21/2007 11:43 AM 38280 ModemLog_HTC USB Modem.txt
-a--- 3/5/2007 6:17 PM 3075 OEWABLog.txt
-a--- 8/30/2007 10:51 AM 32622 SchedLgU.Txt
-a--- 3/1/2007 1:56 AM 1012440 setuplog.txt
-a--- 7/31/2006 7:41 PM 726072 SIGVERIF.TXT
Get-ChildItem $env:WINDIR *.txt | foreach {
if($_.name -match "^s.*"){
write-host $_ -ForegroundColor "green";
} else {
write-host $_ -ForegroundColor "gray"
}
}
ModemLog_Agere Systems HDA Modem.txt
ModemLog_HTC USB Modem.txt
OEWABLog.txt
SchedLgU.Txt
setuplog.txt
SIGVERIF.TXT
As you can see, the foreach output contains only file names, no table headers nor additional property columns. It sure doesn't look like Format-Table's output.
For about an hour or so I was struggling with PowerShell commands and made a lot of experiments. Finally, I was able to construct a filter. The filter accepts three parameters.
Color, property name to match against and a regular expression pattern.
Surprisingly, the solution was pretty simple. Without the filter the code looks like:
Get-ChildItem $env:WINDIR *.txt | foreach {
if($_.name -match "^s.*"){
[console]::ForegroundColor="green"; $_;
} else {
[console]::ForegroundColor="white"; $_;
}
}
Well, here's the code for the filter:
filter colorize-row{
param(
[string]$color="green",
[string]$prop="name",
[string]$regex=$(throw "must supply regular expression pattern")
)
# save current console colors
#$bgc=[console]::BackgroundColor;
$fgc=[console]::ForegroundColor;
if($_.$prop -match $regex){[console]::ForegroundColor=$color; $_}
else{[console]::ForegroundColor=$fgc; $_}
# revert to saved console colors
#[console]::BackgroundColor=$bgc;
[console]::ForegroundColor=$fgc;
}
# get all text files in c:\windows that begins with "s", use default filter color
PS C:\Scripts> Get-ChildItem $env:WINDIR *.txt | colorize-row -regex "^s.*"
Directory: Microsoft.PowerShell.Core\FileSystem::C:\WINDOWS
Mode LastWriteTime Length Name---- ------------- ------ ----
-a--- 7/28/2007 3:25 PM 8184 ModemLog_Agere Systems HDA Modem.txt
-a--- 6/21/2007 11:43 AM 38280 ModemLog_HTC USB Modem.txt
-a--- 3/5/2007 6:17 PM 3075 OEWABLog.txt
-a--- 8/30/2007 10:51 AM 32622 SchedLgU.Txt
-a--- 3/1/2007 1:56 AM 1012440 setuplog.txt
-a--- 7/31/2006 7:41 PM 726072 SIGVERIF.TXT
Now with get-process:
# get all processes which contains "svchost" in their names, colorize in yellow
PS C:\Scripts> get-process | colorize-row -regex "svchost" -prop "name" -color yellow
Handles NPM(K) PM(K) WS(K) VM(M) CPU(s) Id ProcessName
------- ------ ----- ----- ----- ------ -- -----------
...
...
68 3 816 1264 14 0.02 524 sqlbrowser
311 9 34172 20632 1100 1.02 436 sqlservr
84 2 1064 1616 20 0.44 548 sqlwriter
1894 246 34804 38528 217 197.80 180 svchost
104 5 1772 2336 33 10.56 332 svchost
126 4 2616 2160 36 3.80 580 svchost
284 12 8124 5084 47 2.45 1152 svchost
75 3 2332 1468 31 0.06 1512 svchost
230 6 3464 2776 65 72.11 1640 svchost
428 14 2368 2852 40 15.72 1692 svchost
95 10 1796 1460 37 0.28 2696 svchost
807 0 0 244 2 359.94 4 System
207 7 6608 9788 62 114.42 5828 TextPad
...
...
About PowerShell Console Colors
You can specify one of the following enumeration values to the filter -color parameter. To get all possible enumeration color names/values:
>> [consolecolor]::GetNames([System.ConsoleColor])
-or-
>> [consolecolor]::GetValues([System.ConsoleColor])
-or- better use the following to generate a table of color names and there corresponding numeric values:
$colors=@([enum]::GetNames([consolecolor]));
0..($colors.length-1) | select @{n="Name";e={[string][enum]::parse([ConsoleColor],$_)}}, @{n="Constant";e={$_}} | format-table -autosize
Name Constant
---- --------
Black 0
DarkBlue 1
DarkGreen 2
DarkCyan 3
DarkRed 4
DarkMagenta 5
DarkYellow 6
Gray 7
DarkGray 8
Blue 9
Green 10
Cyan 11
Red 12
Magenta 13
Yellow 14
White 15
1 comment:
Hi $hay
Clever way of changing the color without affecting the normal output. Good stuff!
Post a Comment