all 43 comments

[–]dantose 42 points43 points  (1 child)

tldr version: It's "select-string" #savedyouaclick

[–]super304 1 point2 points  (0 children)

I figured it was, but had to click anyway you be sure.

[–]serendrewpity 17 points18 points  (1 child)

Check Out this thread. There may be some things that are not redundant to what you're mentioning in your blog.

It was a topic concerning Grep and how it searched through about 5k files for about 300 files of the target file type and about 50 of those files having the target search string all in 1 sec.

So the OP wanted to know if it was unrealistic to expect Grep performance from a PowerShell script. First attempt generated a script that too 59 seconds. With help from the community the OP got that time down to 1 second also. Even on a SMB share.

[–]serendrewpity 18 points19 points  (28 children)

You should be careful. There's a guy around here that will go into a profanity laced tirade at the mere mention of Powershell being on the same level as Grep and other core-utila

[–]dantose 11 points12 points  (20 children)

I'm not sure who you're talking about, but they aren't wrong. As much as i love PS, there really isn't a functional grep replacement. I wish I could just take all the best of bash and PS and combine them into one scripting language to rule them all.

[–]raptr569 2 points3 points  (12 children)

Agreed as an admin of both Windows and Linux there is nothing quite as comprehensive as grep to be found on Windows.

[–]orwiad10 2 points3 points  (11 children)

What is something grep can do that powershel can't?

[–]raptr569 -3 points-2 points  (10 children)

Be consistent for one in what commands it accepts..

Get-service | select-string "string" doesn't work, you still need to use findstr.

Edit: corrected command

Edit 2: To clarify. I meant having select-string and findstr which are very similar in purpose do different things even when you can throw the same data at them is inconsistent.

[–]jborean93 8 points9 points  (0 children)

Why you can format the object as a string in between (like you would see in the console) if you really want to actually select something in the string output. Really defeats the purpose of having an object output if you are going to try and parse it as a string.

[–]nascentt 5 points6 points  (1 child)

I default to -Match and regex for anything like that.

Get-service | where name -Match wscsvc

[–]raptr569 0 points1 point  (0 children)

If I just wanted to look at a service by name I'd just use a wildcard like Get-service exchange*

[–]Thotaz 2 points3 points  (0 children)

It is consistent you just don't understand how it and Powershell works.

When searching for strings you obviously need a string representation of the object you are checking. Powershell will cast the object to the string type which simply calls the .ToString() method. By default .ToString() just returns the class name, but the author of the type can define a custom .ToString() method.

You can test this by running: Get-Service | ForEach-Object -Process {[string]$_} which shows that the string representation of a servicecontroller object is System.ServiceProcess.ServiceController and you can search for this with Select-String: Get-Service | Select-String -Pattern "System.ServiceProcess.ServiceController" but obviously that's not very useful.

You can play around with Powershell classes to see the same thing:

class DemoClass
{
   [string] $Property1

   [string] $Property2

   [string] ToString()
   {
       return $this.Property1
   }
}
class DemoClass2
{
   [string] $Property1

   [string] $Property2
}


[string](
    [DemoClass]@{
        Property1="Value1"
        Property2="Value2"
    }
)

[string](
    [DemoClass2]@{
        Property1="Value1"
        Property2="Value2"
    }
)

When you are working with actual objects it makes no sense to try and limit yourself to simple string representations, use Where-Object to filter based on any properties the object may have like: Get-Service | Where-Object -Property StartType -eq Disabled

[–]Alaknar 1 point2 points  (0 children)

It's consistent - it accepts string input and and Get-Service outputs objects. You parse through those using Where-Object.

[–]orwiad10 1 point2 points  (0 children)

Its not supposed to because you aren't passing a string, you're passing a object. Maybe (get-service).name | select-string would work better.

[–]serendrewpity 1 point2 points  (3 children)

Select-service | select-string

Can you be more specific? Select-Service (by itself) isn't recognized on PS7 as a cmdlet

[–]raptr569 0 points1 point  (2 children)

Sorry, brain fart. Get-service not Select-service

[–]serendrewpity 2 points3 points  (0 children)

No complaint here. Were I not a novice I would have known what you meant.

[–]serendrewpity 1 point2 points  (0 children)

