0

I spent quite some time searching for the solution of my problem, but found nothing. I have one single folder with mostly .html files, and I frequently need to search to find the files that contain certain strings. I need the search result to be displayed with just the file name (as the file will only be in that one folder) and file's last write time. The list needs to be sorted by the last write time. This code works perfectly for finding the correct files

Get-ChildItem -Filter *.html -Recurse | Select-String -pattern "keyWord string" | group path | select name

The problem with it is that it displays the entire path of the file (which is not needed), it does not show the last write time, and it is not sorted by the last write time.

I also have this code

Get-ChildItem -Attributes !Directory *.html | Sort-Object -Descending -Property LastWriteTime | Select-Object Name, LastWriteTime

That code prints everything exactly as I want to see it, but it prints all the file names from the folder instead of printing only the files that I need to find with a specific string in them.

Ken White
  • 123,280
  • 14
  • 225
  • 444
ChrisN
  • 3
  • 1
  • you could select `fullname` & `name` in your 1st code block, use the `fullname` to get the `lastwritetime`, and then build a `[PSCustomObject]` with the desired properties. – Lee_Dailey May 01 '22 at 01:08

2 Answers2

1

Since you are only using Select-String to determine if the text exists in any of the files move it inside a Where-Object filter and use the -Quiet parameter so that it returns true or false. Then sort and select the properties you want.

Get-ChildItem -Filter *.html | 
    Where-Object { $_ | Select-String -Pattern 'keyWord string' -Quiet } | 
        Sort-Object LastWriteTime | 
            Select-Object Name, LastWriteTime

For multiple patterns one way you can do it is like this

Get-ChildItem -Filter *.html |
    Where-Object {
        ($_ | Select-String -Pattern 'keyWord string' -Quiet) -and
        ($_ | Select-String -Pattern 'keyWord string #2' -Quiet)
    } |
        Sort-Object LastWriteTime |
            Select-Object Name, LastWriteTime

And another way using Select-String with multiple patterns which may be a bit faster

$patterns = 'keyword 1', 'keyword 2', 'keyword 3'
Get-ChildItem -Filter *.html |
    Where-Object {
        ($_ | Select-String -Pattern $patterns | Select-Object -Unique Pattern ).Count -eq $patterns.Count
    } |
        Sort-Object LastWriteTime |
            Select-Object Name, LastWriteTime
Daniel
  • 4,792
  • 2
  • 7
  • 20
  • This is great! Thank you very much! One other thing just came to my mind: how do I search for 2 or more strings as of "and" rather than "or"? When I add another keyword separated by a comma, I get the "or" result. TIA – ChrisN May 01 '22 at 14:27
  • You're welcome @ChrisN. Check updated answer for multiple patterns. There may be faster ways, but this was the fastest to implement with minimal change to the code. – Daniel May 01 '22 at 19:14
  • Daniel, thank you again for your great solutions! I wanted to ask about the last block of code: I think, I can't run it just by pasting it into PowerShell window, I have to run it from a saved .ps1 file, right? I tried that and my OS blocks it from running. Is there a way to run it by just pasting it? – ChrisN May 02 '22 at 01:40
  • You should be able to run it just by pasting directly in a PowerShell console. The console will take multi-line code via pasting. – Daniel May 02 '22 at 03:18
0

If you don't care about it being a bit redundant, you can Get-ChildItem the results after your searching:

Get-ChildItem -Filter *.html -Attributes !Directory -Recurse | Select-String -Pattern "keyWord string" | group path | foreach {Get-ChildItem $_.Name } |  Sort-Object -Descending LastWriteTime | Select Name,LastWriteTime

After you Select-String you get the attributes of that object instead of the original, so we're taking the results of that object and passing it back into the Get-ChildItem command to retrieve those attributes instead.

Guy S
  • 457
  • 4
  • 9