13

我正在编写一个负责将记录写入数据库的 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

4 回答 4

14

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

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

显示命令获取子项

将显示这一点:

在此处输入图像描述

或者; 如果你想要一个命令行替代品,你可以使用Get-Command -Syntax

Get-Command Get-ChildItem -语法

将向您展示:

Get-ChildItem [[-Path] ] [[-Filter] ] [-Include ] [-Exclude ] [-Recurse] [-Depth ] [-Force] [-Name] [-UseTransaction] [-Attributes ] [-Directory ] [-文件] [-隐藏] [-只读] [-系统] []

Get-ChildItem [[-Filter] ] -LiteralPath [-Include ] [-Exclude ] [-Recurse] [-Depth ] [-Force] [-Name] [-UseTransaction] [-Attributes ] [-Directory] ​​[-File ] [-隐藏] [-ReadOnly] [-系统] []

于 2014-11-11T00:43:06.830 回答
5

可悲的是,这是唯一的方法,根据 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
      )

有关参数集的详细信息,请参阅MSDN 库中的Cmdlet 参数集

于 2014-11-16T05:37:37.880 回答
4

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

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

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

由于每个任务都有自己不同的参数集,因此您的函数最终需要它们的笛卡尔积(Manual & XML、Auto & XML、Manual & path、Auto & path)。

每当您发现自己处于这些“笛卡尔积”参数情况之一时,这几乎总是表明您可以将一项功能移动到一个单独的函数中,并将新函数的结果作为原始函数的参数。在这种情况下,您可以将其拆分为New-ConnectionStringand 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>]

...

然后你这样称呼他们:

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

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

  • New-ConnectionString的返回值可用于任意数量的需要连接字符串的函数。
  • 如果他们愿意,调用者可以从其他来源获取连接字符串
  • New-ConnectionString如果呼叫者需要使用您未提供访问权限的功能,他们可以放弃您,转而自己做
于 2017-12-07T23:43:33.143 回答
0

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

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

Install-WidgetDataFromPath
Install-WidgetDataFromXml

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

于 2013-11-14T22:34:10.227 回答