Powershell: Ensure programmatic discoverability of parameters that support wildcard patterns

Created on 31 Aug 2017  路  8Comments  路  Source: PowerShell/PowerShell

Related: #4715.

Currently, compiled cmdlets apparently don't reflect in their parameter metadata which parameters support wildcard patterns.

By contrast, advanced functions that have [SupportsWildcards()]-decorated parameters already do, at least with Get-Command.

Two distinct fixes are required, it seems:

  • Consistently decorate parameters of compiled cmdlets that support wildcard patterns with the [SupportsWildcards()] attribute.

  • Make sure that the output from Get-Help -Parameter reflects that attribute.


Currently, whether a given compiled cmdlet's parameter supports wildcards must be gleaned from the _help description_.

# Get-Command:
# Attributes of the -Path parameter give no indication that wildcards are supported, 
# even though they are.
> Get-Command Get-Item | % Parameters | % Path | % Attributes


Position                        : 0
ParameterSetName                : Path
Mandatory                       : True
ValueFromPipeline               : True
ValueFromPipelineByPropertyName : True
ValueFromRemainingArguments     : False
HelpMessage                     : 
HelpMessageBaseName             : 
HelpMessageResourceId           : 
DontShow                        : False
TypeId                          : System.Management.Automation.ParameterAttribute


# Get-Help:
# The only way to discover wildcard support is via Get-Help, via the parameter *description*.
# Note that the attributes *contradict* the description:
> Get-Help Get-Item -Parameter Path

-Path <String[]>
    Specifies the path to an item. This cmdlet gets the item at the specified location.
    Wildcards are permitted.  # !! This is the ONLY indication that wildcards are supported.
    This parameter is required, but the parameter name ("Path") is optional.

    Use a dot (.) to specify the current location. Use the wildcard character (*) to specify all the items in the current location.

    Required?                    true
    Position?                    1
    Default value                none
    Accept pipeline input?       true (ByValue, ByPropertyName)
    Accept wildcard characters?  false    #  !! Contradicts the above.



By contrast, advanced functions at least allow programmatic discovery via Get-Command:

function foo { param([SupportsWildcards()] $Bar) $Bar }
Get-Command foo | % Parameters | % Bar | Select-Object Attributes

The above yields:

Key Attributes                                                                   
--- ----------                                                                   
    {__AllParameterSets, System.Management.Automation.SupportsWildcardsAttribute}

However, using Get-Help -Parameter still doesn't reflect the attribute:

> Get-Help foo -Parameter Bar

-Bar <Object>

    Required?                    false
    Position?                    0
    Accept pipeline input?       false
    Parameter set name           (All)
    Aliases                      None
    Dynamic?                     false

If you use comment-based help, however, the attribute _is_ reflected, although the output format changes significantly:

<#
.SYNOPSIS
  Short description
.DESCRIPTION
  Long description
.EXAMPLE
  Example of how to use this cmdlet
.EXAMPLE
  Another example of how to use this cmdlet
#>
function foo { param([SupportsWildcards()] $Bar) $Bar }

Note how wildcard support is now reflected [_update_: formerly, the output format would change in the presence of comment-based help, and the wildcard attribute was labeled "globbing"; this seems to be fixed as of at least PowerShell Core 7.1.0-preview.5]

> Get-Help foo -Parameter Bar

-Bar <Object>

    Required?                    false
    Position?                    1
    Default value                
    Accept pipeline input?       false
    Accept wildcard characters?  true

Environment

PowerShell Core v6.0.0-beta.7
Area-Cmdlets-Core Issue-Code Cleanup

Most helpful comment

Opened PR #13353 to fix functions not displaying if a parameter supports wildcards when no comment-based help is present. I had to add logic to add the globbing property if [SupportsWildcards] is present and update the ExtendedCmdletHelpInfo#parameter view to display the globbing property.

C:\> function foo { param($Bar) $Bar }
C:\> Get-Help foo -Parameter Bar

