Search code examples
powershellparameter-passingargs

PowerShell : args and named parameter


I have a PS script I call from a Windows shortcut. I drop on it several files or directories, and it works fine. I would like to add some named parameters (let's call them : -Param1 and -Param2), optional, that can be used, of course, only from PowerShell Prompt.

param (
    [switch]$CreateShortcut
)

A switch parameter works.

But, if I add a string parameter :

param (
    [switch]$CreateShortcut,
    [string]$Param1
)

Of course, it does not work anymore when I call my script thru the Windows shortcut : $Param1 receive the first file.

Is there a solution ?

Thanks


Solution

  • When you drop files/folders on a shortcut file, their full paths are passed as individual, unnamed arguments to the shortcut's executable (script).

    PowerShell allows you to collect such unnamed arguments in a single, array-valued parameter, by declaring it as ValueFromRemainingArguments:

    [CmdletBinding(PositionalBinding=$false)]
    param (
        [switch] $CreateShortcut,
        # Collect all unnamed arguments in this parameter:
        [Parameter(ValueFromRemainingArguments)]
        [string[]] $FilesOrFolders
    )
    
    • [CmdletBinding(PositionalBinding=$false)] ensures that any parameters not explicitly marked with a Position property must be passed as named arguments (i.e., the argument must be preceded by the name of the target parameter, e.g. -Path foo).

      • This isn't necessary to support [switch] parameters, because they are implicitly named-only, but it allows you to support additional, non-[switch] parameters that can be bound by explicit invocation (only).
    • Alternatively, if you do not need support for additional predeclared non-switch parameters, you can omit [CmdletBinding(PositionalBinding=$false)] and the $FilesOrFolders parameter declaration and access any arguments that do not bind to predeclared parameters via the automatic $args variable.

      • Generally, note that use of a [Parameter()] attribute on any of the predeclared parameters would make $args unavailable, as the presence of [CmdletBinding()] does.

      • The reason is that the use of either attribute makes a script or function an advanced one, i.e., makes it cmdlet-like, and therefore disallows passing arguments that do not bind to declared parameters; to put it differently: $args is then by definition always empty (an empty array).

      • Advanced scripts or functions automatically gain additional features, notably support for common parameters such as -Verbose.