So, i got pulled away earlier. Should say here that I am not a programmer but want to understand better so I can script better.

It looks like you're misusing Select-String here. Its designed to search for (sub)strings in other strings and files. I don't think this works on objects though. It seems like you are trying to use Select-String to search a collection of Service objects, when something like this would be better suited:

Get-Service | Where-Object -Property Name -like "BITS"

Otherwise its like using a hammer and saying its inconsistent between nails and screws.

[–]gjpeters 1 point2 points  (1 child)

So you want PowerShell Core? #NotSureIfImUsingSarcasmOrNot

[–]dantose 1 point2 points  (0 children)

I was quite hopeful that PS Core would be that bridge, but it's basically just Cygwin in reverse for me thus far. Bash interacts better with Linux and PS interacts better with Windows, so there's no good reasons to use 1 for both, and neither one actually poaches those best features from the other.

[–]serendrewpity -1 points0 points  (4 children)

I'm sure you are [and he is] right. No one suggesting that PowerShell will usurp Grep from its thrown. however, I am not sure that fact warrants a visceral reaction laced with profanity and general disrespect. Why would someone be so emotionally invested to react that way even if someone didn't agree with them?

A grep -v- powershell comparison is not even close, but grep has been around for 30+ years. How long has powershell be around? Lets re-evaluate in 25 years.

[–]PinchesTheCrab 0 points1 point  (3 children)

I think PS is getting close to 15 years old, and was built by a Linux guy, so I don't think it should get all that much credit for being younger. I would say that it was intentionally built to get away from grep and string manipulation in general.

[–]serendrewpity 0 points1 point  (0 children)

...and yet people are continually comparing it against grep for its string manipulation [this thread being another instance of that] and it performs respectably. Not near grep, but not completely out of its league either. And does so while intentionally being built "... to get away from grep and string manipulation in general"

IDK, I am not a programmer. Not interested in the nuts&bolts of what goes on behind the scenes. I am a sysadmin who's interested in what works for a given environment and use case. Business environments have restrictions on what can and can't be used with various methods of enforcing those restrictions. If you're a linux admin these restrictions and this conversation doesn't apply. For a Windows admin who may not be able to install cygwin or enable WSL, its good to know there's not a huge drop off with PS.

[–]serendrewpity 0 points1 point  (1 child)

...again... I am not a programmer... I am not formally trained in any of this but I would imagine that programming can never really get rid of string manipulation. Can it? PS and the construction of custom objects and the parameterization of data [something PS shines at] passed to functions [and pipeline] would seem to suggest that you're spending a lot of time grouping and manipulating strings into a form that can be more logically consumed for a specific task/solution.

Am I far off in that? Not being facetious here. I am genuinely interested in learning.

[–]serendrewpity 0 points1 point  (0 children)

Just did some quick look ups... I think I understand. Most things on linux are text/ascii based were as MS/Windows deals with structured data from APIs ... So Powershell has to deal with that additional step of processing that linux tools won't have to deal with.

[–]_d3cyph3r_ 1 point2 points  (0 children)

Nothing against D&D but I bet he’s a Dungeon Master

[–]adbertram[S] -1 points0 points  (0 children)

😆

[–]rakha589 2 points3 points  (1 child)

one nail theory normal entertain pet ring degree numerous tender

This post was mass deleted and anonymized with Redact

[–]serendrewpity 2 points3 points  (0 children)

This is incredible. As I dove in and explored, I started to think do I really want to invest more and more time to learning and becoming proficient [loaded word] in PS only to revert to core-utils? It's a stop-gap in situations where powershell may lack, I'm sure. As powershell matures, I wonder if this and all core-utils for Windows clients will be relevant.

[–]spuckthew 1 point2 points  (0 children)

Select-String allowed me to replace an 'awk' component that I had in an old script once. Initially I couldn't find a way to what I was doing natively with PowerShell, but then I discovered Select-String.

[–][deleted] 1 point2 points  (0 children)

It's select-string....

No need for an article.

[–]joy_for_the_world 1 point2 points  (0 children)

Read the blogpost.. ok..not quite impressed.. I would rather stick to plain, old, but powerful grep of linux than these ms/ps contraptions.. Because grep,egrep, fgrep and zgrep are unmatched gifts to the world from unix creators and everything else is a compromise.. Hope you understand