-Bar <Object>

    Required?                    false
    Position?                    0
    Accept pipeline input?       false
    Parameter set name           (All)
    Aliases                      None
    Dynamic?                     false
    Accept wildcard characters?  false



C:\> function foo { param([SupportsWildcards()] $Bar) $Bar }
C:\> Get-Help foo -Parameter Bar

-Bar <Object>

    Required?                    false
    Position?                    0
    Accept pipeline input?       false
    Parameter set name           (All)
    Aliases                      None
    Dynamic?                     false
    Accept wildcard characters?  true

All 8 comments

Help not showing it should be a separate issue

@SteveL-MSFT: In the documentation repo or here?

@mklement0 looks like platyPS has support for this, so it appears to simply be a doc issue. Thanks!

@joeyaiello / @SteveL-MSFT
I have been working on a project to clean up the documentation so that it properly reflects which paramters support wildcards. This is a list of the paramters that need to be marked with the [SupportsWildcards()] option. Can we get some cycles to address this problem?

Module | Cmdlet | Parameter
-- | -- | --
CimCmdlets | Get-CimClass | ClassName
CimCmdlets | Get-CimClass | MethodName
CimCmdlets | Get-CimClass | QualifierName
CimCmdlets | Get-CimSession | Name
CimCmdlets | Remove-CimSession | Name
Microsoft.PowerShell.Archive | Compress-Archive | Path
Microsoft.PowerShell.Core | Clear-History | CommandLine
Microsoft.PowerShell.Core | Disable-PSSessionConfiguration | Name
Microsoft.PowerShell.Core | Disconnect-PSSession | Name
Microsoft.PowerShell.Core | Enable-PSSessionConfiguration | Name
Microsoft.PowerShell.Core | Export-ModuleMember | Alias
Microsoft.PowerShell.Core | Export-ModuleMember | Cmdlet
Microsoft.PowerShell.Core | Export-ModuleMember | Function
Microsoft.PowerShell.Core | Export-ModuleMember | Variable
Microsoft.PowerShell.Core | ForEach-Object | MemberName
Microsoft.PowerShell.Core | Get-Verb | Verb
Microsoft.PowerShell.Core | Get-Command | Name
Microsoft.PowerShell.Core | Get-Command | Noun
Microsoft.PowerShell.Core | Get-Command | ParameterName
Microsoft.PowerShell.Core | Get-Command | ParameterType
Microsoft.PowerShell.Core | Get-Command | Verb
Microsoft.PowerShell.Core | Get-Help | Component
Microsoft.PowerShell.Core | Get-Help | Functionality
Microsoft.PowerShell.Core | Get-Help | Name
Microsoft.PowerShell.Core | Get-Help | Parameter
Microsoft.PowerShell.Core | Get-Help | Path
Microsoft.PowerShell.Core | Get-Help | Role
Microsoft.PowerShell.Core | Get-Job | Command
Microsoft.PowerShell.Core | Get-Job | Name
Microsoft.PowerShell.Core | Get-Module | Name
Microsoft.PowerShell.Core | Get-PSSessionConfiguration | Name
Microsoft.PowerShell.Core | Import-Module | Alias
Microsoft.PowerShell.Core | Import-Module | Cmdlet
Microsoft.PowerShell.Core | Import-Module | Function
Microsoft.PowerShell.Core | Import-Module | Name
Microsoft.PowerShell.Core | Import-Module | Variable
Microsoft.PowerShell.Core | New-Module | Function
Microsoft.PowerShell.Core | New-ModuleManifest | AliasesToExport
Microsoft.PowerShell.Core | New-ModuleManifest | CmdletsToExport
Microsoft.PowerShell.Core | New-ModuleManifest | DscResourcesToExport
Microsoft.PowerShell.Core | New-ModuleManifest | FunctionsToExport
Microsoft.PowerShell.Core | New-ModuleManifest | VariablesToExport
Microsoft.PowerShell.Core | New-PSRoleCapabilityFile | VisibleAliases
Microsoft.PowerShell.Core | New-PSRoleCapabilityFile | VisibleCmdlets
Microsoft.PowerShell.Core | New-PSRoleCapabilityFile | VisibleExternalCommands
Microsoft.PowerShell.Core | New-PSRoleCapabilityFile | VisibleFunctions
Microsoft.PowerShell.Core | New-PSRoleCapabilityFile | VisibleProviders
Microsoft.PowerShell.Core | New-PSSessionConfigurationFile | VisibleAliases
Microsoft.PowerShell.Core | New-PSSessionConfigurationFile | VisibleCmdlets
Microsoft.PowerShell.Core | New-PSSessionConfigurationFile | VisibleExternalCommands
Microsoft.PowerShell.Core | New-PSSessionConfigurationFile | VisibleFunctions
Microsoft.PowerShell.Core | New-PSSessionConfigurationFile | VisibleProviders
Microsoft.PowerShell.Core | Receive-Job | ComputerName
Microsoft.PowerShell.Core | Receive-Job | Name
Microsoft.PowerShell.Core | Remove-Job | Name
Microsoft.PowerShell.Core | Remove-Module | Name
Microsoft.PowerShell.Core | Remove-PSSession | Name
Microsoft.PowerShell.Core | Save-Help | Module
Microsoft.PowerShell.Core | Stop-Job | Name
Microsoft.PowerShell.Core | Test-ModuleManifest | Path
Microsoft.PowerShell.Core | Test-PSSessionConfigurationFile | Path
Microsoft.PowerShell.Core | Unregister-PSSessionConfiguration | Name
Microsoft.PowerShell.Core | Update-Help | Module
Microsoft.PowerShell.Core | Where-Object | Value
Microsoft.PowerShell.Diagnostics | Get-Counter | Counter
Microsoft.PowerShell.Diagnostics | Get-Counter | ListSet
Microsoft.PowerShell.Diagnostics | Get-WinEvent | ListLog
Microsoft.PowerShell.Diagnostics | Get-WinEvent | ListProvider
Microsoft.PowerShell.Diagnostics | Get-WinEvent | LogName
Microsoft.PowerShell.Diagnostics | Get-WinEvent | Path
Microsoft.PowerShell.Diagnostics | Get-WinEvent | ProviderName
Microsoft.PowerShell.Diagnostics | Import-Counter | Counter
Microsoft.PowerShell.Diagnostics | Import-Counter | ListSet
Microsoft.PowerShell.Diagnostics | Import-Counter | Path
Microsoft.PowerShell.LocalAccounts | Get-LocalUser | Name
Microsoft.PowerShell.Management | Add-Content | Exclude
Microsoft.PowerShell.Management | Add-Content | Filter
Microsoft.PowerShell.Management | Add-Content | Include
Microsoft.PowerShell.Management | Add-Content | Path
Microsoft.PowerShell.Management | Clear-Content | Exclude
Microsoft.PowerShell.Management | Clear-Content | Filter
Microsoft.PowerShell.Management | Clear-Content | Include
Microsoft.PowerShell.Management | Clear-Content | Path
Microsoft.PowerShell.Management | Clear-Item | Exclude
Microsoft.PowerShell.Management | Clear-Item | Filter
Microsoft.PowerShell.Management | Clear-Item | Include
Microsoft.PowerShell.Management | Clear-ItemProperty | Exclude
Microsoft.PowerShell.Management | Clear-ItemProperty | Filter
Microsoft.PowerShell.Management | Copy-Item | Exclude
Microsoft.PowerShell.Management | Copy-Item | Filter
Microsoft.PowerShell.Management | Copy-Item | Include
Microsoft.PowerShell.Management | Copy-Item | Path
Microsoft.PowerShell.Management | Copy-ItemProperty | Exclude
Microsoft.PowerShell.Management | Copy-ItemProperty | Filter
Microsoft.PowerShell.Management | Get-ChildItem | Exclude
Microsoft.PowerShell.Management | Get-ChildItem | Filter
Microsoft.PowerShell.Management | Get-ChildItem | Include
Microsoft.PowerShell.Management | Get-ChildItem | Name
Microsoft.PowerShell.Management | Get-ChildItem | Path
Microsoft.PowerShell.Management | Get-ComputerInfo | Property
Microsoft.PowerShell.Management | Get-Content | Exclude
Microsoft.PowerShell.Management | Get-Content | Filter
Microsoft.PowerShell.Management | Get-Content | Include
Microsoft.PowerShell.Management | Get-Content | Path
Microsoft.PowerShell.Management | Get-EventLog | LogName
Microsoft.PowerShell.Management | Get-EventLog | Message
Microsoft.PowerShell.Management | Get-EventLog | Source
Microsoft.PowerShell.Management | Get-EventLog | UserName
Microsoft.PowerShell.Management | Get-HotFix | Description
Microsoft.PowerShell.Management | Get-Item | Exclude
Microsoft.PowerShell.Management | Get-Item | Filter
Microsoft.PowerShell.Management | Get-Item | Include
Microsoft.PowerShell.Management | Get-Item | Stream
Microsoft.PowerShell.Management | Get-ItemProperty | Filter
Microsoft.PowerShell.Management | Get-ItemPropertyValue | Exclude
Microsoft.PowerShell.Management | Get-ItemPropertyValue | Filter
Microsoft.PowerShell.Management | Get-ItemPropertyValue | Include
Microsoft.PowerShell.Management | Get-Process | Name
Microsoft.PowerShell.Management | Get-Service | DisplayName
Microsoft.PowerShell.Management | Get-Service | Exclude
Microsoft.PowerShell.Management | Get-Service | Include
Microsoft.PowerShell.Management | Get-Service | Name
Microsoft.PowerShell.Management | Get-Service | RequiredServices
Microsoft.PowerShell.Management | Get-TimeZone | Name
Microsoft.PowerShell.Management | Invoke-Item | Exclude
Microsoft.PowerShell.Management | Invoke-Item | Filter
Microsoft.PowerShell.Management | Join-Path | ChildPath
Microsoft.PowerShell.Management | Join-Path | Path
Microsoft.PowerShell.Management | Move-Item | Exclude
Microsoft.PowerShell.Management | Move-Item | Filter
Microsoft.PowerShell.Management | Move-ItemProperty | Exclude
Microsoft.PowerShell.Management | Move-ItemProperty | Filter
Microsoft.PowerShell.Management | Move-ItemProperty | Include
Microsoft.PowerShell.Management | New-Item | Path
Microsoft.PowerShell.Management | Push-Location | Path
Microsoft.PowerShell.Management | Remove-Item | Path
Microsoft.PowerShell.Management | Remove-ItemProperty | Exclude
Microsoft.PowerShell.Management | Remove-ItemProperty | Filter
Microsoft.PowerShell.Management | Remove-PSDrive | Name
Microsoft.PowerShell.Management | Rename-ItemProperty | Include
Microsoft.PowerShell.Management | Restart-Service | DisplayName
Microsoft.PowerShell.Management | Restart-Service | Exclude
Microsoft.PowerShell.Management | Restart-Service | Include
Microsoft.PowerShell.Management | Restart-Service | Name
Microsoft.PowerShell.Management | Resume-Service | DisplayName
Microsoft.PowerShell.Management | Resume-Service | Exclude
Microsoft.PowerShell.Management | Resume-Service | Include
Microsoft.PowerShell.Management | Set-Clipboard | Path
Microsoft.PowerShell.Management | Set-Content | Exclude
Microsoft.PowerShell.Management | Set-Content | Filter
Microsoft.PowerShell.Management | Set-Content | Include
Microsoft.PowerShell.Management | Set-Content | Path
Microsoft.PowerShell.Management | Set-Item | Exclude
Microsoft.PowerShell.Management | Set-ItemProperty | Filter
Microsoft.PowerShell.Management | Set-Location | Path
Microsoft.PowerShell.Management | Show-ControlPanelItem | CanonicalName
Microsoft.PowerShell.Management | Show-ControlPanelItem | Name
Microsoft.PowerShell.Management | Split-Path | Path
Microsoft.PowerShell.Management | Start-Service | DisplayName
Microsoft.PowerShell.Management | Start-Service | Exclude
Microsoft.PowerShell.Management | Start-Service | Include
Microsoft.PowerShell.Management | Stop-Process | Name
Microsoft.PowerShell.Management | Stop-Service | DisplayName
Microsoft.PowerShell.Management | Stop-Service | Exclude
Microsoft.PowerShell.Management | Stop-Service | Include
Microsoft.PowerShell.Management | Stop-Service | Name
Microsoft.PowerShell.Management | Suspend-Service | DisplayName
Microsoft.PowerShell.Management | Suspend-Service | Exclude
Microsoft.PowerShell.Management | Suspend-Service | Include
Microsoft.PowerShell.Management | Suspend-Service | Name
Microsoft.PowerShell.Management | Test-Path | Exclude
Microsoft.PowerShell.Management | Test-Path | Filter
Microsoft.PowerShell.Management | Test-Path | Include
Microsoft.PowerShell.Management | Test-Path | Path
Microsoft.PowerShell.Security | Get-Acl | Exclude
Microsoft.PowerShell.Security | Get-Acl | Filter
Microsoft.PowerShell.Security | Get-Acl | Include
Microsoft.PowerShell.Security | Get-Acl | Path
Microsoft.PowerShell.Security | Get-AuthenticodeSignature | FilePath
Microsoft.PowerShell.Security | Set-Acl | Exclude
Microsoft.PowerShell.Security | Set-Acl | Filter
Microsoft.PowerShell.Security | Set-Acl | Include
Microsoft.PowerShell.Security | Set-Acl | Path
Microsoft.PowerShell.Utility | Add-Type | AssemblyName
Microsoft.PowerShell.Utility | Add-Type | OutputAssembly
Microsoft.PowerShell.Utility | Clear-Variable | Exclude
Microsoft.PowerShell.Utility | Clear-Variable | Include
Microsoft.PowerShell.Utility | Clear-Variable | Name
Microsoft.PowerShell.Utility | Export-Alias | Name
Microsoft.PowerShell.Utility | Export-Alias | Path
Microsoft.PowerShell.Utility | Export-PSSession | CommandName
Microsoft.PowerShell.Utility | Format-Custom | Property
Microsoft.PowerShell.Utility | Format-Hex | Path
Microsoft.PowerShell.Utility | Format-Table | Property
Microsoft.PowerShell.Utility | Format-Wide | Property
Microsoft.PowerShell.Utility | Get-Alias | Definition
Microsoft.PowerShell.Utility | Get-Alias | Exclude
Microsoft.PowerShell.Utility | Get-Alias | Name
Microsoft.PowerShell.Utility | Get-FileHash | Path
Microsoft.PowerShell.Utility | Get-FormatData | TypeName
Microsoft.PowerShell.Utility | Get-TraceSource | Name
Microsoft.PowerShell.Utility | Get-TypeData | TypeName
Microsoft.PowerShell.Utility | Get-Variable | Exclude
Microsoft.PowerShell.Utility | Get-Variable | Include
Microsoft.PowerShell.Utility | Get-Variable | Name
Microsoft.PowerShell.Utility | Import-Alias | Path
Microsoft.PowerShell.Utility | Import-PowerShellDataFile | Path
Microsoft.PowerShell.Utility | Measure-Object | Property
Microsoft.PowerShell.Utility | Select-Object | ExcludeProperty
Microsoft.PowerShell.Utility | Select-Object | Property
Microsoft.PowerShell.Utility | Select-String | Exclude
Microsoft.PowerShell.Utility | Select-String | Include
Microsoft.PowerShell.Utility | Select-String | Path
Microsoft.PowerShell.Utility | Select-Xml | Path
Microsoft.PowerShell.Utility | Set-PSBreakpoint | Command
Microsoft.PowerShell.Utility | Set-TraceSource | Name
Microsoft.PowerShell.Utility | Set-Variable | Exclude
Microsoft.PowerShell.Utility | Set-Variable | Include
Microsoft.PowerShell.Utility | Sort-Object | Property
Microsoft.PowerShell.Utility | Tee-Object | FilePath
Microsoft.PowerShell.Utility | Unblock-File | Path
Microsoft.WsMan.Management | Enable-WSManCredSSP | DelegateComputer
PackageManagement | Find-Package | Name
PackageManagement | Find-PackageProvider | Name
PackageManagement | Get-Package | Name
PowershellGet | Find-Module | Name
PowershellGet | Find-Script | Name
PowershellGet | Get-InstalledScript | Name
PowershellGet | Save-Module | Path
PowershellGet | Save-Script | Path
PowershellGet | Test-ScriptFileInfo | Path
PowershellGet | Update-Module | Name
PowershellGet | Update-ModuleManifest | AliasesToExport
PowershellGet | Update-ModuleManifest | CmdletsToExport
PowershellGet | Update-ModuleManifest | FunctionsToExport
PowershellGet | Update-ScriptFileInfo | Path
PSDesiredStateConfiguration | Get-DscResource | Name

