I have the following script to find files containing a certain string and then report on the location of the file along with the size in bytes.

It works, but I seem to have made heavy weather of finding the string which involves a fair bit of tidying up afterwards to produce some clean output.

Any idea how I could make this more concise?

# Ignore errors
$ErrorActionPreference= 'silentlycontinue'

# Grab user options
$ext = Read-Host -Prompt        "Enter extension   "
$huntString = Read-Host -Prompt "Enter hunt string "

# Find text files (.log, .txt etc) containing the hunt string
$entries = gci -recurse -include *.$ext -ErrorAction SilentlyContinue | select fullname, length | sort -property length

echo ''
foreach ($e in $entries)
    # Find files containing the hunt string
    $foundFile = (gci $e.fullname | select-string $huntString | measure-object | findstr Count)

    # Output hit count along with size and name
    $rawOutput = $foundFile.ToString() + $e.Length.ToString().PadRight(10,[char]32) + "`t" + $e.fullname

    # Only output entries with a hit count
    $cleanOutput = echo $rawOutput | select-string ": 1"

    # Remove hit count
    $finalOutput = $cleanOutput -replace "Count","" -replace ": ",""

    # Trim and output
    echo $finalOutput.TrimStart()

1 Answer 1


Using findstr in PowerShell is superfluous and
not very powershell'ish which is about objects and pipes.

You can directly pipe the raw output of Get-ChildItem to Select-String and parse the resulting object for the information you require.

As the size of the file isn't contained in the properties sls returns:

Context      Property
Filename     Property
IgnoreCase   Property
Line         Property
LineNumber   Property
Matches      Property
Path         Property
Pattern      Property

You've to append it, either with a calculated property

# Grab user options
$ext = Read-Host -Prompt        "Enter extension   "
$huntString = Read-Host -Prompt "Enter hunt string "

Get-ChildItem *.$ext -Recurse | Select-String $huntString -List | 
    Select-Object @{Label='Size';Expression={(Get-Item $_.Path).Length}},Path

or iterate the output and build a [PSCustomObject]:

Get-ChildItem *.$ext -Recurse | Select-String $huntString -List | 
    ForEach-Object {
            Path = $_.Path
            Size = (Get-Item $_.path).Length

The objectsoutput will be the very same:

> Q:\Test\2018\12\17\CR_209811.ps1
Enter extension   : ps1
Enter hunt string : ::Now
Size Path
---- ----
 878 Q:\Test\2018\09\18\SO_52381514.ps1
 677 Q:\Test\2018\11\16\SO_53336923.ps1
 770 Q:\Test\2018\11\19\SO_53381881.ps1
1141 Q:\Test\2018\12\17\CR_209811.ps1
1259 Q:\Test\2018\12\17\SU_1385185.ps1
  • 1
    \$\begingroup\$ @RobbieDee Sorry for the missing closing brackets, Label or Name are both valid for calculated properties \$\endgroup\$
    – LotPings
    Dec 18, 2018 at 13:12

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.