Порядок привязки параметров конвейера PowerShell - PullRequest
0 голосов
/ 01 марта 2019

У меня есть расширенная функция, которая может принимать два типа данных конвейера:

  • Пользовательский объект с PSTypeName «MyType»
  • Любой объект со свойством ID

Вот моя функция:

function Test-PowerShell {
    [CmdletBinding(DefaultParameterSetName = "ID")]
    param (
        [Parameter(
            Mandatory = $true,
            ParameterSetName = "InputObject",
            ValueFromPipeline = $true
        )]
        [PSTypeName('MyType')]
        $InputObject,

        [Parameter(
            Mandatory = $true,
            ParameterSetName = 'ID',
            ValueFromPipelineByPropertyName = $true
            )]
        [int]
        $ID
    )

    process {
        if ($InputObject) {
            $objects = $InputObject
            Write-Verbose 'InputObject binding'
        }
        else {
            $objects = Get-MyType -ID $ID
            Write-Verbose 'ID binding'
        }

        # Do something with $objects
    }
}

Я могу использовать эту функцию следующим образом:

$obj = [PSCustomObject]@{
    PSTypeName = 'MyType'
    ID = 5
    Name = 'Bob'
}
$obj | Test-PowerShell -Verbose

Обратите внимание, что этот объект удовлетворяет обоим из указанных выше условий:MyType, и у него есть свойство ID.В этом случае PowerShell всегда связывается со свойством ID.Это не идеальное решение с точки зрения производительности, поскольку переданный по конвейеру объект отбрасывается, и я должен повторно запросить его, используя идентификатор.У меня такой вопрос:

Как заставить PowerShell привязать конвейер к $ InputObject, если это возможно?

Если я изменяю параметр по умолчанию, установленный на InputObject, PowerShell связываетна $ InputObject.Однако я не хочу этого, потому что при запуске без параметров я хочу, чтобы PowerShell запрашивал идентификатор, а не InputObject.

1 Ответ

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

Простой ответ: удалите аргумент Mandatory для атрибута Parameter на $InputObject, чтобы получить желаемую функциональность.У меня недостаточно знаний о том, как работает привязка параметров, чтобы объяснить , почему это работает.

function Test-PowerShell {
    [CmdletBinding(DefaultParameterSetName = 'ID')]
    param(
        [Parameter(ParameterSetName = 'InputObject', ValueFromPipeline)]
        [PSTypeName('MyType')]
        $InputObject,

        [Parameter(ParameterSetName = 'ID', Mandatory, ValueFromPipelineByPropertyName)]
        [int]
        $ID
    )

    process {
        $PSBoundParameters
    }
}

$o = [pscustomobject]@{
    PSTypeName = 'MyType'
    ID         = 6
    Name       = 'Bob'
}


PS> $o | Test-PowerShell

Key         Value
---         -----
InputObject MyType


PS> [pscustomobject]@{ID = 6} | Test-PowerShell

Key Value
--- -----
ID      6

Мысли и эксперименты приведены ниже.

Вот a способ решения вашей проблемы (определение вашего собственного типа):

Add-Type -TypeDefinition @'
public class MyType
{
    public int ID { get; set; }
    public string Name { get; set; }
}
'@

И тогда вы бы пометили свой параметр как [MyType], создавая такие объекты, как выбудет от [pscustomobject]:

[MyType]@{ ID = 6; Name = 'Bob' }

Оглядываясь назад, этот метод не работает.То, с чем вы сталкиваетесь, это поведение DefaultParameterSet.Я бы посоветовал изменить то, что вы принимаете за конвейерный ввод.Есть ли вариант использования для получения идентификатора в качестве входного конвейера по сравнению с пользователем, который просто использует Test-PowerShell -ID 5 или Test-PowerShell и получает запрос на ввод идентификатора?

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

function Test-PowerShell {
    [CmdletBinding(DefaultParameterSetName = 'ID')]
    param(
        [Parameter(ParameterSetName = 'InputObject', Mandatory = $true, ValueFromPipeline = $true)]
        [PSTypeName('MyType')]
        $InputObject,

        [Parameter(ParameterSetName = 'ID', Mandatory = $true, ValueFromPipeline = $true)]
        [int]
        $ID
    )

    process {
        $PSBoundParameters
    }
}

Чтобы взять пример из существующего встроенного командлета, они не используют одно и то же имя или свойства объекта для нескольких параметров.В Get-ChildItem и LiteralPath, и Path принимают входные данные конвейера, но LiteralPath принимает их только через PropertyName LiteralPath или PSPath (с псевдонимом).Path - это ByValue и PropertyName, но только как Path.

...