Найти значения в ValidateSet

Мне было интересно, если есть способ получить значения, используемые в предложении Param() за ValidateSet, Примерно так было бы здорово

Function Foo {
    Param (
        [ValidateSet('Startup', 'Shutdown', 'LogOn', 'LogOff')]
        [String]$Type = 'Startup'
    )

    $Type.ValidateSet
}

Но, конечно, на Type объект. Можно ли получить значения, установленные в ValidateSet?

3 ответа

Решение
function Foo {
    param (
        [ValidateSet('Startup', 'Shutdown', 'LogOn', 'LogOff')]
        [String]$Type = 'Startup'
    )

    $ParameterList = (Get-Command -Name $MyInvocation.MyCommand).Parameters
    $ParameterList["Type"].Attributes.ValidValues
}

После вашего комментария:

param (
        [ValidateSet('Startup', 'Shutdown', 'LogOn', 'LogOff')]
        [String]$Type = 'Startup'
)


(Get-Variable "Type").Attributes.ValidValues

Get-Variable Вызов также работает в функции.

Все приведенные ниже решения работают как в функциях, так и в сценариях.

Самое надежное решение, которое должно работать в любом сценарии вызова, PSv2 +:

param (
    [ValidateSet('Startup', 'Shutdown', 'LogOn', 'LogOff')]
    [String]$Type = 'Startup'
)

($MyInvocation.MyCommand.Parameters['Type'].Attributes |
  Where-Object { $_ -is [System.Management.Automation.ValidateSetAttribute] }).ValidValues

Более простое, но хрупкое решение PSv3+, которое предполагает:

  • тот Set-StrictMode либо установлен на -version 1 или не установлено.

    • Set-StrictMode возможно, был установлен вне вашего контроля, поэтому, если вы не полностью управляете средой выполнения, безопаснее использовать более подробную, PSv2-совместимую команду, описанную выше.
      (The Set-StrictMode Настройка ведет себя как переменная: она наследуется наследуемыми областями, но установка ее в области потомков устанавливает ее локально (влияет только на эту область и ее потомков).)

    • Однако, если вы определите функцию как часть модуля, внешний мир Set-StrictMode настройка не применяется.

  • что, по крайней мере, до Windows PowerShell v5.1 / PowerShell Core v6.0-alpha16, эта ошибка возникает при неоднократном расстановке точек в сценарии, не являясь проблемой.

param (
    [ValidateSet('Startup', 'Shutdown', 'LogOn', 'LogOff')]
    [String]$Type = 'Startup'
)

(Get-Variable Type).Attributes.ValidValues

Дополнительная справочная информация

PSv3+ сокращенный синтаксис (Get-Variable Type).Attributes.ValidValues по существу эквивалентно:

(Get-Variable Type).Attributes | ForEach-Object { $_.ValidValues }

То есть PowerShell автоматически перечисляет коллекцию .Attributes и собирает значения каждого элемента .ValidValues имущество.

В данном случае только один атрибут в .Attributes коллекция - подтип [System.Management.Automation.ValidateSetAttribute] - имеет .ValidValues свойство, так что возвращается одно значение.

Учитывая, что другие атрибуты не имеют такого свойства, установка Set-StrictMode в -version 2 или выше вызывает попытку получить доступ к несуществующему свойству, чтобы вызвать ошибку, и команда терпит неудачу.

((Get-Variable Type).Attributes |
  Where-Object { $_ -is [System.Management.Automation.ValidateSetAttribute] }).ValidValues

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

Более подробная альтернатива для доступа к атрибутам параметра [variable] $Type с (Get-Variable Type).Attributes это использовать $MyInvocation.MyCommand.Parameters['Type'].Attributes,

Использование $MyInvocation.MyCommand.Parameters коллекция позволяет перечислять и проверять все параметры без необходимости заранее знать их имена.


Ответ Дэвида Брабанта полезен, но (на момент написания статьи):

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

  • Get-Command -Name $MyInvocation.MyCommand часть это:

    • не нужно, потому что $MyInvocation.MyCommand Сам предоставляет интересующую информацию:
      $MyInvocation.MyCommand это экземпляр типа [System.Management.Automation.ExternalScriptInfo] в сценариях и введите [System.Management.Automation.FunctionInfo] в функциях, которые оба происходят от типа [System.Management.Automation.CommandInfo], который является типом, который Get-Commmand возвращает - так что они не только предоставляют ту же информацию, они также однозначно ссылаются на прилагаемый скрипт / функцию.

    • хрупкий

      • $MyInvocation.MyCommand преобразуется в строку из-за передачи в -Name параметр, который в скрипте приводит к простому имени файла скрипта (например, script.ps1) и в функции в названии функции (например, Foo).

      • В сценарии это обычно приводит к Get-Command не искать скрипт вообще - если только этот скрипт не находится в PATH (один из каталогов, перечисленных в $env:PATH). Но это также означает, что другой сценарий, который имеет одно и то же имя файла и который находится / находится на первом месте в переменной PATH, может быть сопоставлен, что приведет к неверным результатам.
        Короче: Get-Command -Name $MyInvocation.MyCommand в сценариях часто ломается, и когда он возвращает результат, это может быть неправильный сценарий.

      • В функции он также может идентифицировать неправильную команду, хотя это гораздо менее вероятно:
        Из-за командного приоритета PowerShell данное имя сначала интерпретируется как псевдоним, а затем как функция, поэтому, теоретически, с Foo определенный псевдоним, Get-Command -Name $MyInvocation.MyCommand внутренняя функция Foo по ошибке вернул бы информацию о псевдониме.
        (Вызывать функцию нетривиально Foo в то время как псевдоним Foo определяется, но это может быть сделано; например: & (Get-Item Function:Foo))

validateScript, может предоставить более гибкое решение и будет работать хорошо, если вам потребуется дополнительная проверка параметров. Это также позволяет вам получить список допустимых параметров за пределами foo функция, с созданием get-validTypes функция.

Function Foo {
    Param (
        [validateScript({test-validTypes $_})]
        [String]$Type = 'Startup'
    )

    get-validTypes
}

function get-validTypes {

    $powerOptions = @('Startup', 'Shutdown', 'LogOn', 'LogOff')
    Write-Output $powerOptions

}

function test-validTypes {
[cmdletbinding()]
param ($typeInput)

    $validTypes = get-validTypes
    if ($validTypes.contains($typeInput)){
        return $true
    } else {
        Write-Error "Invalid Type Paramater, Must be on of the following: $powerOptions"
    }

}
Другие вопросы по тегам