我正在编写一个cmdlet(在PowerShell中),负责将记录写入数据库。使用条件命令行,似乎我必须定义四个不同的参数集。
有没有更有成效的方法呢?
详情
cmdlet的参数是:
ComputerName
(要连接的SQL服务器)Path
(数据的位置)Xml
(原始数据本身)UserName
Password
UseIntegratedSecurity
(而不是用户名/密码,请使用当前凭据) Path
和Xml
是互斥的,UserName
/ Password
和UseIntegratedSecurity
是互斥的。
为了正确连接,似乎我必须定义四个不同的参数集,例如:
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,
)
答案 0 :(得分:8)
如果您想对参数集进行快速完整性检查,可以使用Show-Command
这将显示一个包含多个选项卡的表单,每个选项卡对应一个选项卡。例如:
Show-Command Get-ChildItem
将显示:
或者;如果您想要命令行替代方案,可以使用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,手动和路径,自动和路径)。
任何时候你发现自己身处其中一种"笛卡尔产品"参数情况,它几乎总是一个标志,你可以将一个功能移动到一个单独的功能,并使新功能的结果成为原始参数。在这种情况下,您可以将其拆分为New-ConnectionString
和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
自行支持答案 3 :(得分:0)
嗯,这是最简洁的方式。更简洁然后是开关/案例的恐怖,或者if / then陷阱来解释所有可能的参数集!
但是,您的另一个选择是为互斥参数集编写不同的命令,例如
Install-WidgetDataFromPath
Install-WidgetDataFromXml
如果您只使用脚本文件,两者都可以调用Install-WidgetData
脚本命令行开关,您可以将其隐藏在模块中,或者使用范围修饰符将其隐藏在全局范围内。内部命令行开关可以为两个(或更多)面向用户的包装器实现共享代码。从你的代码来看,我认为你不需要解释如何实现它。