Why does PowerShell's `Get-ChildItem` command resolve the parameter `d` to `Depth`?

It's because the other parameters are dynamic parameters added at invocation, based on the path you're asking about.

  • -Directory is only valid when the Path is in the FileSystem provider
  • -DnsName and -DocumentEncryptionCert are only valid in the Certificate provider

It's the same with -re being -Recurse instead of being ambiguous with -ReadOnly ...

It's also the same with -e being -Exclude instead of -Eku or -ExpiriringInDays ...

And you'll notice that if you run Get-ChildItem -f and it tells you f is ambiguous, the only options that it suggests are -Filter and -Force, not -File or -FollowSymlink which are exclusive to the FileSystem provider...


You can see all of that using Get-Parameter which you can get from the PowerShell gallery by Install-Script Get-Parameter


I eventually found a way to show by experimentation that the non-dynamic parameters will always get resolved first, and the parameter binder never even looks at the dynamic parameters for anything it can bind without them. Therefore, the parameter selector doesn't even know what the names or aliases of the dynamic parameters are unless it can't find a match on the non-dynamic parameters. So that d alias is just causing confusion, unless it's being generated in such a way that it also shows up on other commands...

Try this:

using namespace System.Management.Automation
function Test-Alias {
    [CmdletBinding()]
    param(
        [switch]$Awful
    )

    dynamicparam {
        $paramDictionary = [RuntimeDefinedParameterDictionary]::new()
        $attribs = [System.Collections.ObjectModel.Collection[System.Attribute]]::new()
        $attribs.Add([ParameterAttribute]@{ParameterSetName = "_AllParameterSets" })

        $paramdictionary.Add("Automation", [RuntimeDefinedParameter]::new( "Automation", [switch], $attribs))

        $attribs += [AliasAttribute]::new("A", "C")
        $paramdictionary.Add("Architecture", [RuntimeDefinedParameter]::new( "Architecture", [switch], $attribs))
        $paramdictionary
    }
    end {
        $PSBoundParameters
    }
}

If you run that in your console, you'll not only be able to see that Test-Alias -A uses Awful but also that Test-Alias -C does work! The A alias never had a chance, but it's not because aliases on dynamic parameters are ignored completely, it's because there was a parameter that started with that letter which was not dynamic.

Now try this:

Trace-Command -Name ParameterBinding { Test-Alias -A } -PSHost

A screenshot of my output, for the lazy

And compare that to the output when you use Test-Alias -C or Test-Alias -A -C ...

You can see that the Dynamic parameters are only considered after everything non-dynamic that can be bound has been.

Tags:

Powershell