Search code examples
powershellselect-stringselect-object

PowerShell code returning more values than expected


Good evening. Stack Overflow and Powershell novice here.

The below piece of code in Powershell is returning more values than I wanted. For example, it is capturing variables in a JSON file that match PPVCOUNT but also variables named with characters before and after the PPVCount string. Example:

PPVCountAtInception

OperatorCountGreaterThanPPVCountIndicator

GOAL: My goal is to have the code only return the variable PPVCount. I also want to keep the columns: Pattern, LineNumber, Line. Forgive me for my lack of knowledge and thank you in advance

$file = 'C:\\Users\\B187515\\Downloads\\j.json'
$PPVCount="PPVCount"

Get-Content $file | Select-String -Pattern $PPVCount -Context 1| Select-Object Pattern,LineNumber, Line -ExpandProperty Context -First 18 | Format-Table | Out-file -FilePath 'C:\\Users\\B187515\\Downloads\\test.csv' -Append

Expected results:

My goal is to have the code only return the variable "PPVCount" in the CSV file. I also want to keep the columns: Pattern, LineNumber, Line

Actual results There are multiple variables returning contain "PPVCount" somewhere in the variable name. See screenshot of CSV enter image description here


Solution

  • Building on the helpful comments:

    # Note: Just use '\' - no need for '\\'
    $file = 'C:\Users\B187515\\Downloads\j.json'
    
    # Enclose the property name to search for in embedded "..."
    $searchRegex ='"PPVCount"'
    
    # Pass $file (the file to search through) directly to Select-String, 
    # and use Export-Csv to export the results to a CSV file.
    Select-String -LiteralPath $file -Pattern $searchRegex -Context 1 | 
      Select-Object Pattern, LineNumber, Line -ExpandProperty Context -First 18 | 
      Export-Csv -LiteralPath 'C:\Users\B187515\Downloads\test.csv'
    
    • Your intent is to look for string PPVCount as a separate word; since you seem to be looking for this string as a JSON property name, you can assume that it is enclosed in embedded "..." and can therefore make it part of the search string.

      • Since this amounts to a literal search, you can add the -SimpleMatch switch, which likely improves performance.

      • Generally, to look for a token consisting only of letters, numbers, or _ as a separate word, you can use word-boundary assertions aka anchor (which is a regex feature and therefore requires you not to use -SimpleMatch), so the alternative in your case would be to use $searchRegex ='\bPPVCount\b'

    • Since your intent is to create a CSV file, use Export-Csv to create it.

      • As for what you used: Both Format-Table and Out-File create representations of data for the human observer, which is why you should never use them to print data for programmatic processing - see this answer for more information.

      • Character-encoding caveat: In Windows PowerShell (versions up to v5.1), Export-Csv inexplicably defaults to ASCII(!) encoding; whereas in PowerShell (Core) 7 it is commendably BOM-less UTF-8. Use an -Encoding argument as needed, but note that -Encoding utf8 invariably creates a UTF-8 file with a BOM in Windows PowerShell.

    • A couple of asides:

      • While benign in file paths, there's no reason to use \\ instead of \ in PowerShell. \ is not the escape char. in PowerShell, ` is - see the about_Special_Characters help topic.

      • The above passes the path of the file to search through directly to Select-String, via its -LiteralPath parameter. This is much more efficient than piping the lines of the file one by one to it via Get-Content, and is required if you want to see line numbers alongside the matching lines in the default display output.