有没有更好的方法来声明多个参数集?

时间:2013-02-07 19:55:36

标签: powershell

我正在编写一个cmdlet(在PowerShell中),负责将记录写入数据库。使用条件命令行,似乎我必须定义四个不同的参数集。

有没有更有成效的方法呢?

详情

cmdlet的参数是:

  • ComputerName(要连接的SQL服务器)
  • Path(数据的位置)
  • Xml(原始数据本身)
  • UserName
  • Password
  • UseIntegratedSecurity(而不是用户名/密码,请使用当前凭据)

PathXml是互斥的,UserName / PasswordUseIntegratedSecurity是互斥的。

为了正确连接,似乎我必须定义四个不同的参数集,例如:


function Install-WidgetData
{
    [CmdletBinding()]
    PARAM
    (
        [Parameter(ParameterSetName="Xml_AutoConnect", Mandatory=$True)]
        [Parameter(ParameterSetName="Xml_ManualConnect", Mandatory=$True)]
        [Parameter(ParameterSetName="Path_AutoConnect", Mandatory=$True, )]
        [Parameter(ParameterSetName="Path_ManualConnect", Mandatory=$True)]
        [ValidateNotNullOrEmpty()]
        [string[]] $ComputerName,

        [Parameter(ParameterSetName="Path_AutoConnect", Mandatory=$True)]
        [Parameter(ParameterSetName="Path_ManualConnect", Mandatory=$True)]
        [ValidateNotNullOrEmpty()]
        [string] $Path,

        [Parameter(ParameterSetName="Xml_AutoConnect", Mandatory=$True)]
        [Parameter(ParameterSetName="Xml_ManualConnect", Mandatory=$True)]
        [ValidateNotNullOrEmpty()]
        [string[]] $Xml,

        [Parameter(ParameterSetName="Xml_AutoConnect")]
        [Parameter(ParameterSetName="Path_AutoConnect")]
        [switch] $UseIntegratedSecurity,

        [Parameter(ParameterSetName="Xml_ManualConnect")]
        [Parameter(ParameterSetName="Path_ManualConnect")]
        [ValidateNotNullOrEmpty()]
        [string] $UserName,

        [Parameter(ParameterSetName="Xml_ManualConnect")]
        [Parameter(ParameterSetName="Path_ManualConnect")]
        [ValidateNotNullOrEmpty()]
        [string] $Password,
    )

4 个答案:

答案 0 :(得分:8)

如果您想对参数集进行快速完整性检查,可以使用Show-Command

这将显示一个包含多个选项卡的表单,每个选项卡对应一个选项卡。例如:

  

Show-Command Get-ChildItem

将显示:

enter image description here

或者;如果您想要命令行替代方案,可以使用Get-Command -Syntax

  

Get-Command Get-ChildItem -Syntax

会告诉你:

  

Get-ChildItem [[-Path]] [[-Filter]] [-Include] [-Exclude] [-Recurse] [-Depth] [-Force] [-Name] [-UseTransaction] [-Attributes] [-Directory] ​​[-File] [-Hidden] [-ReadOnly] [-System] []

     

Get-ChildItem [[-Filter]] -LiteralPath [-Include] [-Exclude] [-Recurse] [-Depth] [-Force] [-Name] [-UseTransaction] [-Attributes] [-Directory] [-File] [-Hidden] [-ReadOnly] [-System] []

答案 1 :(得分:4)

可悲的是,根据about_Functions_Advanced_Parameters

,这是唯一的方法。

以下是摘录:

    You can specify only one ParameterSetName value in each argument and only
    one ParameterSetName argument in each Parameter attribute. To indicate that
    a parameter appears in more than one parameter set, add additional Parameter        
    attributes.

    The following example explicitly adds the Summary parameter to the Computer
    and User parameter sets. The Summary parameter is mandatory in one parameter
    set and optional in the other.

    Param
      (
        [parameter(Mandatory=$true,
                  ParameterSetName="Computer")]
        [String[]]
        $ComputerName,

        [parameter(Mandatory=$true,
                  ParameterSetName="User")]
        [String[]]
        $UserName

        [parameter(Mandatory=$false, ParameterSetName="Computer")]
        [parameter(Mandatory=$true, ParameterSetName="User")]
        [Switch]
        $Summary
      )

有关参数集的更多信息,请参阅Cmdlet Parameter Sets          在MSDN库中。

答案 2 :(得分:2)

有更好的方法,但它是设计解决方案,而不是技术方案。

问题实际上是你的功能做了太多事情。有人可能会说它违反了单一责任原则。它执行的每个任务都有两个独立的参数集。任务及其参数集为:

  • 构建连接字符串
    • 手动(用户名和密码)
    • 自动(操作系统帐户验证)
  • 向数据库发送查询
    • XML数据
    • 包含数据的XML文件的路径

由于每个任务都有自己不同的参数集,因此您的函数最终需要它们的笛卡尔积(手动和XML,自动和XML,手动和路径,自动和路径)。

任何时候你发现自己身处其中一种"笛卡尔产品"参数情况,它几乎总是一个标志,你可以将一个功能移动到一个单独的功能,并使新功能的结果成为原始参数。在这种情况下,您可以将其拆分为New-ConnectionStringInstall-WidgetDataInstall-WidgetData可以接受完整的连接字符串作为参数。这消除了从Install-WidgetData构建连接字符串的逻辑,将几个参数压缩为一个,并将所需的参数集数量减半。

function New-ConnectionString(
    [Parameter(Mandatory=$True, Position=0)] # Makes it mandatory for all parameter sets
    [ValidateNotNullOrEmpty()]
    [string[]]$ComputerName,

    [Parameter(ParameterSetName="AutoConnect", Mandatory=$True)]
    [switch]$UseIntegratedSecurity,

    [Parameter(ParameterSetName="ManualConnect", Mandatory=$True, Position=1)]
    [ValidateNotNullOrEmpty()]
    [string]$UserName,

    [Parameter(ParameterSetName="ManualConnect", Mandatory=$True, Position=2)]
    [ValidateNotNullOrEmpty()]
    [string]$Password
) {
    # ... Build connection string up
    return $connString
}


function Install-WidgetData(
    [Parameter(Mandatory=$True, Position=0)]
    [ValidateNotNullOrEmpty()]
    [string]$ConnectionString,

    [Parameter(ParameterSetName="Path", Mandatory=$True, Position=1)]
    [ValidateNotNullOrEmpty()]
    [string]$Path,

    [Parameter(ParameterSetName="Xml", Mandatory=$True)]
    [ValidateNotNullOrEmpty()]
    [string[]]$Xml
) {
     # Do installation
}

通过在命令上调用help,您可以看到这样做了您想要的:

PS C:\> help New-ConnectionString

NAME
    New-ConnectionString

SYNTAX
    New-ConnectionString [-ComputerName] <string[]> -UseIntegratedSecurity  [<CommonParameters>]

    New-ConnectionString [-ComputerName] <string[]> [-UserName] <string> [-Password] <string>  [<CommonParameters>]

...

PS C:\> help Install-WidgetData

NAME
    Install-WidgetData

SYNTAX
    Install-WidgetData [-ConnectionString] <string> [-Path] <string>  [<CommonParameters>]

    Install-WidgetData [-ConnectionString] <string> -Xml <string[]>  [<CommonParameters>]

...

然后你称他们为:

Install-WidgetData (New-ConnectionString 'myserver.example.com' -UseIntegratedSecurity) `
    -Path '.\my-widget-data.xml'

当然,如果需要,您可以将New-ConnectionString的结果存储在变量中。您还可以通过执行此重构获得一些其他功能:

  • New-ConnectionString的返回值可以重复用于需要连接字符串的任意数量的函数。
  • 如果用户愿意
  • ,则可以从其他来源获取连接字符串
  • 如果他们需要使用您未提供访问权限的功能,来电者可以放弃您的New-ConnectionString自行支持

答案 3 :(得分:0)

嗯,这是最简洁的方式。更简洁然后是开关/案例的恐怖,或者if / then陷阱来解释所有可能的参数集!

但是,您的另一个选择是为互斥参数集编写不同的命令,例如

Install-WidgetDataFromPath
Install-WidgetDataFromXml

如果您只使用脚本文件,两者都可以调用Install-WidgetData脚本命令行开关,您可以将其隐藏在模块中,或者使用范围修饰符将其隐藏在全局范围内。内部命令行开关可以为两个(或更多)面向用户的包装器实现共享代码。从你的代码来看,我认为你不需要解释如何实现它。