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

Powershell 有没有更好的方法来声明多个参数集?,powershell,Powershell,我正在编写一个cmdlet(在PowerShell中),负责将记录写入数据库。使用条件命令行,我似乎必须定义四个不同的参数集 有没有更成功的方法 细节 cmdlet的参数包括: ComputerName(要连接到的SQL server) 路径(数据的位置) Xml(原始数据本身) 用户名 密码 UseIntegratedSecurity(使用当前凭据而不是用户名/密码) Path和Xml是互斥的,而UserName/Password和useeintegratedsecurity是互斥的 为了

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

有没有更成功的方法

细节

cmdlet的参数包括:

  • ComputerName
    (要连接到的SQL server)
  • 路径(数据的位置)
  • Xml
    (原始数据本身)
  • 用户名
  • 密码
  • UseIntegratedSecurity
    (使用当前凭据而不是用户名/密码)
Path
Xml
是互斥的,而
UserName
/
Password
useeintegratedsecurity
是互斥的

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


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,
    )

嗯,这是最简洁的方式。比switch/case或if/then陷阱更简洁地解释了所有可能的参数集

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

Install-WidgetDataFromPath
Install-WidgetDataFromXml

两者都可以调用
Install WidgetData
script commandlet,您可以将其隐藏在模块内部,如果您仅使用脚本文件,则可以使用范围修饰符将其从全局范围隐藏。内部commandlet可以为两个(或多个)面向用户的包装器实现共享代码。从您的代码判断,我认为不需要向您解释如何实现此功能。

如果您希望对参数集进行快速的健全性检查,可以使用
Show命令

这将显示一个具有多个选项卡的表单,每个参数集一个选项卡。例如:

Show命令Get ChildItem

将显示:

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

Get命令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][-UseTransation][Attributes][Directory][File][Hidden][ReadOnly][System][]


不幸的是,根据about_函数和Advanced_参数,这是唯一的方法

以下是摘录:

有关参数集的详细信息,请参见
在MSDN库中。

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

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

  • 构建一个连接字符串
    • 手册(用户名和密码)
    • 自动(操作系统帐户身份验证)
  • 向数据库发送查询
    • XML数据
    • 包含数据的XML文件的路径
由于每个任务都有自己不同的参数集,因此函数最终需要这些参数的笛卡尔积(Manual&XML、Auto&XML、Manual&path、Auto&path)

每当你发现自己处于这些“笛卡尔积”参数的情况下,它几乎总是一个迹象,表明你可以将一部分功能移动到一个单独的函数中,并使新函数的结果成为原始函数的参数。在这种情况下,您可以将其拆分为
newconnectionString
Install WidgetData
,并且
Install 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>]

...
当然,如果需要,可以将
newconnectionString
的结果存储在变量中。执行此重构还可以获得一些附加功能:

  • 新连接字符串
    的返回值可用于需要连接字符串的任意数量的函数
  • 如果调用者愿意,他们可以从其他来源获取连接字符串
  • 如果呼叫者需要使用您未提供访问权限的功能,他们可以放弃您的
    新连接字符串
    ,转而自己使用

$ComputerName
可以不使用
参数setname
。据我所知,你唯一可以最小化的就是@C.B.所说的内容。让我们只说,
#region
存在的原因是有原因的,这对于非技术人员来说非常方便。非常棒。
Get命令Install WidgetData-Syntax
同样有用这可能对某些用户很有帮助,但似乎并没有真正回答问题。这是正确的解决方案,即使它不是真正的
PowerShell
方法。它使使用更加复杂(调用两个函数而不是一个函数)。不过,这需要一些很好的解释/文档/示例。@oɔɯǝɹ我不会说这不是PowerShell的做事方式。在我看来,这与在传入文件路径之前调用
joinpath
建立文件路径没有太大区别。您只需添加一个函数,从几个不同的部分构建一个内聚参数。
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'