Несколько наборов параметров и PowerShell

Я строю функцию, которая будет иметь три различных набора параметров, и два из этих наборов будут перекрываться с третьим. Параметры будут выглядеть так:

A B
A C
A (D E F)
A B (D E F)
A C (D E F)

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

function Move-AccountOut {

    [CmdletBinding(DefaultParameterSetName='NoTransferHomeDrive')]
    Param(
        [Parameter(Mandatory=$True, ValueFromPipeline=$True, ValueFromPipelineByPropertyName=$True)]
        [string]$Username,

        [Parameter(ParameterSetName='RetainGroups')]
        [switch]$RetainGroups,

        [Parameter(ParameterSetName='RemoveFromAllGroups')]
        [switch]$RemoveFromAllGroups,

        [Parameter(ParameterSetName='TransferHomeDrive', Mandatory=$False)]
        [switch]$TransferHomeDrive,

        [Parameter(ParameterSetName='TransferHomeDrive', Mandatory=$True)]
        [string]$OldServer,

        [Parameter(ParameterSetName='TransferHomeDrive', Mandatory=$True)]
        [string]$NewServer
    )
}

Цель этой функции - автоматизировать процесс переноса учетной записи AD в другое место в компании. RetainGroups автоматически сохранит группы пользователей, когда они установлены, а RemoveFromAllGroups автоматически удалит пользователя из их групп. Два переключателя не должны использоваться вместе. Кроме того, если установлен TransferHomeDrive, он будет вызывать функцию для планирования передачи с использованием внутреннего инструмента.

RetainGroups словами, RetainGroups и RemoveFromAllGroups должны быть членами всех наборов параметров (аналогично имени Username), но их нельзя использовать вместе.

Я пробовал два способа. Первый:

function Move-AccountOut {

    [CmdletBinding(DefaultParameterSetName='NoTransferHomeDrive')]
    Param(
        [Parameter(Mandatory=$True, ValueFromPipeline=$True, ValueFromPipelineByPropertyName=$True)]
        [string]$Username,

        [Parameter(ParameterSetName='RetainGroups')]
        [switch]$RetainGroups,

        [Parameter(ParameterSetName='RemoveFromAllGroups')]
        [switch]$RemoveFromAllGroups,

        [Parameter(ParameterSetName='TransferHomeDrive', Mandatory=$False)]
        [Parameter(ParameterSetName='RetainGroups')]
        [Parameter(ParameterSetName='RemoveFromAllGroups')]
        [switch]$TransferHomeDrive,

        [Parameter(ParameterSetName='TransferHomeDrive', Mandatory=$True)]
        [Parameter(ParameterSetName='RetainGroups')]
        [Parameter(ParameterSetName='RemoveFromAllGroups')]
        [string]$OldServer,

        [Parameter(ParameterSetName='TransferHomeDrive', Mandatory=$True)]
        [Parameter(ParameterSetName='RetainGroups')]
        [Parameter(ParameterSetName='RemoveFromAllGroups')]
        [string]$NewServer
    )
}

Используя эту технику, сохранить и удалить нельзя использовать вместе, но OldServer и NewServer больше не являются обязательными. Если я изменю их на:

        [Parameter(ParameterSetName='TransferHomeDrive', Mandatory=$True)]
        [Parameter(ParameterSetName='RetainGroups', Mandatory=$True)]
        [string]$OldServer,

        [Parameter(ParameterSetName='TransferHomeDrive', Mandatory=$True)]
        [Parameter(ParameterSetName='RetainGroups', Mandatory=$True)]
        [string]$NewServer

Они будут обязательными, но больше не волнует, установлен ли TransferHomeDrive.

Если я настрою это наоборот:

function Move-AccountOut {

    [CmdletBinding(DefaultParameterSetName='NoTransferHomeDrive')]
    Param(
        [Parameter(Mandatory=$True, ValueFromPipeline=$True, ValueFromPipelineByPropertyName=$True)]
        [string]$Username,

        [Parameter(ParameterSetName='RetainGroups')]
        [Parameter(ParameterSetName='TransferHomeDrive')]
        [switch]$RetainGroups,

        [Parameter(ParameterSetName='RemoveFromAllGroups')]
        [Parameter(ParameterSetName='TransferHomeDrive')]
        [switch]$RemoveFromAllGroups,

        [Parameter(ParameterSetName='TransferHomeDrive', Mandatory=$False)]
        [switch]$TransferHomeDrive,

        [Parameter(ParameterSetName='TransferHomeDrive', Mandatory=$True)]
        [string]$OldServer,

        [Parameter(ParameterSetName='TransferHomeDrive', Mandatory=$True)]
        [string]$NewServer
    )
}

