Чтобы суммировать и дополнить полезные комментарии по этому вопросу Lee_Dailey , Мэтью и Маклайтон :
[switch]
параметры в PowerShell (или флаги в других оболочках):
switch
параметры предназначены для подразумевают $true
против $false
их присутствием в вызове: например, передача -sw
самой сигналов $true
, тогда как пропуск -sw
сигналы $false
.
Это - это возможно передать логическое значение явно , с целью передачи определенное программно значение ; Например: -sw:$var
Обратите внимание на обязательные :
после имени переключателя, который сообщает PowerShell, что логическое значение принадлежит параметру переключателя; без этого PowerShell считает, что значение является позиционным аргументом, предназначенным для другого параметра (см. ниже).
Caveat : Команды могут интерпретировать -sw:$false
иначе, чем пропуск -sw
; ярким примером является использование общего параметра -Confirm:$false
для переопределения действующего значения $ConfirmPreference
.
- Если вам нужно сделать это различие в вашем собственном коде, используйте
$PSBoundParameters.ContainsKey('sw') -and -not $sw
для обнаружения -sw:$false
case.
Не назначать значение по умолчанию переменной параметра переключателя: хотя технически это возможно, соглашение предусматривает переключение по умолчанию на $false
(которое в любом случае является значением [switch]
экземпляра по умолчанию); то есть параметр [switch]
всегда должен иметь opt-in logi c.
A [switch]
переменная параметра эффективно ведет себя как Логическое значение в большинстве контекстов:
То есть, например, вы можете сказать if ($sw) { ... }
.
Если вам нужен явный доступ к булевому значению в оболочке, обратитесь к свойству .IsPresent
(обратите внимание, что имя свойства несколько сбивает с толку, поскольку в вызове -sw:$false
переключатель все еще присутствует , но его значение , как указано в .IsPresent
, равно $false
).
- Примером необходимости
.IsPresent
является использование Boolean как неявный индекс массива, особенно для эмуляции троичного условия [1] : ('falseValue', 'trueValue')[$sw.IsPresent]
; без .IsPresent
эффективное логическое значение не будет распознаваться как таковое и не будет автоматически отображаться на индекс 0
(с $false
) или 1
(с $true
).
В конечном счете, ваша проблема заключалась в том, что вы думали, что $true
был аргументом для -sw
, тогда как он стал позиционным аргумент неявно связан с параметром -test2
.
[switch]
параметры никогда не нужно значение, поэтому следующий аргумент становится отдельным позиционным аргументом - если , вы явно указываете, что аргумент принадлежит коммутатору, следуя имени коммутатора с :
, как показано выше. [2]
Позиционный против именованный передача аргумента в PowerShell:
примечание по терминологии : для концептуальной ясности термин аргумент используется для обозначения значение , переданное в объявленный параметр . Это позволяет избежать неоднозначности использования параметра ситуативно для обращения к языковой конструкции, которая получает значение против данного значения .
Именованный передача аргумента (привязка) относится к явному размещению целевого имени параметра перед аргументом (обычно разделяется пробелом, но в качестве альтернативы также и / или :
); например, -AppName foo
.
- Порядок , в котором передаются именованные аргументы , никогда не имеет значения .
Позиционный (без имени) передача аргумента относится к передаче аргумента без , перед которым стоит имя его целевого параметра; например, foo
.
- Передача является позиционной в том смысле, что относительная позиция (порядок) среди других неназванных аргументов определяет, какой целевой параметр подразумевается .
[switch]
параметры являются исключением в том смысле, что они:
- обычно передаются только именем (
-sw
), подразумевая значение $true
и, если передано значение , , требуется :
для отделения имени от значения. - никогда поддержка позиционное связывание.
Вы можете объединить именованный проход с позиционным проходом , в этом случае именованный сначала связываются аргументы, после чего позиционные аргументы затем рассматриваются (по порядку) для привязки к еще не связанным параметрам.
Функции PowerShell простые функции по умолчанию. Чтобы осуществлять управление позиционным связыванием , необходимо использовать атрибуты [CmdletBinding()]
и / или [Parameter()]
(см. Ниже), которые неизменно превращают простую функцию в расширенную . функция .
- Превращение простой функции в более сложную имеет большие поведенческие последствия (в основном полезные), которые подробно описаны в этом ответе .
По умолчанию функции PowerShell принимают позиционные аргументы для любого параметра (отличного от типа [switch]
), в том порядке, в котором были объявлены параметры .
- Кроме того, простые функции принимают произвольные дополнительные аргументы для которых не было объявлено ни одного параметра , которые собираются в переменной массива automati c
$args
.
Чтобы запретить вашей функции принимать любые позиционные аргументы по умолчанию , поместить [CmdletBinding(PositionalBinding=$false, ...)]
атрибут над блоком param(...)
.
Поскольку это делает вашу функцию продвинутой , это также отключает передачу произвольной дополнительной аргументы ($args
больше не применяется и не заполняется).
В качестве отступления: при реализации командлета (команда реализована как двоичный , обычно через C#), это поведение подразумевается .
К выборочно поддерживает позиционные аргументы , украшает объявления отдельных параметров атрибутом [Parameter(Position=<n>, ...)]
(например, [Parameter(Position=0)] [string] $Path
)
Примечание: Независимо от того, начинаете ли вы нумерацию с 0
или 1
, это не имеет значения, если используемые числа отражают желаемый порядок среди всех позиционных параметров; 0
рекомендуется в качестве самодокументируемого соглашения, поскольку оно недвусмысленно.
Атрибут [Parameter(Position=<n>)]
- это явное согласие, которое выборочно переопределяет [CmdletBinding(PositionalBinding=$false)]
: то есть последний отключает позиционное связывание , если только явно не указано в объявлениях отдельных параметров; на самом деле, последний является подразумеваемым от первого, в этом как только вы используете один [Parameter(Position=<n>)]
атрибут, вы должны использовать его для всех других параметров, которые вы хотите связать позиционно а также .
[1] Обратите внимание, что PowerShell [Core] 7.0+ изначально поддерживает троичные условия: $sw ? 'trueValue' : 'falseValue'
[2] По сути, параметры [switch]
являются единственным типом, для которого PowerShell поддерживает необязательный аргумент . См. этот ответ для получения дополнительной информации.