Позиционное связывание и наборы параметров

Я изо всех сил пытаюсь понять поведение наборов параметров и позиционной привязки. Вот пример функции.

function Test-PositionBinding {
    [CmdletBinding(DefaultParameterSetName = 'ParamSet2')]
    param (
        [Parameter(ParameterSetName='ParamSet1',Position = 0)]
        [int]
        $param1,

        [Parameter(ParameterSetName='ParamSet1',Position = 1)]
        [int]
        $param2,

        [Parameter(ParameterSetName='ParamSet2',Position = 0)]
        [int]
        $param3
    )    
    process {
        $PSCmdlet.ParameterSetName
        $param1
        $param2
        $param3
    }
}

Основываясь на выводе справки, кажется, что вызов функции с одним int должен использовать paramset1, а вызов с 2 int должен использовать paramset2, чего я и ожидал.

SYNTAX
    Test-PositionBinding [[-param3] <int>] [<CommonParameters>]

    Test-PositionBinding [[-param1] <int>] [[-param2] <int>] [<CommonParameters>]

Однако я получаю следующий вывод.

PS C:\> Test-PositionBinding 1
ParamSet2
0
0
1
PS C:\> Test-PositionBinding 1 2

Test-PositionBinding: A positional parameter cannot be found that accepts argument '2'.

Я ожидал следующего.

PS C:\> Test-PositionBinding 1 2
ParamSet1
1
2
0

Если мы изменим тип param1 на строку, функция будет работать, как и ожидалось.

PS C:\> Test-PositionBinding 1
ParamSet2

0
1
PS C:\> Test-PositionBinding 'abc'
ParamSet1
abc
0
0
PS C:\> Test-PositionBinding 'abc' 2
ParamSet1
abc
2
0

Что я неправильно понимаю в том, как PS интерпретирует наборы параметров?

В конечном счете, мой вопрос заключается в том, почему PS не может различать 2 набора параметров с позиционной привязкой и разным количеством параметров, если первый параметр имеет один и тот же тип между наборами.


person StephenP    schedule 17.04.2020    source источник


Ответы (2)


Если вы добавите ЕСЛИ, вы увидите, что при выборе параметра 1 или 2 вы находитесь в наборе параметров 1.

если вы выберете параметр 1 или 2, вы не сможете выбрать параметр 3 или 4.

если вы запустите Test-postionbinding 1

Затем, поскольку param1 определен как 0, powershell автоматически привяжет первый параметр, переданный функции, к позиции 0.
если вы передадите 0 -param4 1
Param3 будет иметь значение 0, а param4 будет 1 и вы попадаете в paramset2.

Если вы укажете param1, то вашим единственным другим параметром будет param2, потому что он является членом Paramset1.

Если вы выберете param3, то единственным другим доступным параметром будет param4, потому что он является частью paramset2.

function Test-PositionBinding {
    [CmdletBinding(DefaultParameterSetName = 'ParamSet2')]
    param (
        [Parameter(ParameterSetName='ParamSet1',Position = 0)]
        [int]
        $param1,

        [Parameter(ParameterSetName='ParamSet1',Position = 1)]
        [int]
        $param2,

        [Parameter(ParameterSetName='ParamSet2',Position = 0)]
        [int]
        $param3
    )    
    process {
        if($PSCmdlet.ParameterSetName -eq "paramset1")
        {
            write-output "Paramset1"
            $param1
            $param2
        }

        if($PSCmdlet.ParameterSetName -eq "paramset2")
        {
            write-output "Paramset2"
            $param3
            $param4
        }
    }
}

Наблюдение за привязкой позиции 2

Test-PositionBinding -param1 1 10
Paramset1
1
10

Наблюдение за параметром2

Test-PositionBinding -param3 10
Paramset2
10

не используя имена параметров и заставляя powershell использовать указанную привязку: Test-PositionBinding 0 1 Test-PositionBinding : позиция

al parameter cannot be found that accepts argument '1'.
At line:1 char:1
+ Test-PositionBinding 0 1
+ ~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidArgument: (:) [Test-PositionBinding], ParameterBindingException
    + FullyQualifiedErrorId : PositionalParameterNotFound,Test-PositionBinding


