Требовать и проверять только именованные аргументы - PullRequest
2 голосов
/ 07 марта 2019

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

Сценарий начинается сблок параметров, такой как

param (
    [string][Alias("s")]  $sets,
    [string][Alias("l")]  $location, # /MLF #
    [switch][Alias("c")]  $conform,

    [string][Alias("eM")] $exitMode,
    [string][Alias("iM")] $interactionMode,
    [string][Alias("lM")] $logMode,
    [switch][Alias("tM")] $testMode,

    [parameter(ValueFromRemainingArguments = $true)][object[]]$extraParameters = @()
)

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

if ($extraparameters.count -gt 0) {
    $invalidArguments = New-Object Collections.ArrayList
    foreach ($namedParameter in $extraParameters) {
        if ($namedParameter.StartsWith('-')) {
            $invalidArguments.Add($namedParameter) > $null
        }
    }
    Write-PxLog "{initError-[cf][2]}_Invalid arguments '$($invalidArguments -join ', ')'"
    $proceed = $false
}

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

if ($logMode) {
    if ($validLogMode = Resolve-PxLogMode $logMode) {
        $logMode = $validLogMode
    } else {
        Write-PxLog "{initError-[cf][2]}_Invalid -logMode '$($logMode)'"
        $logMode = $null
        $proceed = $false
    }
} else {
    $logMode = 'Terse'
}

Все это с именованными аргументами, как и ожидалось, поэтому командная строка может быть

sets:Proxy -logMode:Verbose -eM:exitConsole

Все еще хорошо.

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

Proxy exitConsol verbose

, я бы ожидал, что $args.count будет 3, и я ожидаю, что exitMode, InteractionMode и LogMode будут по умолчанию.Но $args.count равно 0, и даже более странно, exitMode проверяет «подробность».Здесь я предполагаю, что параметр Conform, будучи переключателем, сбрасывает его, поэтому $ exitMode принимает третью предоставленную строку.

