PowerShell: Split-Path switches (-Leaf, -Parent, ...) do not work with -LiteralPath

Prerequisites

Steps to reproduce

Split-Path -Parent -LiteralPath $env:SystemRoot

Expected behavior

PS> Split-Path -Parent -LiteralPath $env:SystemRoot
C:\

Actual behavior

PS> Split-Path -Parent -LiteralPath $env:SystemRoot
Split-Path: Parameter set cannot be resolved using the specified named parameters. One or more parameters issued cannot be used together or an insufficient number of parameters were provided.

Error details

Exception             :
    Type              : System.Management.Automation.ParameterBindingException
    Message           : Parameter set cannot be resolved using the specified named parameters. One or more parameters issued
cannot be used together or an insufficient number of parameters were provided.
    ErrorId           : AmbiguousParameterSet
    Line              : 1
    Offset            : 1
    CommandInvocation :
        MyCommand        : Split-Path
        BoundParameters  :
            Comparer : System.OrdinalIgnoreCaseComparer
            Count    : 2
            Keys     :
                Length : 6

                Length : 11
            Values   :
                IsPresent : True

                Length      : 1
                LongLength  : 1
                Rank        : 1
                SyncRoot    :
                    Length : 10
                IsFixedSize : True
                Count       : 1
            SyncRoot :
                Comparer : System.OrdinalIgnoreCaseComparer
                Count    : 2
                Keys     :
                    Length : 6

                    Length : 11
                Values   :
                    IsPresent : True

                    Length      : 1
                    LongLength  : 1
                    Rank        : 1
                    SyncRoot    :
                        Length : 10
                    IsFixedSize : True
                    Count       : 1
                SyncRoot :
                    Comparer : System.OrdinalIgnoreCaseComparer
                    Count    : 2
                    Keys     :
                        Length : 6

                        Length : 11
                    Values   :
                        IsPresent : True

                        Length      : 1
                        LongLength  : 1
                        Rank        : 1
                        SyncRoot    :
                            Length : 10
                        IsFixedSize : True
                        Count       : 1
                    SyncRoot :
                        Comparer : System.OrdinalIgnoreCaseComparer
                        Count    : 2
                        Keys     :
                            Length : 6

                            Length : 11
                        Values   :
                            IsPresent : True

                            Length      : 1
                            LongLength  : 1
                            Rank        : 1
                            SyncRoot    :
                                Length : 10
                            IsFixedSize : True
                            Count       : 1
                        SyncRoot :
                            Comparer : System.OrdinalIgnoreCaseComparer
                            Count    : 2
                            Keys     :
                                Length : 6

                                Length : 11
                            Values   :
                                IsPresent : True

                                Length      : 1
                                LongLength  : 1
                                Rank        : 1
                                SyncRoot    :
                                    Length : 10
                                IsFixedSize : True
                                Count       : 1
                            SyncRoot :
                                Comparer : System.OrdinalIgnoreCaseComparer
                                Count    : 2
                                Keys     :
                                    Length : 6

                                    Length : 11
                                Values   :
                                    IsPresent : True

                                    Length      : 1
                                    LongLength  : 1
                                    Rank        : 1
                                    SyncRoot    : …
                                    IsFixedSize : True
                                    Count       : 1
                                SyncRoot :
                                    Comparer : System.OrdinalIgnoreCaseComparer
                                    Count    : 2
                                    Keys     : …
                                    Values   : …
                                    SyncRoot : …
        ScriptLineNumber : 1
        OffsetInLine     : 1
        HistoryId        : 8
        Line             : Split-Path -Parent -LiteralPath $env:SystemRoot
        Statement        : Split-Path -Parent -LiteralPath $env:SystemRoot
        PositionMessage  : At line:1 char:1
                           + Split-Path -Parent -LiteralPath $env:SystemRoot
                           + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        InvocationName   : Split-Path
        PipelineLength   : 1
        PipelinePosition : 1
    ErrorRecord       :
        Exception             :
            Type    : System.Management.Automation.ParentContainsErrorRecordException
            Message : Parameter set cannot be resolved using the specified named parameters. One or more parameters issued
cannot be used together or an insufficient number of parameters were provided.
            HResult : -2146233087
        CategoryInfo          : InvalidArgument: (:) [Split-Path], ParentContainsErrorRecordException
        FullyQualifiedErrorId : AmbiguousParameterSet,Microsoft.PowerShell.Commands.SplitPathCommand
        InvocationInfo        :
            MyCommand        : Split-Path
            ScriptLineNumber : 1
            OffsetInLine     : 1
            HistoryId        : 8
            Line             : Split-Path -Parent -LiteralPath $env:SystemRoot
            Statement        : Split-Path -Parent -LiteralPath $env:SystemRoot
            PositionMessage  : At line:1 char:1
                               + Split-Path -Parent -LiteralPath $env:SystemRoot
                               + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
            CommandOrigin    : Internal
        ScriptStackTrace      : at <ScriptBlock>, <No file>: line 1
    TargetSite        :
        Name          : ThrowAmbiguousParameterSetException
        DeclaringType : System.Management.Automation.CmdletParameterBinderController, System.Management.Automation,
