106

In PowerShell I have tried:

alias | select-string Alias

This fails even though Alias is clearly in the output. I know this is because select-string is operating on some object and not the actual output string.

What can be done about it?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Ian Kelling
  • 9,643
  • 9
  • 35
  • 39

8 Answers8

117

I think this solution is easier and better, use directly the function findstr:

alias | findstr -i Write

You can also make an alias to use grep word:

new-alias grep findstr
Roi
  • 1,434
  • 2
  • 11
  • 13
  • 5
    This is the most intuitive and easy to remember approach among all the other answers. – o.v Oct 31 '17 at 09:25
  • 12
    1/2. Just to clarify two things since I was a little confused trying to understand what this command is doing. First the `-i`. If you show the help for findstr with `findstr /?` it will show all the options prefaced with a forward slash `/`. However it will accept arguments prepended with a `/` OR a `-'. For example `ipconfig /all` is functionally identical to `ipconfig -all`. So `-i` is the same as `/i` and since findstr is an old DOS program, and old DOS programs don't care about case, `/i` is idential to `/I`. So it means it's a case insesitive search. – Stack of Pancakes Apr 26 '18 at 19:28
  • 6
    2/2. The next thing that confused me was the `Write` at the end. `alias` is an alias for `Get-Alias`, which is a PowerShell cmdlet. and `Write` is actually the string being searched, NOT the alias of `Write-Output` which I thought initially because of the colored formatting indicating a PowerShell command. I thought that `Write-Output` was being replaced in-place for findstr to search through. It's not. So what's actually happening is each line of `Get-Alias` is piped to findstr and that will search the piped str for a case insesitive match of the search term "Write". – Stack of Pancakes Apr 26 '18 at 19:28
  • Perfect for my needs! – Marinaio Mar 23 '21 at 15:51
  • 1
    This is a ***cmd.exe/DOS*** answer but the question says ***powershell***. – c z Jun 16 '22 at 12:48
  • The problem with `findstr` is the line length limit (8191 characters) – golimar Aug 23 '22 at 00:50
73

Your problem is that alias emits a stream of AliasInfo objects, rather than a stream of strings. This does what I think you want.

alias | out-string -stream | select-string Alias

or as a function

function grep {
  $input | out-string -stream | select-string $args
}

alias | grep Alias

When you don't handle things that are in the pipeline (like when you just ran 'alias'), the shell knows to use the ToString() method on each object (or use the output formats specified in the ETS info).

Zombo
  • 1
  • 62
  • 391
  • 407
Mike Shepard
  • 17,466
  • 6
  • 51
  • 69
  • 1
    Just wanted to add that this works on output from a generic cli program. It mimics Linux ./foo | grep bar just like I wanted – Sint Oct 08 '14 at 12:12
  • Here's what I was looking for: Get-Command | out-string -stream | select-string Verbose Function Disable-DeliveryOptimizationVerboseLogs 1.0.2.0 DeliveryOptimization Function Enable-DeliveryOptimizationVerboseLogs 1.0.2.0 DeliveryOptimization Cmdlet Write-Verbose 7.0.0.0 Microsoft.PowerShell.Utility – zBernie Oct 11 '20 at 02:41
  • Thank god,, someone has a post. Powershell objects are really annoying to deal with coming from a Unix bg. – Adam D. Mar 07 '22 at 17:04
36

If you truly want to "grep" the formatted output (display strings) then go with Mike's approach. There are definitely times where this comes in handy. However if you want to try embracing PowerShell's object pipeline nature, then try this. First, check out the properties on the objects flowing down the pipeline:

PS> alias | Get-Member


   TypeName: System.Management.Automation.AliasInfo

Name                MemberType     Definition
----                ----------     ----------
Equals              Method         bool Equals(System.Object obj)
GetHashCode         Method         int GetHashCode()
GetType             Method         type GetType()
ToString            Method         string ToString()
<snip>
*Definition*        Property       System.String Definition {get;}
<snip>

Note the Definition property which is a header you see when you display the output of Get-Alias (alias) e.g.:

PS> alias

CommandType     Name           *Definition*
-----------     ----           ----------
Alias           %              ForEach-Object
<snip>

Usually the header title matches the property name but not always. That is where using Get-Member comes in handy. It shows you what you need to "script" against. Now if what you want to "grep" is the Definition property contents then consider this. Rather than just grepping that one property's value, you can instead filter each AliasInfo object in the pipepline by the contents of this property and you can use a regex to do it e.g.:

PS> alias | Where-Object {$_.Definition -match 'alias'}

CommandType     Name                   Definition
-----------     ----                   ----------
Alias           epal                   Export-Alias
Alias           gal                    Get-Alias
Alias           ipal                   Import-Alias
Alias           nal                    New-Alias
Alias           sal                    Set-Alias

In this example I use the Where-Object cmdlet to filter objects based on some arbitrary script. In this case, I filter by the Defintion property matched against the regex 'alias'. Only those objects that return true for that filter are allowed to propagate down the pipeline and get formatted for display on the host.

BTW if you're typing this, then you can use one of two aliases for Where-Object - 'Where' or '?'. For example:

PS> gal | ?{$_.Definition -match '-Item*'}
Keith Hill
  • 194,368
  • 42
  • 353
  • 369
  • 5
    You can also use `findstr` where PowerShell will handle conversion to text for you, since it's not a cmdlet but a program (just out of completeness; in general it's always better to filter according to properties, imho :-)) – Joey Sep 28 '09 at 21:03
  • FYI, as per Powershell 3, the following is more concise: `gal | Where Definition -match 'alias'` – tkokasih Apr 13 '14 at 10:33
  • I feel this answers to OP content, but not the title. If my command is (for example) "pip freeze" - the output is just text. Roi's answer is what the title of this appears to mean. – Danny Staple Aug 13 '17 at 15:36
16

There are two problems. As in the question, select-string needs to operate on the output string, which can be had from "out-string". Also, select-string doesn't operate linewise on strings that are piped to it. Here is a generic solution

(alias|out-string) -split "`n" | select-string Write 
Ian Kelling
  • 9,643
  • 9
  • 35
  • 39
  • 4
    In Powershell 1.0 there is no -split. You can do this instead: (alias|out-string -stream) | select-string Write – Mike Sep 28 '09 at 15:08
  • 1
    Aren't you all completely missing the point here? You don't need to grep powershell's output. – x0n Sep 06 '11 at 03:01
  • 3
    @x0n Well, there are cases in which when I'm quicly searching for something through PS console and I do not know and/or care if it's in particular property. I find it too tedious to use `Get-Member` and then use the correct property and expression in the `where` command. And `grep` is particularly good in this one. – OnesimusUnbound Feb 08 '12 at 12:32
  • 4
    The use of split is unnecessary. Just use the `-Stream` parameter on `Out-String` and then you can pipe directly to Select-String. – Keith Hill Sep 07 '12 at 23:03
