For any of you that come from a Linux or Unix background, you probably have a good solid friendship with the grep command. Unfortunately, the utility of this little command has been overlooked for many who spend the majority of their day in the Windows world. This caused me a bit of grief when I went looking for the equivalent command in PowerShell. Now, don’t get me wrong, I found the Select-String
command pretty quickly, and I had great success when searching inside of files, but for searching the output of a powershell command, I found its results to be somewhat…
1 2 3 4 5 6 7 8 9 10 11 |
C:\> ls | select-string "windows" windows install.exe:57:♫☼►◄↕‼¶§▬↨↑↓→←∟↔▲▼ !"#$%&'()*+,-./0123456789:& ?@abcdefghijklm nopqrstuvwxyz[\]^_`abcdefghijklmnopqrstuvwxyz{|}~⌂ = getprocesswindowstation getuserobjectinformationa getlastactivepopup getactivewindow messageboxa use r32.dll ( n u l l ) (null) ♠ ♠ ☺ ► ♥♠ ♠☻►♦eee♣♣♣♣♣50 p ( 8p 700wp `h```` xp ♠������ ►♥�����¶♣ ♣eee���♣ 00�p� ('8pw� 700pp� (���� `h`hxp complete object locator' class hierarchy descriptor' base class array' base class descriptor at ( type descriptor' `local static thread guard' `managed vector copy constructor iterator' `vector vbase copy... |
…less than useful (As a side note, I found it difficult to include the many system beeps that resulted from this command, so you’re have to live with just the truncated text output).
Those of you who have an intimate knowledge of PowerShell can probably tell pretty quickly what happened there. Instead of searching the text of the output of ls
, Select-String
was fed a bunch of FileInfo and DirectoryInfo objects, which it was very happy to read into memory and attempt to cat to the terminal.
I tried getting around this issue recently by piping everything to Out-String, first, but I was left with more unexpected behavior:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
C:\> ls | Out-String | Select-String "Windows" Directory: C:\ Mode LastWriteTime Length Name ---- ------------- ------ ---- d---- 10/14/2014 11:19 AM altools d---- 11/10/2014 3:52 PM DFSReports d---- 10/29/2014 10:07 AM ExchangeSetupLogs d---- 11/5/2014 11:43 AM inetpub ... d---- 11/18/2014 4:21 PM temp d-r-- 11/6/2014 12:23 PM Users d---- 11/14/2014 11:09 AM Windows C:\> |
Yay, we got the string output from the previous command! Unfortunately, for some reason, Select-String
was unable to filter it. Oh, and no, I haven’t figured out the cause. I have, however, found the solution. Checking the help file reveals that Out-String
has a nifty little switch named Stream
, which changes the way the output hits the pipeline. Using this switch appears to give us the expected result:
1 2 3 |
C:\> ls | Out-String -Stream | Select-String "Windows" d---- 11/14/2014 11:09 AM Windows |
So, there it is. I realize this is a bit of a long-winded article for such a simple thing, but sometimes it’s useful to have a bit of context. Hopefully that’s the case here, and I’m not just completely full of hot air.
As a side note, Windows PowerShell has some pretty fantastic filtering capabilities which Don Jones at Microsoft wrote a very helpful article about. If you find yourself using Out-Host -Stream | Select-String
in a script, you’re probably doing it wrong.