Тогда OldServer и NewServer будут обязательными, но RetainGroups и RemoveFromAllGroups могут использоваться вместе. Кроме того, если я использую функции сохранения и удаления вместе, то OldServer и NewServer становятся обязательными, но не тогда, когда они используются по отдельности.

Как мне сделать эту работу?

Ответ 1

Хорошо, я думаю, что понимаю это. Возможные комбинации:

  1. -RetainGroups
  2. -RemoveFromAllGroups
  3. -RetainGroups плюс -TransferHomeDrive
  4. -RemoveFromAllGroups плюс -TransferHomeDrive
  5. Только -UserName
  6. -UserName плюс -TransferHomeDrive

Я предполагаю, что -OldServer и -NewServer применяются только при перемещении домашнего диска, поэтому всякий раз, когда вы перемещаете домашний диск, они являются обязательными. Если это не так, дайте мне знать.

Итак, у вас есть 6 наборов параметров. Как бы ни была мощна магия с набором параметров powershell, нет хорошего способа сказать, что "эти 2 переключателя являются взаимоисключающими, но также должны быть доступны во всех наборах параметров", поэтому вы должны мультиплексировать его и повторять каждый набор параметров с одним или Другой.

function Move-AccountOut {
[CmdletBinding(DefaultParameterSetName='OnlyUser')]
Param( 
    [Parameter(
        Mandatory=$True, 
        ValueFromPipeline=$True, 
        ValueFromPipelineByPropertyName=$True
    )]
    [string]
    $Username,

    [Parameter(
        Mandatory=$True,
        ParameterSetName='RetainOnly'
    )]
    [Parameter(
        Mandatory=$True,
        ParameterSetName='RetainAndTransfer'
    )]
    [switch]
    $RetainGroups,

    [Parameter(
        Mandatory=$True,
        ParameterSetName='RemoveOnly'
    )]
    [Parameter(
        Mandatory=$True,
        ParameterSetName='RemoveAndTransfer'
    )]
    [switch]
    $RemoveFromAllGroups,

    [Parameter(
        Mandatory=$True,
        ParameterSetName='RetainAndTransfer'
    )]
    [Parameter(
        Mandatory=$True,
        ParameterSetName='RemoveAndTransfer'
    )]
    [Parameter(
        Mandatory=$True,
        ParameterSetName='TransferOnly'
    )]
    [switch]
    $TransferHomeDrive,

    [Parameter(
        Mandatory=$True,
        ParameterSetName='RetainAndTransfer'
    )]
    [Parameter(
        Mandatory=$True,
        ParameterSetName='RemoveAndTransfer'
    )]
    [Parameter(
        Mandatory=$True,
        ParameterSetName='TransferOnly'
    )]
    [string]
    $OldServer,

    [Parameter(
        Mandatory=$True,
        ParameterSetName='RetainAndTransfer'
    )]
    [Parameter(
        Mandatory=$True,
        ParameterSetName='RemoveAndTransfer'
    )]
    [Parameter(
        Mandatory=$True,
        ParameterSetName='TransferOnly'
    )]
    [string]
    $NewServer
)

}

Вывод Get-Help Move-AccountOut:

Move-AccountOut -Username <string>  [<CommonParameters>]

Move-AccountOut -Username <string> -RetainGroups -TransferHomeDrive -OldServer <string> -NewServer <string>  [<CommonParameters>]

Move-AccountOut -Username <string> -RetainGroups  [<CommonParameters>]

Move-AccountOut -Username <string> -RemoveFromAllGroups -TransferHomeDrive -OldServer <string> -NewServer <string>  [<CommonParameters>]

Move-AccountOut -Username <string> -RemoveFromAllGroups  [<CommonParameters>]

Move-AccountOut -Username <string> -TransferHomeDrive -OldServer <string> -NewServer <string>  [<CommonParameters>]

Упрощая это

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

[Parameter(
    Mandatory=$false # you can leave this out
)]
[ValidateSet(
    'None',
    'Retain',
    'RemoveAll'
)]
[String]
$GroupAction = 'None'

Это уменьшит ваши наборы параметров до 2, и все ваше определение будет выглядеть так:

function Move-AccountOut {
[CmdletBinding(DefaultParameterSetName='OnlyUser')]
Param( 
    [Parameter(
        Mandatory=$True, 
        ValueFromPipeline=$True, 
        ValueFromPipelineByPropertyName=$True
    )]
    [string]
    $Username,

    [ValidateSet(
        'None',
        'Retain',
        'RemoveAll'
    )]
    [String]
    $GroupAction = 'None' ,

    [Parameter(
        Mandatory=$True,
        ParameterSetName='TransferOnly'
    )]
    [switch]
    $TransferHomeDrive,

    [Parameter(
        Mandatory=$True,
        ParameterSetName='TransferOnly'
    )]
    [string]
    $OldServer,

    [Parameter(
        Mandatory=$True,
        ParameterSetName='TransferOnly'
    )]
    [string]
    $NewServer
)

}