I don't think this is just a doc issue since creating a function with SupportsWildcards attribute doesn't show if the parameter supports wildcards. Seems the help system needs to check for this attribute and add the Accept wildcard characters? true|false message.

C:\> function Test-Wildcards { param([SupportsWildcards()][string]$Name) }
C:\> Get-Help Test-Wildcards -Parameter Name

-Name <string>

    Required?                    false
    Position?                    0
    Accept pipeline input?       false
    Parameter set name           (All)
    Aliases                      None
    Dynamic?                     false

@ThomasNieto, yes, it's not _consistently_ shown; as noted in the OP, it is curiously the presence of _comment-based help_ that makes the attribute show.

I think I may have found why it works for comment-based help but not for a command with no defined help.

If no comment-based help or external help for a command (cmdlet/function), help is generated from the command syntax. GetPSObjectFromCmdletinfo after a few methods finally calls AddParameterProperties which adds all the parameter information. This method does not have logic for globbing that comment-based parser generates.

https://github.com/PowerShell/PowerShell/blob/4597b41396f8f24f73f0b43a26b8876efea0b0ec/src/System.Management.Automation/help/CommandHelpProvider.cs#L373

https://github.com/PowerShell/PowerShell/blob/4b9b0788ed28ea6d463ce857d1ed81bd4a977a59/src/System.Management.Automation/help/DefaultCommandHelpObjectBuilder.cs#L410

Comment-based parser adds globbing property.
https://github.com/PowerShell/PowerShell/blob/4b9b0788ed28ea6d463ce857d1ed81bd4a977a59/src/System.Management.Automation/help/HelpCommentsParser.cs#L124

Opened PR #13353 to fix functions not displaying if a parameter supports wildcards when no comment-based help is present. I had to add logic to add the globbing property if [SupportsWildcards] is present and update the ExtendedCmdletHelpInfo#parameter view to display the globbing property.

C:\> function foo { param($Bar) $Bar }
C:\> Get-Help foo -Parameter Bar

-Bar <Object>

    Required?                    false
    Position?                    0
    Accept pipeline input?       false
    Parameter set name           (All)
    Aliases                      None
    Dynamic?                     false
    Accept wildcard characters?  false



C:\> function foo { param([SupportsWildcards()] $Bar) $Bar }
C:\> Get-Help foo -Parameter Bar

-Bar <Object>

    Required?                    false
    Position?                    0
    Accept pipeline input?       false
    Parameter set name           (All)
    Aliases                      None
    Dynamic?                     false
    Accept wildcard characters?  true
Was this page helpful?
0 / 5 - 0 ratings