Fix hyphen-prefixed arguments being split at period#26522
Fix hyphen-prefixed arguments being split at period#26522yotsuda wants to merge 2 commits intoPowerShell:masterfrom
Conversation
When passing arguments like -foo.bar or -foo=bar.baz, PowerShell incorrectly splits them at the first period. This fix modifies the tokenizer to treat such tokens as single arguments in command mode. Fixes PowerShell#6291
b179b78 to
6423fe1
Compare
There was a problem hiding this comment.
Pull request overview
This PR fixes a tokenizer bug where hyphen-prefixed arguments containing periods (e.g., -foo.bar, -DVERSION=1.2.3) were incorrectly split at the period character. The fix ensures such arguments are treated as single tokens in command mode, which is critical for passing compiler flags and other command-line arguments to native commands.
Key Changes
- Modified the
ScanParameter()method intokenizer.csto handle periods in command mode by treating the entire token as a generic argument rather than attempting to parse it as a parameter name - Added comprehensive test coverage with 25 test cases covering basic functionality, edge cases, real-world scenarios (compiler flags), splatting, native commands, and backward compatibility
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
| src/System.Management.Automation/engine/parser/tokenizer.cs | Moved period handling from the generic case statement to a dedicated case with command mode detection, mirroring the existing pattern used for quote characters |
| test/powershell/Language/Parser/Parser.Tests.ps1 | Added comprehensive test context "Hyphen-prefixed arguments should not be split at dot" with 25 test cases validating the fix and ensuring backward compatibility |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
This pull request has been automatically marked as Review Needed because it has been there has not been any activity for 7 days. |
PR Summary
Fix argument parsing for hyphen-prefixed tokens containing periods. Tokens like
-foo.barare now passed as a single argument instead of being incorrectly split into-fooand.bar.PR Context
Fixes #6291
Also partially addresses the splatting issue described in #6360 (closed due to inactivity, not because it was fixed).
Note: This PR fixes the period (
.) splitting issue in splatting, but does not fix the colon (:) splitting issue also mentioned in #6360. The colon case requires a different fix in NativeCommandParameterBinder.The Problem
When passing unquoted arguments that start with a hyphen and contain a period, PowerShell incorrectly splits them at the first period:
This behavior affects many real-world scenarios, particularly when calling external programs with flags like:
-DVERSION=1.2.3(compiler defines)-std=c++20(compiler standards)-fmodule-file=Hello=Hello.pcm(clang modules)--config=path/to.file(various CLI tools)Committee Decision
The PowerShell Committee reviewed this issue and confirmed it is a bug:
Before this fix:
After this fix:
Technical Approach
Root Cause
In
ScanParameter()method oftokenizer.cs, when the tokenizer encounters a hyphen at the start of a token, it begins scanning for a parameter name. When it encounters a period (.), it terminates the parameter scan and leaves the remaining text (.bar) as a separate token.This behavior was originally designed for expression mode where
.indicates member access (e.g.,$obj.Property). However, in command mode, this special treatment of.causes unintended argument splitting.Solution
Modified the
case '.'handling inScanParameter()to check if we're in command mode. When in command mode:-and everything after the.) is treated as a generic argumentScanGenericToken()which preserves it as a single unitThis approach mirrors the existing handling of quote characters (
',") in the same method, which already use the same pattern to treat quoted content as arguments rather than parameters.Backward Compatibility Analysis
Why This Change Is Safe
Parameter names cannot contain periods: PowerShell does not allow
.in parameter names. Any attempt to declareparam($foo.bar)results in a parse error.No intentional usage exists: Since
-foo.barcannot match any declared parameter, the current "split at period" behavior is purely accidental. No scripts intentionally rely on-foo.barbeing interpreted as-foowith value.bar.Consistent with user expectations: Users who write
-foo.barexpect it to be a single argument (typically for external programs).Colon syntax remains unchanged: The intentional
-param:valuesyntax continues to work as expected.Verified Backward Compatibility
The following scenarios were tested and continue to work correctly:
-foo bar)-foo:bar)-Verbose)$obj.foo)'hello'.ToUpper())-3.14)-3..-1)--foo.bar)Potential Concerns
WG-Engine's Comment
WG-Engine commented:
This PR applies the fix to all commands (not just native commands) because:
Tokenization happens before command resolution: At the tokenizer level, PowerShell doesn't know whether the target is a native command, cmdlet, or function.
No practical difference: Since parameter names cannot contain periods, the "split at period" behavior never provides useful functionality for PowerShell commands either.
Splatting consistency: The fix ensures that
$Argsand@Argscorrectly preserve arguments regardless of whether they're ultimately passed to native commands or PowerShell functions.Extensive testing: All backward compatibility scenarios have been verified with no regressions found.
The PowerShell team should evaluate whether this broader fix is acceptable or if a native-command-only approach is required.
PR Checklist
.h,.cpp,.cs,.ps1and.psm1files have the correct copyright headerTest Coverage
Added 25 comprehensive test cases covering:
Basic Cases
-foo.bar- single period-foo=bar.baz- equals sign with periodEdge Cases: Multiple and Consecutive Periods
-foo..bar- consecutive periods-foo...bar- three consecutive periods-foo.bar.baz- multiple periods-foo=1.2.3.4- IP-address-like patternEdge Cases: Leading and Trailing Periods
-.foo- leading period after hyphen-foo.- trailing periodDouble Hyphen
--foo.bar- GNU-style long option (already worked, included for completeness)Real-World Use Cases
-DVERSION=1.2.3- compiler define-std=c++20- compiler standard flagSplatting
@Argswith-foo.bar@Argswith-foo=bar.bazNative Commands
Backward Compatibility
-foo:bar)-Path .txt)Test Results
Files Changed
src/System.Management.Automation/engine/parser/tokenizer.cs- Modified period handling inScanParameter()test/powershell/Language/Parser/Parser.Tests.ps1- Added comprehensive test coverage