-
Notifications
You must be signed in to change notification settings - Fork 8.2k
Make Select-String more intelligent for non-primitive types #10726
Description
Summary of the new feature/enhancement
As a user,
I want to be able to easily use Select-String to find string data in formatted output,
so that I can find and process data in PowerShell more quickly.
By default, when you pass non-string data into the Select-String cmdlet, it will find matches based on the object's ToString() method results. This is great when the ToString output actually represents the data you want to match, but very often ToString results do not represent the data that you see in PowerShell, and this can result in incorrect or failed matches.
For example, consider this script:
# First, capture the date:
$date = Get-Date
# Now, get the current month in string format:
$month = $date.ToString("MMMM")
# Now, look at how the date renders in PowerShell, showing the month as a string
$date
# Now, try to match the month using Select-String. This returns nothing.
Get-Date | Select-String -Pattern $monthThat script shows the current date, including the month in string format, but if you try to select that string based on the actual string month, there are no matches. Why does this happen? Because ToString() on DateTime objects returns the date time with a numeric month, not the string month.
Now let's look at a more realistic example:
# Get some services, including the Windows Update service, and filter output on the
# string "Update"
Get-Service wuauserv,bits | Select-String UpdateThat returns nothing. Why? Because the ToString method on service objects returns the name of service, so you can't filter output based on a partial match of a display name string this way.
Here is one more example:
Get-Process -Id $PID | Format-List * | Select-String MemoryThis also returns nothing, because of the ToString method on Format cmdlet output objects returns their type name, none of which match Memory.
It is reasonable for a user to expect to be able to easily and consistently parse/filter output that is rendered in the PowerShell console, but this is not possible unless they pipe to Out-String -Stream before they then pipe that streamed result to Select-String.
Proposed technical implementation details (optional)
[EDIT]: Updated to reflect the parameter name we decided to move forward in the discussion below.
I want to make Select-String better by adding a new -ConsoleOutput switch parameter (or some better parameter name: suggestions welcome)-FromFormattedOutput switch parameter that indicates that you want to select a string based on the console output of the data that is piped into Select-String, which would automatically take care of the formatting and output of non-value and non-string types (and non-MatchInfo, but that's a special case internally for Select-String), and select string matches based on that output rather than based on the ToString method output of individual objects.
Additional details
Personally I would prefer if Select-String worked this way by default for non-value and non-string types, but that would be a breaking change at this point, so that's not an option; however, users who want it to work this way by default can use $PSDefaultParameterValues['Select-String:FromFormattedOutput'] = $true, and that will have the same result.