Со следующим выводом Get-Help:

Move-AccountOut -Username <string> [-GroupAction <string> {None | Retain | RemoveAll}]  [<CommonParameters>]

Move-AccountOut -Username <string> -TransferHomeDrive -OldServer <string> -NewServer <string> [-GroupAction <string> {None | Retain | RemoveAll}]  [<CommonParameters>] 

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

Поэтому добавление некоторой сложности в определение для упрощения использования может быть правильным решением.

Ответ 2

Добавив еще два набора параметров, вы можете делать то, что хотите. Это необходимо, потому что у вас есть 3 набора сейчас, а также не заданный параметр (который технически помещает его в набор __AllParameterSets если я правильно помню). Так что 4 способа сделать это. Вам нужно 6 способов сделать это, если я правильно прочитаю ваш вопрос. Вам нужны все следующие варианты:

Move-AccountOut -Username <string>  [<CommonParameters>]
Move-AccountOut -Username <string> [-RetainGroups] [-TransferHomeDrive] [-OldServer <string>] [-NewServer <string>]  [<CommonParameters>]
Move-AccountOut -Username <string> [-RetainGroups]  [<CommonParameters>]
Move-AccountOut -Username <string> [-RemoveFromAllGroups] [-TransferHomeDrive] [-OldServer <string>] [-NewServer <string>]  [<CommonParameters>]
Move-AccountOut -Username <string> [-RemoveFromAllGroups]  [<CommonParameters>]
Move-AccountOut -Username <string> -OldServer <string> -NewServer <string> [-TransferHomeDrive]  [<CommonParameters>]

Поэтому мы добавим RemoveFromAllGroupsWTran параметров RemoveFromAllGroupsWTran и RetainGroupsWTran, добавим их как в $TransferHomeDrive, $OldServer, так и в $NewServer (удалив из них другие связанные с ними имена наборов), а затем добавим их к соответствующему параметру коммутатора. Это выглядит так:

function Move-AccountOut {

    [CmdletBinding(DefaultParameterSetName='NoTransferHomeDrive')]
    Param( 
        [Parameter(Mandatory=$True, ValueFromPipeline=$True, ValueFromPipelineByPropertyName=$True)]
        [string]$Username,

        [Parameter(ParameterSetName='RetainGroups')]
        [Parameter(ParameterSetName='RetainGroupsWTran')]
        [switch]$RetainGroups,

        [Parameter(ParameterSetName='RemoveFromAllGroups')]
        [Parameter(ParameterSetName='RemoveFromAllGroupsWTran')]
        [switch]$RemoveFromAllGroups,

        [Parameter(ParameterSetName='TransferHomeDrive', Mandatory=$False)]
        [Parameter(ParameterSetName='RetainGroupsWTran')]
        [Parameter(ParameterSetName='RemoveFromAllGroupsWTran')]
        [switch]$TransferHomeDrive,

        [Parameter(ParameterSetName='TransferHomeDrive', Mandatory=$True)]
        [Parameter(ParameterSetName='RetainGroupsWTran')]
        [Parameter(ParameterSetName='RemoveFromAllGroupsWTran')]
        [string]$OldServer,

        [Parameter(ParameterSetName='TransferHomeDrive', Mandatory=$True)]
        [Parameter(ParameterSetName='RetainGroupsWTran')]
        [Parameter(ParameterSetName='RemoveFromAllGroupsWTran')]
        [string]$NewServer
    )
}

Ответ 3

Вы также можете использовать [ValidateScript()], если во всех наборах параметров есть два параметра Mandatory = false, и вам нужно использовать их только вместе, например:

function SomeFunction {
[CmdletBinding()]
Param(
[Parameter (Mandatory = $true,
ParameterSetName = "A")]
[Parameter (Mandatory = $true,
ParameterSetName = "B")]
[Parameter (Mandatory = $true,
ParameterSetName = "C")]
[switch]$Param1,
[Parameter (Mandatory = $true,
ParameterSetName = "A")]
[switch]$Param2,
[Parameter (Mandatory = $true,
ParameterSetName = "B")]
[string]$Param3, 
[Parameter (Mandatory = $true,
ParameterSetName = "C")]
[string]$Param4,
[Parameter (Mandatory = $false,]
[ValidateScript({
                    if ($Param6) {
                    $True                         
                    }
                    else {
                    throw "This parameter will work only with parameter [Param6]"
                    } 
                }
)]
[string]$Param5,
[Parameter (Mandatory = $false)]
[ValidateScript({
                    if ($Param5) {
                    $True                         
                    }
                    else {
                    throw "This parameter will work only with parameter [Param5]"
                    } 
                }
)]
[string]$Param6
...
}