Version=7.4.0.101, Culture=neutral, PublicKeyToken=31bf3856ad364e35
        MemberType    : Method
        Module        : System.Management.Automation.dll
    Data              : System.Collections.ListDictionaryInternal
    Source            : System.Management.Automation
    HResult           : -2146233087
    StackTrace        :
   at System.Management.Automation.CmdletParameterBinderController.ThrowAmbiguousParameterSetException(UInt32 parameterSetFlags,
MergedCommandParameterMetadata bindableParameters)
   at System.Management.Automation.CmdletParameterBinderController.ValidateParameterSets(Boolean prePipelineInput, Boolean
setDefault)
   at System.Management.Automation.CmdletParameterBinderController.BindCommandLineParametersNoValidation(Collection`1 arguments)
   at System.Management.Automation.CmdletParameterBinderController.BindCommandLineParameters(Collection`1 arguments)
   at System.Management.Automation.CommandProcessor.BindCommandLineParameters()
   at System.Management.Automation.CommandProcessor.Prepare(IDictionary psDefaultParameterValues)
   at System.Management.Automation.CommandProcessorBase.DoPrepare(IDictionary psDefaultParameterValues)
   at System.Management.Automation.Internal.PipelineProcessor.Start(Boolean incomingStream)
   at System.Management.Automation.Internal.PipelineProcessor.SynchronousExecuteEnumerate(Object input)
--- End of stack trace from previous location ---
   at System.Management.Automation.Internal.PipelineProcessor.SynchronousExecuteEnumerate(Object input)
   at System.Management.Automation.PipelineOps.InvokePipeline(Object input, Boolean ignoreInput, CommandParameterInternal[][]
pipeElements, CommandBaseAst[] pipeElementAsts, CommandRedirection[][] commandRedirections, FunctionContext funcContext)
   at System.Management.Automation.Interpreter.ActionCallInstruction`6.Run(InterpretedFrame frame)
   at System.Management.Automation.Interpreter.EnterTryCatchFinallyInstruction.Run(InterpretedFrame frame)
CategoryInfo          : InvalidArgument: (:) [Split-Path], ParameterBindingException
FullyQualifiedErrorId : AmbiguousParameterSet,Microsoft.PowerShell.Commands.SplitPathCommand
InvocationInfo        :
    MyCommand        : Split-Path
    ScriptLineNumber : 1
    OffsetInLine     : 1
    HistoryId        : 8
    Line             : Split-Path -Parent -LiteralPath $env:SystemRoot
    Statement        : Split-Path -Parent -LiteralPath $env:SystemRoot
    PositionMessage  : At line:1 char:1
                       + Split-Path -Parent -LiteralPath $env:SystemRoot
                       + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    CommandOrigin    : Internal
ScriptStackTrace      : at <ScriptBlock>, <No file>: line 1

Environment data

Name                           Value
----                           -----
PSVersion                      7.4.0-rc.1
PSEdition                      Core
GitCommitId                    7.4.0-rc.1
OS                             Microsoft Windows 10.0.25992
Platform                       Win32NT
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0…}
PSRemotingProtocolVersion      2.3
SerializationVersion           1.1.0.1
WSManStackVersion              3.0

Visuals

grafik

About this issue

  • Original URL
  • State: open
  • Created 7 months ago
  • Reactions: 1
  • Comments: 18 (6 by maintainers)

Most upvoted comments

Cmdlets should be intuitive to use. When there is no technical reason why a given parameter should not work in a specific parameterset, then adding it to the parameterset seems an easy fix. I‘ll take this issue to the cmdlet working group for discussion.

@PowerShell/wg-powershell-cmdlets reviewed this. -LiteralPath in all cases should work with the same set of parameters that -Path would accept (excluding some potential edge cases) as its intent is to allow an easier way to specify characters that shouldn’t be interpreted. The only concern is the complexity of untangling the parametersets to ensure no regression. However, we agreed that the other switches should work with -LiteralPath

Any bug can be considered “design” because it’s always technically coded to behave that way. But if it makes no sense, goes against expectations, there’s no good reason for the behavior and it likely wasn’t intended by the authors - then it becomes a bug.

@mklement0 you have contributed many fantastic issues and discussions to PowerShell, but I don’t think it’s necessary to convince @237dmitry of your opinion here, what matters is that we can (finally) get this fixed.

Also, for both of yous information, when you submit a bug to this repository it explicitly states you can also do that for unexpected behavior:

Screenshot_2023-11-18-11-40-23-232_org mozilla firefox-edit

So I think no matter how one defines “bug”, we’re good here.

If you’ve had a change of heart: great.

No, I had not change my position:

  • this is not a bug, the error is the result of incorrect user command line syntax
  • this is bad design, the user expects -lp, just like in other cmdlets
  • the cmdlet should be improved, as written by Dr. Tobias Weltner.

The answer to this question is irrelevant, as argued. By circular reasoning I was referring to the logic of your arguments, which can be distilled to: “Because it is that way, it must be meant to be that way, otherwise it wouldn’t be that way.”

A very strange answer. I expected to see your position not in relation to me, but on the essence of this issue

  • If there is design intent, they will tell us - you don’t know, and it is pointless to make yourself the defender of such speculative intent.
    • The syntax diagram in the docs are generated from the implementation, and contain nothing beyond that speaks to the intent that you speculate about.
  • Even if there is design intent: By all appearances, as argued, the cmdlet’s behavior doesn’t make sense (and is self-contradictory), so whether there was design intent is ultimately irrelevant - unless someone can come up with a good rationale for it; your circular reasoning does not constitute a rationale.
    • In the absence of a good rationale, the only other reason not to make a change would be the need to maintain backward compatibility, and that is not a concern here.

Good to know the technical reason for the bug, @237dmitry, but the point is that it is a bug: there is no conceivable reason not to allow the combination of -LiteralPath with either -Parent or -Leaf.

(As noted in the original issue (#8751), using -Path is a workaround, because Split-Path treats -Path and -LiteralPath arguments the same; also, for -Parent only, simply omitting it with -LiteralPath is an option, given that the -Parent functionality is the default one, e.g. Split-Path -LiteralPath $HOME)