Fix Select-Object to support properties with literal wildcard characters when using escaped names.#26333
Conversation
…ers when using escaped names. This PR resolves two related GitHub issues: - **[PowerShell#25982: Select-Object cannot target properties that literally contain wildcard characters](PowerShell#25982 - **[PowerShell#17068: Select-Object -Property argument that is an escaped wildcard expression retains the escape characters in the resulting property name](PowerShell#17068 The fix enables both `-Property` and `-ExpandProperty` parameters to work correctly with escaped wildcard property names while also resolving the escape character retention bug in column headers.
There was a problem hiding this comment.
Pull Request Overview
This PR adds support for selecting and expanding properties with literal wildcard characters (like [], *, ?) using escaped property names via WildcardPattern.Escape() in the Select-Object cmdlet. This addresses GitHub issue #25982.
- Implements exact property matching for escaped wildcard patterns before falling back to wildcard resolution
- Adds comprehensive test coverage for various scenarios involving escaped wildcard characters
- Includes minor whitespace cleanup in existing tests
Reviewed Changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 7 comments.
| File | Description |
|---|---|
| src/Microsoft.PowerShell.Commands.Utility/commands/utility/Select-Object.cs | Adds TryGetExactPropertyMatch helper method and integrates exact-match logic into ProcessParameter and ProcessExpandParameter methods |
| test/powershell/Modules/Microsoft.PowerShell.Utility/Select-Object.Tests.ps1 | Adds 15 new test cases covering escaped wildcard scenarios, fixes whitespace issues, and adds regression tests for issue #25982 |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
|
||
| It "Select-Object with Skip and SkipLast should work with Skip overlapping SkipLast" { | ||
| $results = "1", "2" | Select-Object -Skip 2 -SkipLast 1 | ||
| $results. Count | Should -Be 0 |
There was a problem hiding this comment.
There's an erroneous space before 'Count' in '$results. Count'. This should be '$results.Count' without a space.
|
|
||
| It "Select-Object with Skip and SkipLast should work with skiplast overlapping skip" { | ||
| $results = "1", "2" | Select-Object -Skip 1 -SkipLast 2 | ||
| $results. Count | Should -Be 0 |
There was a problem hiding this comment.
There's an erroneous space before 'Count' in '$results. Count'. This should be '$results.Count' without a space.
| foreach (PSPropertyExpression resolvedName in ex.ResolveNames(inputObject)) | ||
| { | ||
| List<PSPropertyExpressionResult> tempExprResults = resolvedName.GetValues(inputObject); | ||
| if (tempExprResults == null) | ||
| if (_exclusionFilter == null || !_exclusionFilter.IsMatch(resolvedName)) | ||
| { | ||
| continue; | ||
| } | ||
| List<PSPropertyExpressionResult> tempExprResults = resolvedName.GetValues(inputObject); | ||
| if (tempExprResults == null) | ||
| { | ||
| continue; | ||
| } | ||
|
|
||
| foreach (PSPropertyExpressionResult mshExpRes in tempExprResults) | ||
| { | ||
| expressionResults.Add(mshExpRes); | ||
| foreach (PSPropertyExpressionResult mshExpRes in tempExprResults) | ||
| { | ||
| expressionResults.Add(mshExpRes); | ||
| } | ||
| } | ||
| } |
There was a problem hiding this comment.
This foreach loop implicitly filters its target sequence - consider filtering the sequence explicitly using '.Where(...)'.
| // If no exact match was found, fall back to wildcard resolution | ||
| if (!exactMatchFound) | ||
| { | ||
| foreach (PSPropertyExpression resolvedName in ex.ResolveNames(inputObject)) |
There was a problem hiding this comment.
| } | ||
| else | ||
| { | ||
| expressionResults = ex.GetValues(inputObject); |
There was a problem hiding this comment.
…ect-Object.cs Co-authored-by: Copilot <[email protected]>
Co-authored-by: Copilot <[email protected]>
|
This pull request has been automatically marked as Review Needed because it has been there has not been any activity for 7 days. |
|
@bhattumang7 please read the following Contributor License Agreement(CLA). If you agree with the CLA, please reply with the following information.
Contributor License AgreementContribution License AgreementThis Contribution License Agreement (“Agreement”) is agreed to by the party signing below (“You”),
|
|
(default - no company specified) I have sole ownership of intellectual property rights to my Submissions and I am not making Submissions in the course of work for my employer. |
PR Summary
Fix Select-Object to support properties with literal wildcard characters when using escaped names.
This PR resolves two related GitHub issues:
The fix enables both
-Propertyand-ExpandPropertyparameters to work correctly with escaped wildcard property names while also resolving the escape character retention bug in column headers.PR Context
Users frequently encounter objects with property names containing wildcard characters, especially when working with:
Previously, these properties were inaccessible via
Select-Objecteven when properly escaped, forcing users to use workarounds or direct property access. Additionally, when escaped wildcards were used, the escape characters were incorrectly retained in column headers.Before this fix:
After this fix:
PR Checklist
.h,.cpp,.cs,.ps1and.psm1files have the correct copyright headerSelect-Objectcannot target properties that literally contain wildcard characters #25982Technical Details
Root Cause Analysis
The original issue occurred because escaped wildcard expressions needed two-phase resolution:
Previously,
Select-Objectwould process escaped expressions throughPSPropertyExpression.ResolveNames(), but sinceHasWildCardCharactersreturnsfalsefor escaped expressions, no wildcard resolution occurred. This led to literal property lookups that failed because the actual property name wasFoo[], notFoo[].Implementation Approach
Core Algorithm
Added a new
TryGetExactPropertyMatchhelper method that:WildcardPattern.Unescape()Integration Points
Modified two key methods to use the new exact-match logic:
ProcessParameter- For-PropertyparameterProcessExpandProperty- For-ExpandPropertyparameterBoth methods now follow this pattern:
Performance Impact
Complexity Handled
*,?,[],[abc],[0-9])-ExpandPropertyparameterTest Coverage Added
Select-Objectcannot target properties that literally contain wildcard characters #25982 and Select-Object -Property argument that is an escaped wildcard expression retains the escape characters in the resulting property name #17068Files Modified
src/Microsoft.PowerShell.Commands.Utility/commands/utility/Select-Object.cstest/powershell/Modules/Microsoft.PowerShell.Utility/Select-Object.Tests.ps1Important Behavior Note: Duplicate Property Names
There's an important behavior to be aware of when using both wildcard patterns and escaped property names that resolve to the same property. This is expected behavior and consistent with how Select-Object works today.
Example:
This will produce a non-terminating error but continue processing:
Why this happens:
Foo*(wildcard) resolves to the actual propertyFoo[]([WildcardPattern]::Escape('Foo[]'))also resolves to the same propertyFoo[]This behavior is not new - it's longstanding Select-Object behavior that occurs whenever multiple expressions resolve to the same property name. Our fix doesn't change this rule; it just makes escaped names resolve properly so they can participate in this existing duplicate detection.
Validation Results
✅ Both issues resolved: #25982 property access works, #17068 headers fixed
✅ Performance validated: 0.092ms per operation, no measurable regression
✅ Backward compatibility: All 51 original tests pass, normal functionality unchanged
✅ Comprehensive testing: 15 new tests added, all 66 tests passing
✅ Production ready: No debug output, proper error handling, full documentation