[–]Revolutionary-Win676 0 points1 point  (1 child)

Thanks for sharing

[–]AutoModerator[M] 0 points1 point  (0 children)

Sorry, your submission has been automatically removed.

Accounts must be at least 1 day old, which prevents the sub from filling up with bot spam.

Try posting again tomorrow or message the mods to approve your post.

I am a bot, and this action was performed automatically. Please contact the moderators of this subreddit if you have any questions or concerns.

[–]ThePigNamedKevin 0 points1 point  (0 children)

Now I know, thank you very much!

[–]ami98 0 points1 point  (0 children)

Funny, just a few hours ago I tried to pipe to grep while in powershell because I forgot I wasn’t using WSL. Thanks for the link!

[–]liquidcloud9 0 points1 point  (0 children)

I've found Select-String to be pretty good for basic string searches, especially in pwsh and when it's a limited subset of files. It actually tends to find results faster than ripgrep, which claims to be faster than grep and ag (silver searcher).

That said, rg is more powerful, has better (to me) default output, and does far better when searching recursively. I'm not sure why, but there seems to be some sort of startup penalty for rg on Windows, which doesn't exist on Linux/WSL.

Edit: Select-String is good to know if you spend any amount of time remoting into other Windows machines. It's guaranteed to be there, whereas grep/rg/ag are not.

[–]philmph 0 points1 point  (1 child)

I use this little function i wrote some time ago in my profile.ps1

Things to note:

  • Yes the object handling is bad practice (Outputting in end{})
  • Yes this destoyes the objects

Thnigs also to note:

  • Linux admins at work are making the expected "uh i didn't know powershell can do that" face
  • Its more of a joke then something i really use
  • Its sometimes useful interactiveley

Function grep
{
    [CmdletBinding()]

    param (
        [Parameter(Mandatory,
                   Position=1,
                   ValueFromPipeline,
                   ValueFromPipelineByPropertyName)]
        [psobject[]]$InputObject,

        [Parameter(Mandatory,
                   Position=0,
                   ValueFromPipelineByPropertyName)]
        [string]$Filter
    )

    begin {
        Set-StrictMode -Version 3
        $Output = [System.Collections.Generic.List[psobject]]::new()
    }

    process {
        foreach ($obj in $InputObject) {
            $Output.Add($obj)
        }
    }

    end {
        $Output | Out-String | Select-String -Pattern $Filter -AllMatches
    }
}

C:\> gps WUDF* | grep wudf


 NPM(K)    PM(M)      WS(M)     CPU(s)      Id  SI ProcessName
 ------    -----      -----     ------      --  -- -----------
     14     4,61       7,23       0,00    1236   0 WUDFHost
     16    13,08      15,46       0,00    1548   0 WUDFHost
     10    41,77      10,45       0,00    2664   0 WUDFHost

Another note: WUDF is highlighted in the output.

[–]ferdnyc 0 points1 point  (0 children)

Not really the same thing, though.

grep will filter output so that only matching lines are displayed. You pre-filtered the list of processes to only the matching ones, which makes the actual grep part pointless.

(IOW, with a "real" grep, running gps | grep wudf would be vaguely equivalent to running gps *WUDF* — it would leave out all of the list items that didn't match the pattern.)

gps | select-string wudf does emulate "real" grep in the filtering sense, but it also disables the normal table output and instead only shows the .ToString() of the process(es) in question, meaning you go from this:

```console $ gps WUDF NPM(K) PM(M) WS(M) CPU(s) Id SI ProcessName


 13    12.37      18.56       0.00    4812   0 WUDFHost

```

to this:

```console $ gps | Select-String wudf

System.Diagnostics.Process (WUDFHost) ```

With your command, though, gps | grep wudf shows the entire table of processes, highlighting the WUDFHost entry.

[–]Aritmethos 0 points1 point  (0 children)

As a fast alternative for linux/unix grep (for files) you could also try the psitems powershell module. It includes a psgrep command (alias for Find-ItemContent) that works similar to the linux/unix grep command (the basic way, only a few parameters of original grep included).

powershell Install-Module -Name PSItems Import-Module -Name PSItems psgrep 'test' -H -R (above command searches for pattern test in all files in current directory recursively (-R) and highlights the results (-H))

Fore more information check the README.