Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Apply quoting for globbing * and ~ in splatting.#26232

Open
kzrnm wants to merge 6 commits into
PowerShell:masterPowerShell/PowerShell:masterfrom
kzrnm:globbingkzrnm/PowerShell:globbingCopy head branch name to clipboard
Open

Apply quoting for globbing * and ~ in splatting.#26232
kzrnm wants to merge 6 commits into
PowerShell:masterPowerShell/PowerShell:masterfrom
kzrnm:globbingkzrnm/PowerShell:globbingCopy head branch name to clipboard

Conversation

@kzrnm

@kzrnm kzrnm commented Oct 17, 2025

Copy link
Copy Markdown

PR Summary

Fix #24178

On Unix-like platforms.

/bin/echo @( '*' )

Note that using embedded quoting (e.g., @('"*"')) is not an option, because it becomes part of the argument.

Expected behavior

* should print verbatim.

Note:

* The above assumes that  `'*'` should _not_ be treated like a bareword in the context of splatting, which in turn implies that you fundamentally cannot specify barewords that way, and would have to use something like `@((Get-Item * -Name))` to manually perform the desired globbing.

* This strikes me as an acceptable trade-off and much preferable to the alternative: defaulting to interpretation as barewords, with a yet-to-be-devised opt-out method.

Actual behavior

The names of the files and subdirectories in the current directory print, because native globbing was applied.

According to the comment added in #5188:

Supporting this scenario would require adding a NoteProperty to each quoted string argument - maybe not worth it, and maybe an argument for another way to suppress globbing.

https://github.com/kzrnm/PowerShell/blob/26bb188c8be0cda6cb548ce1a12840ebf67e1331/test/powershell/Language/Scripting/NativeExecution/NativeUnixGlobbing.Tests.ps1#L84-L88

However, I disagree with this comment. As noted in #24178, there are cases where one wants to use splatting without enabling globbing. Therefore, I believe implementing this via a NoteProperty would be worth it.

Additional considerations

When using an expression other than a string literal, such as /bin/echo "a*a".Replace("a",""), globbing is performed. This behavior is unintuitive, so I think it’s worth considering a breaking change to make it not perform globbing along with the above modification.

PR Context

PR Checklist

@microsoft-github-policy-service microsoft-github-policy-service Bot added the Review - Needed The PR is being reviewed label Oct 25, 2025
@jshigetomi jshigetomi requested a review from a team as a code owner January 19, 2026 16:26
@jshigetomi

Copy link
Copy Markdown
Collaborator

@kzrnm Could you look at the test failures? I tried to resolve a conflict but could have botched it.

@kzrnm

kzrnm commented Mar 25, 2026

Copy link
Copy Markdown
Author

@jshigetomi I’ve managed to find some time, so I’ll start looking into this now.

Copilot AI review requested due to automatic review settings May 22, 2026 15:01

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

This PR enhances native argument handling by preserving string quoting metadata through compilation/runtime so native features (tilde expansion and UNIX globbing) behave correctly across direct invocation and splatting scenarios.

Changes:

  • Expanded Pester test coverage for tilde expansion and UNIX globbing, including quoted and splatted inputs.
  • Added runtime/compiler support to wrap string arguments with their StringConstantType so quoting intent is preserved.
  • Updated native parameter binding to read the preserved StringConstantType from wrapped string arguments.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
test/powershell/Language/Scripting/NativeExecution/NativeWindowsTildeExpansion.Tests.ps1 Reworks tilde-expansion tests into table-driven coverage for direct, quoted, and splatted cases.
test/powershell/Language/Scripting/NativeExecution/NativeUnixGlobbing.Tests.ps1 Adds/reenables tests for quoted + splatted behavior and aligns expectations via testexe -echoargs.
src/System.Management.Automation/engine/runtime/ScriptBlockToPowerShell.cs Wraps constant/expandable string arguments with StringConstantType metadata during AST->PowerShell conversion.
src/System.Management.Automation/engine/parser/Compiler.cs Emits wrapped string constants and wraps expandable strings during compilation via cached reflection.
src/System.Management.Automation/engine/lang/parserutils.cs Adds ParserOps.WrappedString helper to attach StringConstantType metadata to strings.
src/System.Management.Automation/engine/NativeCommandParameterBinder.cs Consumes wrapped string metadata to determine usedQuotes, and unwraps to the base string for native binding.

internal static class ParserOps
{
internal const string MethodNotFoundErrorId = "MethodNotFound";
internal const string StringConstantType = "StringConstantType";
Comment on lines +294 to +299
internal static PSObject WrappedString(string text, StringConstantType stringConstantType)
{
var wrapped = new PSObject(text);
wrapped.Properties.Add(new PSNoteProperty(StringConstantType, stringConstantType), true);
return wrapped;
}
Comment on lines +841 to +845
if (ast is ExpandableStringExpressionAst expandableStringExpressionAst)
{
Debug.Assert(argument is string);
argument = ParserOps.WrappedString(argument as string, expandableStringExpressionAst.StringConstantType);
}
Comment on lines +102 to 107
bool usedQuotes;
if (argValue is PSObject { BaseObject: string baseString } psObject && psObject.Properties[ParserOps.StringConstantType]?.Value is StringConstantType stp)
{
case StringConstantExpressionAst sce:
usedQuotes = sce.StringConstantType != StringConstantType.BareWord;
break;
case ExpandableStringExpressionAst ese:
usedQuotes = ese.StringConstantType != StringConstantType.BareWord;
break;
case ArrayLiteralAst ala:
arrayLiteralAst = ala;
break;
usedQuotes = stp != StringConstantType.BareWord;
argValue = baseString;
}
@jshigetomi jshigetomi added the CL-Engine Indicates that a PR should be marked as an engine change in the Change Log label Jun 15, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CL-Engine Indicates that a PR should be marked as an engine change in the Change Log Review - Needed The PR is being reviewed

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Unix: Native globbing cannot be bypassed when using splatting

3 participants

Morty Proxy This is a proxified and sanitized view of the page, visit original site.