Итак, как я могу форсировать именованные параметры и проверять неназванные, чтобы получить значимую ошибку?Я ожидал, что $ args добьется цели, но кажется, что если вы используете блок Param (), $ args не заполняется, а параметр, который не указывает позицию, все еще может быть позиционным параметром, а использование (Position=#) простопозволяет определить эту позицию как отличную от порядка определения самих параметров?

Ответы [ 2 ]

2 голосов
/ 07 марта 2019

Чтобы требовать, чтобы все значения параметров, кроме $extraParameters, вводились с их именами, вы можете просто добавить атрибут [CmdletBinding(PositionalBinding=$false)] перед ключевым словом param:

[CmdletBinding(PositionalBinding=$false)]
param (
    [string][Alias("s")]  $sets,
    [string][Alias("l")]  $location, # /MLF #
    [switch][Alias("c")]  $conform,

    [string][Alias("eM")] $exitMode,
    [string][Alias("iM")] $interactionMode,
    [string][Alias("lM")] $logMode,
    [switch][Alias("tM")] $testMode,

    [parameter(ValueFromRemainingArguments = $true)][object[]]$extraParameters = @()
)

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

$PSBoundParameters

Объяснение

[CmdletBinding(PositionalBinding=$false)]
  • По умолчанию все параметры позиционные .
  • Аргумент PositionalBinding атрибута CmdletBinding позволяет контролировать настройки по умолчанию. Если вы не используете аргумент, тогда вы фактически установили PositionalBinding $true. Если оставить значение $true, то безымянные параметры быть переданным вашей команде.

$PSBoundParameters

  • $PSBoundParameters содержит словарь параметров, переданных в вашу команду или скрипт. Доступ к нему возможен только из области, в которой объявлены параметры.
  • В переменной или словаре будут перечислены параметры, которые были объявлены с использованием ключевого слова param.
  • Параметры и значения параметров доступны с помощью именованного индекса. Если вы объявили параметр с именем -computer, то вы можете получить доступ к этому значению в функции из $PSBoundParameters['Computer'].
  • Чтобы получить доступ к неназванным значениям параметров в вашем коде, вы просто должны использовать $PSBoundParameters['extraParameters'].
  • Здесь можно использовать методы и свойства объекта [PSBoundParametersDictionary].

$args

  • Содержит массив значений для необъявленных параметров, т.е. без использования ключевого слова param.

ValueFromRemainingArguments = $true

  • Если для этого аргумента установлено значение true, в команду могут быть переданы безымянные значения параметров. Значения будут присвоены какому-либо параметру с этим аргументом и игнорируются значения PositionalBinding.

См. about_Functions_Advanced_Parameters и about_Automatic_Variables для дополнительных объяснений и возможностей.

Пример использования именованных аргументов

function namedArguments {
[cmdletbinding(PositionalBinding=$false)]
param(
[parameter()][string]$a,
[parameter()][byte]$b,
[parameter()][byte]$c

)

write-host "args is "
$args
write-host "parameters is "
$psboundparameters

}

namedArguments -a "hi" -b 2 -c 3
args is
parameters is

Key Value
--- -----
a   hi
b   2
c   3

Вызов функции выше со значением параметра Безымянный:

namedArguments -a "test" -b 20 -c 43 "extraparameter"

namedArguments: не найден позиционный параметр, который принимает аргумент «экстрапараметр». В строке: 1 символ: 1 + namedArguments -a "тест" -b 20 -c 43 "экстрапараметр" + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~ + CategoryInfo: InvalidArgument: (:) [namedArguments], ParameterBindingException + FullyQualifiedErrorId: PositionalParameterNotFound, namedArguments

namedArguments "no parameter name"

namedArguments: невозможно найти позиционный параметр, который принимает аргумент «нет имени параметра». В строке: 1 символ: 1 + namedArguments "без имени параметра" + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo: InvalidArgument: (:) [namedArguments], ParameterBindingException + FullyQualifiedErrorId: PositionalParameterNotFound, namedArguments

Пример использования именованных и безымянных

function AllArgumentsWelcome {
[cmdletbinding(PositionalBinding=$false)]
param(
[parameter()][string]$a,
[parameter()][byte]$b,
[parameter()][byte]$c,
[parameter(ValueFromRemainingArguments = $true)][string]$d
)

$PSBoundParameters
 if ($PSBoundParameters['d']) { # Checking unnamed parameters
  "$($PSBoundParameters['d']) was not assigned to a named parameter!"
 }
}

AllArgumentsWelcome -a "test" -b 2 -c 3 "no parameter name"

Key Value
--- -----
a   test
b   2
c   3
d   no parameter name
no parameter name was not assigned to a named parameter!
  • Обратите внимание на приведенный выше пример доступа к неназванным значениям параметров, переданным функции.

Примечания стороны

  • Можно установить атрибут [Parameter(Position=0)] для всех ваших параметров, чтобы получить аналогичный эффект, требующий все параметры будут названы. Однако, если у вас есть только один параметр в определение функции, это не даст желаемого результата и будет разрешен единственный безымянный параметр.

.

0 голосов
/ 07 марта 2019

Составление ответа AdminOfThings и Frode F. s ответа на Получите ValueFromRemainingArguments в качестве хеш-таблицы :

[CmdletBinding(PositionalBinding=$false)]
param (
    [string][Alias("s")]  $sets,
    [string][Alias("l")]  $location, # /MLF #
    [switch][Alias("c")]  $conform,

    [string][Alias("eM")] $exitMode,
    [string][Alias("iM")] $interactionMode,
    [string][Alias("lM")] $logMode,
    [switch][Alias("tM")] $testMode,

    [parameter(ValueFromRemainingArguments)][object[]]$extraParameters = @()
)
    #Convert extraparameters to an OrderedDictionary (initially hashtable)
    $htvars = [ordered]@{}
    $iii = 0                   # extraparameters counter
    $lastvar = "unnamed_$iii"
    $extraparameters | ForEach-Object {
        $iii += 1 
        if($_ -match '^-') {
            #New parameter
            $lastvar = $_ -replace '^-'
            $htvars[$lastvar] = $null
        } else {
            #Value
            $htvars[$lastvar] = $_
            $lastvar = "unnamed_$iii" 
        }
    }
    #Propagate OrderedDictionary
    $htvars

Приведенное выше решение поддерживает параметры с:

  • Простое значение (один элемент)
  • Массив
  • Нулевое значение (переключатель)
  • Безымянное значение

Пример вывода:

PS D:\PShell> .\SO\55042084a.ps1 -a111 -s 555 -abc "ABC" -num 15, 17 'ghi' -Seria "seria" "fifi" -l "llllů" -foo

Name                           Value                                           
----                           -----                                           
a111                                                                           
abc                            ABC                                             
num                            {15, 17}                                        
unnamed_5                      ghi                                             
Seria                          seria                                           
unnamed_8                      fifi                                            
foo                                                                            

PS D:\PShell> .\SO\55042084a.ps1 a111 -s 555 -abc "ABC" -num 15, 17 'ghi' -foo -Seria "seria" "fifi" -l "llllů"

Name                           Value                                           
----                           -----                                           
unnamed_0                      a111                                            
abc                            ABC                                             
num                            {15, 17}                                        
unnamed_5                      ghi                                             
foo                                                                            
Seria                          seria                                           
unnamed_9                      fifi                                            
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...