How does Select-String work with Pipelines of objects?

How does Select-String work with Pipelines of objects?

Rate This
  • Comments 4

<Edited to convert Match-String to Select-String 7/9/2006>

In our newsgroup (Microsoft.Public.Windows.Server.Scripting) , Vasu asked about how Select-string works in pipelines:


Here is what I observe:
1. MSH C:\> get-alias
 ..truncated..
Alias           ri                                   remove-item
Alias           rni                                  rename-item
..truncated..

2. MSH C:\> get-alias | select-string ri
ri
MSH C:\>

The question is why did the string "ri" get emitted instead of the alias record.

So what is going on here?

Select-String works on Streams of STRINGS.  When you pass it a string of OBJECTS, the MONAD engine converts those objects to strings before passing them to Select-String.  Thus the following 2 commands are functionaly equivalent:

get-alias | select-string "ri"
get-alias | foreach {"$_"} |Select-string "ri"

Converting an object to a string is accomplished by call that object's ToString() method (vs using MONAD's formating subsystem).  Notice the difference - the first uses Monad's formating and the second is the object's ToString() 

MSH> (gal ri)

CommandType     Name                          Definition
-----------     ----                          ----------
Alias           ri                            remove-item


MSH> (gal ri).ToString()
ri
MSH>

If you wanted Select-String to work on the Monad formatted output, you'll need to get that as a string.  Here is the thing to grok about our outputing.  When your command sequence emits a stream of strings, we emit it without processing.  If  instead, your command sequence emits a stream of objects, then we redirect those objects to the command Out-Default.  Out-Default looks at the type of the object and the registered formating metadata to see if there is a default view for that object type.  A view defines a FORMATTER and the metadata for that command.  Most objects get vectored to either Format-Table or Format-List (though they could go to Format-Wide or Format-Custom).  THESE FORMATTERS DO NOT EMIT STRINGS!  You can see this for yourself by the following:

MSH> gps |ft |group {$_.GetType().name} |ft Count,Name -auto

Count Name
----- ----
    1 FormatStartData
    1 GroupStartData
   53 FormatEntryData
    1 GroupEndData
    1 FormatEndData

These formating records are then vectored to an OUT-xxx command to be rendered into the appropriate data for a particular output device.  By default, they go to Out-Host but you can pipe this to Out-File, Out-Printer or Out-String.  (NOTE: these OUT-xxx commands are pretty clever, if you pipe formating objects to them, they'll render them.  If you pipe raw object to them, they'll first call the appropriate formatter and then render them.)

So to make Select-string work against the string version of Monad's output, you'd do this:

MSH> get-alias | out-string -stream | Select-string "ri"
Alias           clv                       clear-variable
Alias           gdr                       get-drive
Alias           gv                        get-variable
Alias           ndr                       new-drive
Alias           nv                        new-variable
Alias           rdr                       remove-drive
Alias           ri                        remove-item
Alias           rv                        remove-variable
...

Notice a couple things 1) you had to say "Out-String -STREAM" (if you didn't say -STREAM you would have gotten a single string) 2) now Select-string matches any line that has an "ri" in it not just the ones where the NAME has an "ri" in it.

Think about the last statement 'just the ones where the NAME has an "ri" in it'.  One of the things we designed Monad to do was to give you an experience where you think it, you type it, you get it.  So let's say it, "I want to GET the ALIASes WHERE the NAME matches the string RI".  Now lets type it:

MSH> GET-ALIAS |WHERE {$_.NAME -match "ri"}

CommandType     Name                       Definition
-----------     ----                       ----------
Alias           ri                         remove-item
Alias           write                      write-object

It take a while to stop thinking in terms of streams of text and start thinking in terms of streams of objects.  The benefit is that once you do this, you begin to ask questions in a way that makes it really easy to answer.

Enjoy!

Jeffrey Snover
Monad Architect

[Edit: Monad has now been renamed to Windows PowerShell. This script or discussion may require slight adjustments before it applies directly to newer builds.]

PSMDTAG:FAQ: How does Select-String work with objects?

PSMDTAG:FAQ: How does outputing (i.e. out-default) work?

PSMDTAG:PHILOSOPHY: Stop thinking in terms of streams of text and start thinking of streams of objects

PSMDTAG:CMDLET: Get-Alias, Select-String

PSMDTAG:CMDLET:FORMAT: out-default, out-string -stream

PSMDTAG:INTERNAL: Formatters do NOT emit strings, they emit format records

 

Leave a Comment
  • Please add 1 and 4 and type the answer here:
  • Post
  • Hmm. I comment here since this is the only sensible result I got from Google and I guess you *should* know the answer. :)

    when writing your own cmdlet, is it possible to do something sensible with those Format{Start,End,Entry}Data entries? I did not find any methods that are useful.

    Just assume someone wants to write an Out-GUI cmdlet that shows the results in a TreeView CommonControl (and allows sorting and stuff), or an output cmdlet that shows results like Linux' "top" command does with processes (i.e show columns, that can be resized/swapped/hidden/sorted/scrolled by keystrokes).

    Is this possible for someone who only uses the accessible API to write such a cmdlet that can work sensibly with pre-formatted (format-table & co) data?

    TIA for any answer (you may write to schierlm [AT] gmx [DOT] de)

    Michael
  • > when writing your own cmdlet, is it possible to do something sensible with those Format{Start,End,Entry}Data entries?

    No.  We are not going to document those objects and they are subject to change without notice.  You are better off writing an out-xxx cmdlet that takes the raw objects directly and displays them.

    Jeffrey Snover [MSFT]
    Windows PowerShell/Aspen Architect
    Visit the Windows PowerShell Team blog at:    http://blogs.msdn.com/PowerShell
    Visit the Windows PowerShell ScriptCenter at:  http://www.microsoft.com/technet/scriptcenter/hubs/msh.mspx
  • PingBack from http://HuddledMasses.org/jaykul/powershell-host-and-custom-formatting/

  • out-string -stream did the trick for me ( first page on my question to google regarding custom format tables and select string pipeline inputs ) . Many thanks

Page 1 of 1 (4 items)