5

The proposed solution is just to much work for something that can be done like this:

Get-Alias -Definition Write*
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
mjsr
  • 7,410
  • 18
  • 57
  • 83
2

Try this:

PS C:\> ipconfig /displaydns | Select-String -Pattern 'www.yahoo.com' -Context 0,7

>     www.yahoo.com
      ----------------------------------------
>     Record Name . . . . . : www.yahoo.com
      Record Type . . . . . : 5
      Time To Live  . . . . : 27
      Data Length . . . . . : 8
      Section . . . . . . . : Answer
      CNAME Record  . . . . : new-fp-shed.wg1.b.yahoo.com
  • The Pattern string is by default a regular expression. Among other optional parameters, `-CaseSensitive` might be useful since it is by default case-insensitive. – C Perkins Apr 12 '22 at 17:18
1
PS> alias | Where-Object {$_.Definition -match 'alias'}

CommandType     Name                   Definition
-----------     ----                   ----------
Alias           epal                   Export-Alias
Alias           gal                    Get-Alias
Alias           ipal                   Import-Alias
Alias           nal                    New-Alias
Alias           sal                    Set-Alias

what would be contradict of match in PS then as in to get field not matching a certain value in a column

Dilan
  • 2,610
  • 7
  • 23
  • 33
Kavya
  • 11
  • 2
0

For a more flexible and lazy solution, you could match all properties of the objects. Most of the time, this should get you the behavior you want, and you can always be more specific when it doesn't. Here's a grep function that works based on this principle:

Function Select-ObjectPropertyValues {
    param(
    [Parameter(Mandatory=$true,Position=0)]
    [String]
    $Pattern,
    [Parameter(ValueFromPipeline)]
    $input)

    $input | Where-Object {($_.PSObject.Properties | Where-Object {$_.Value -match $Pattern} | Measure-Object).count -gt 0} | Write-Output
}
Marty Gentillon
  • 127
  • 1
  • 3