我正在将我的一个标准功能转换为高级功能。该功能基本上与我公司的服务器对话,并返回我需要的有关我们产品的信息。目前它被编码为只扫描所有服务器,但我想将交换机添加到MyFunc -All将扫描所有服务器的位置,MyFunc -Single SERVERNAME将仅扫描该服务器,MyFunc -Help将显示有关该功能的信息。
我有这个功能,如果你把所有东西放在哪里,你应该工作正常。我遇到的问题是强制某人在运行该功能时在位置0输入一个开关。如果我在没有开关的情况下调用该函数,它会要求为“All”提供一个值。如果我将值保留为空或输入任何内容,则会收到错误消息“无法对参数'All'处理参数转换”。
这是我对高级功能的第一次尝试,所以我确定我错过了一些东西,但我认为有一种方法可以要求0位输入。
我正在寻找的例子(如果可能的话)
PS> MYFUNC
PS>“由于没有给出开关,我们被要求提供开关”
PS> -All或-Help或-Single SERVERNAME
PS>打印结果
function MyFunc
{
[CmdletBinding()]
PARAM(
[Parameter(Mandatory=$true, Position=0)]
[switch]$All,
[switch]$Help,
[switch]$Single,
[Parameter(ValueFromRemainingArguments=$true)]
[string]$ServerName
)
If($all)
{
$Servers = @("Server1",
"Server2",
"Server3",
"Server4",
"Server5")
#Check servers
}
elseif($Single)
{
$Servers = @($ServerName)
#Check server
}
elseif($Help)
{
#Print help message
}
}
答案 0 :(得分:1)
我建议您调用函数的方式进行一些更改并定义其参数。
首先,摆脱-Help
开关。 PowerShell有(非常好)帮助语义,你应该使用它们。为您的函数定义comment-based help,然后用户可以调用Get-Help MyFunc
或help MyFunc
并查看您所有的函数信息。最好的部分是,如果你想要的只是参数和需要哪些参数,你不必做任何事情;为您自动生成(继续尝试现在获取您的功能的帮助,没有任何更改)。
其次,我的建议是避免在函数中静态定义服务器(对于-All
)。只需要一个带有数组的-ServerName
参数,然后让你的函数检查其中的内容。 PowerShell在接受单个项目和数组时非常容易。使用高级功能,这也可以在管道上工作,只需最少的额外更改。
这将使您的功能只有一个参数,同时让它保持同样多样化。我的函数版本如下所示:
function MyFunc
{
[CmdletBinding()]
PARAM(
[Parameter(
ValueFromRemainingArguments=$true,
ValueFromPipeline=$true
)]
[string[]]
$ServerName
)
Process {
foreach ($server in $ServerName) {
# check this particular server
}
}
}
以下是您可以调用此功能的不同方法:
MyFunc 'SomeServer'
MyFunc 'Server4' 'Server5' 'Server6' # Spaces
MyFunc -ServerName 'ThisServer'
MyFunc -ServerName 'ThatServer','ThisServer','OtherServer'
'CoolServer' | MyFunc
'Server1','Server2','Server3' | MyFunc
该函数的调用者可以使用$PSDefaultParameterValues
预先定义服务器列表。
如果你真的想预先定义一个服务器列表,你可以将它们放在一个单独的文本文件中,每行一个,然后执行以下操作:
Get-Content -Path 'C:\List\Servers.txt' | MyFunc
这就是在你的职能中支持管道的美妙之处!
您还可以定义一个函数,为您提供列表,其实现可能会在以后更改:
function Get-DefaultServerList {
[CmdletBinding()]
param()
@(
'Server1'
'Server2'
'Server3'
)
}
然后你可以这样做:
Get-DefaultServerList | MyFunc
重点是什么?您可以稍后更改该函数的定义(例如)从文件,Web服务,注册表中获取其列表,等等。
答案 1 :(得分:1)
为briantist's helpful answer补充一些一般性建议:
要实现互斥参数,请使用参数集。
不要将[switch]
参数强制,除非它们用于选择(唯一暗示使用)一个已定义的参数集。向briantist求助的提示。
[switch]
es应可选(并且应始终默认为$False
,他们隐含地做了;)
换句话说:至少应该有一个不要求用户传递开关的参数集。使用基于评论的帮助可使您的高级功能不仅可以自动使用Get-Help
,还可以支持标准-?
参数来调用基本帮助(有关更详细的帮助,必须使用Get-Help
)。
尽可能避免使用ValueFromRemainingArguments
:PowerShell传递开放式相关值集的方法是使用数组参数,而是传递给它值以逗号分隔。
根据上述建议,这是您的功能的重写形式。
我已将-ServerName
参数更改为-ComputerName
以与标准cmdlet保持一致。
Briantist有一个关于不将服务器名称硬编码到函数中的观点,但我在这里是为了说明参数集的使用:
您 使用MyFunc
或至少调用1个服务器名称来调用-All
。
使用参数集可确保您不能同时执行这两项操作。
<#
.SYNOPSIS
One-line description.
.DESCRIPTION
More detailed description
.PARAMETER All
Targets all servers.
.PARAMETER ComputerName
The name(s) of the server(s) to targets.
.EXAMPLE
> MyFunc -All
#>
function MyFunc {
[CmdletBinding(DefaultParameterSetName='Given', PositionalBinding=$False)]
param(
[Parameter(ParameterSetName='Given', Position=0, Mandatory, ValueFromPipeline)]
[string[]] $ComputerName
,
[Parameter(ParameterSetName='All', Mandatory)]
[switch] $All
)
begin {
# If -All was specified, determine the set of servers.
if ($PSCmdlet.ParameterSetName -eq 'All') {
$ComputerName = 'Server1', 'Server2'
}
}
process {
foreach ($server in $ComputerName) {
$server # process each server
}
}
}