PS C:\WINDOWS\system32> Test-PositionBinding 0
Paramset2
0
person thom schumacher    schedule 17.04.2020
comment
Я только что обновил, чтобы уточнить. Если мы изменим тип параметра первой позиции в любом наборе на другой тип, он будет работать так, как ожидалось. Это то, что я не могу понять. - person StephenP; 17.04.2020
comment
ваш набор параметров по умолчанию — paramset2 . Я думаю, что происходит, когда вы указываете больше, чем указано по умолчанию. поэтому, если вы передадите два параметра по умолчанию. это приведет к ошибке, так как он не знает, где также связать второй аргумент. - person thom schumacher; 17.04.2020
comment
может показаться, что позиционная привязка работает только со значением по умолчанию. измените значение по умолчанию в начале функции и посмотрите, получите ли вы желаемое поведение. - person thom schumacher; 17.04.2020
comment
Если я изменю набор параметров по умолчанию на ParamSet1, то нет возможности вызвать позиционный параметр для ParamSet2, поскольку PS использует ParamSet1 и предполагает 0 для отсутствующего позиционного параметра. - person StephenP; 17.04.2020

Согласно MS Документы:

Требования к набору параметров Следующие требования применяются ко всем наборам параметров.

Каждый набор параметров должен иметь хотя бы один уникальный параметр. Если возможно, сделайте этот параметр обязательным параметром.

Набор параметров, содержащий несколько позиционных параметров, должен определять уникальные позиции для каждого параметра. Никакие два позиционных параметра не могут указывать одну и ту же позицию.

Только один параметр в наборе может объявить ключевое слово ValueFromPipeline со значением true. Несколько параметров могут определять ключевое слово ValueFromPipelineByPropertyName со значением true.

Если для параметра не указан набор параметров, параметр принадлежит ко всем наборам параметров.

Это хорошая запись на эту тему, которая мне помогла. Вырезать это здесь, вместо того, чтобы просто дать вам ссылку, чтобы перейти к ней. Хотя это не относится к конкретному набору параметров, применяются те же правила.

Указание позиции параметра PowerShell

Для некоторых команд имеет смысл разрешить вам передавать вещи по положению, а не по имени, особенно в тех случаях, когда было бы мало путаницы, если бы имена параметров были опущены (как в этом примере).

function Test-Position
{
    [CmdletBinding()]
    Param
    (
        [parameter(Position=0)]$parm1,
        [parameter(Position=1)]$parm2,
        [parameter(Position=2)]$parm3,
        [parameter(Position=3)]$parm4
    )
}

Что я должен делать?

> Согласно справке (about_Functions_CmdletBindingAttribute), следует использовать необязательный аргумент PositionalBinding для атрибута CmdletBinding() и установить для него значение $false.

Это приведет к тому, что все параметры по умолчанию не будут разрешены по положению. Затем > вы можете указать позицию для любого (желательно только одного или двух) параметров, которые вы хотите использовать для позиции.

Например, это позволит использовать только $parm1 по положению:

function Test-Position
{
    [CmdletBinding(PositionalBinding = $false)]
    Param([parameter(Position=0)]$parm1,
                                    $parm2,
                                    $parm3,
                                    $parm4)
}

Но подождите, становится легче

Несмотря на то, что в справке сказано, что все параметры по умолчанию являются позиционными, оказывается, что использование Position для одного параметра означает, что вы должны использовать его для любых параметров, к которым вы хотите получить доступ по положению.

Например, в этой версии функции я не указал ositionalBinding=$False в атрибуте CmdletBinding, а доступен только первый параметр по позиции.

function Test-Position2
{
    [CmdletBinding()]
    Param
    (
        [parameter(Position=0)]$parm1, 
                                $parm2, 
                                $parm3, 
                                $parm4
    )
}

Мне это интересно, так как кажется, что это противоречит тому, что есть в справке. Конкретно в хелпе написано, что все параметры позиционные. Затем он говорит, что для отключения этого значения по умолчанию следует использовать параметр PositionalBinding. Это показывает, что вам не нужно этого делать, если только вам не нужны никакие позиционные параметры.

В качестве последнего примера, просто чтобы убедиться, что мы понимаем, как используется значение Position, рассмотрим следующую справку по функциям и синтаксису:

function Test-Position3
{
    [CmdletBinding()]
    Param
    (
        $parm1,
        $parm2,
        [parameter(Position=1)]$parm3,
        [parameter(Position=0)]$parm4
    )
}

Включив Position в 2 параметра, мы добились того, что два других параметра доступны только по имени. Кроме того, назначенные позиции отличаются от порядка определения параметров в функции, что отражено в справке по синтаксису.

person postanote    schedule 19.04.2020