在上次的介绍中我们主要介绍了Windows PowerShell V2 中高级函数的一些基础概念,在本次介绍中我们将要涉及的是如何使用高级函数达到类似cmdlet的使用体验(下面就以高级函数来称呼)。
首先还是让我们来看一下高级函数是如何构成的:
Function Test-AdvancedFunction
{
[CmdletBinding(SupportsShouldProcess=<Boolean>,
ConfirmImpact=<String>,
DefaultParameterSetName=<String>)]
Param ($Parameter1)
Begin{}
Process{}
End{}
}
大家一定注意到了最开始的CmdletBinding,接下来让我们来详细看下这个属性及它自身的一些成员属性(相关的帮助信息可以通过“help about_Functions_CmdletBindingAttribute”来查看)。
- SupportsShouldProcess
可选参数值为$True, $False。当设置为$True时,高级函数将支持通用参数-whatif以及-confirm。
- ConfirmImpact
可选参数值为High, Low, Medium, None。关于这个参数我们会在稍后通过代码实例说明。
- DefaultParameterSetName
代表默认的参数集名称。参数集就是我们在使用帮助命令时看到的语法内容,这部分内容将放在下次的介绍中进行说明。
为了与DynamicParam所定义的参数区别开来,我们姑且称有Param定义的参数为静态参数。接下来让我们来看下如何定义静态的参数。静态参数的定义本身并不复杂,复杂的地方在于如何选择参数的属性来达到自己想要的效果。下面给出相关参数属性的列表:
|
属性名
|
可选参数值
|
属性说明
|
|
Mandatory
|
$True, $False
|
指定参数是否是必要参数,强制用户输入
|
|
Position
|
整数
|
指定参数位置,如果用户没有指定具体参数名称,那么PowerShell将根据该值按序填充相应的参数
|
|
ParameterSetName
|
字符串
|
指定该参数属于哪个特定的参数集
|
|
ValueFromPipeline
|
$True, $False
|
是否接受来自管道中的值
|
|
ValueFromPipelineByPropertyName
|
$True, $False
|
是否接受来自管道中指定参数名的值
|
|
ValueFromRemainingArguments
|
$True, $False
|
是否接受来自管道中的剩余参数
|
|
HelpMessage
|
字符串
|
描述参数作用的帮助信息
|
|
Alias
|
字符串
|
指定参数的另一个名称
|
|
下面的参数是用来对用户输入的参数进行验证
|
|
AllowNull
|
无
|
允许对象为空
|
|
AllowEmptyString
|
无
|
允许字符串为空
|
|
AllowEmptyCollection
|
无
|
允许集合为空
|
|
ValidateCount
|
整数
|
检验可以接受的参数个数
|
|
ValidateLength
|
整数
|
检验参数的长度
|
|
ValidatePattern
|
正则表达式
|
使用正则表达式来检验参数
|
|
ValidateRange
|
整数范围
|
检验参数值是否在指定范围内
|
|
ValidateScript
|
表达式
|
使用代码来检验参数值
|
|
ValidateSet
|
集合
|
检验参数值是否在指定的属性集合中
|
|
ValidateNotNull
|
无
|
检验参数是否为非空对象
|
|
ValidateNotNullOrEmpty
|
无
|
检验参数是否为非空字符串
|
这里虽然给出了完整的可用参数属性列表,但并不是说我们每设置一个参数都要指定这么多属性,我们可以按需使用相应的属性。如果各位要查看如何使用具体每一个属性,可以参考这里。
接下来我将给出一段模拟计算器的示例代码,我们结合代码来看如何结合参数属性定义静态参数。
Function Test-Calc
{
[CmdletBinding(SupportsShouldProcess=$True,ConfirmImpact="none")]
Param
(
[ValidateRange(1,100)]
[parameter(Mandatory=$true,
Position=0,
HelpMessage="请输入数字1")]
[int]$Number1,
[parameter(Mandatory=$true,
Position=1,
HelpMessage="操作符")]
[ValidateSet("+","-","*","/","Max","Min")]
[string]$Operator,
[ValidateRange(1,100)]
[parameter(Mandatory=$true,
Position=2,
HelpMessage="请输入数字2")]
[int]$Number2
)
process
{
switch ($Operator)
{
"+" {$result = $Number1 + $Number2}
"-" {$result = $Number1 - $Number2}
"*" {$result = $Number1 * $Number2}
"/" {$result = $Number1 / $Number2}
"Min" {$result = [Math]::Min($Number1,$Number2)}
"Max" {$result = [Math]::Max($Number1,$Number2)}
}
}
end
{
Write-Host "Result : $Number1 $Operator $Number2 = $result"
}
}
首先Param后面使用的是小括号(),而不是花括号{},这点大家需要注意。其次我们有可能需要定义很多个参数,同时也会指定很多参数的属性,此时在注意合理换行的同时,也要注意括号匹配的问题。我们来看下这两个参数的定义:
[ValidateRange(1,100)]
[parameter(Mandatory=$true,
Position=0,
HelpMessage=
"请输入数字1")]
[int]$Number1,
[parameter(Mandatory=$true,
Position=1,
HelpMessage=
"操作符")]
[ValidateSet(
"+",
"-",
"*",
"/",
"Max",
"Min")]
[string]$Operator,
在最开始,我们对使用了用户参数进行验证的ValidateRange,它可以独立成行,并且使用中括号[]来定义。接着我们看到了Parameter,所有的参数属性都必须包含在Parameter后的()中,之间使用,分隔。最后我们定义参数的具体类型,同时我们需要注意不同参数之间也是用,进行分隔的,因此这里的,和不同括号可能非常让人头晕眼花,在定义的时候经常出错,所以大家定义的时候还需仔细。当然参数属性的部分,也可以写成这样:
[ValidateRange(1,100)]
[parameter(Mandatory=$true,Position=0,HelpMessage="请输入数字1")]
[int]$Number1,
[parameter(Mandatory=$true,Position=1,HelpMessage="操作符")]
[ValidateSet("+","-","*","/","Max","Min")]
[string]$Operator,
这样做的缺点也很明显,如果使用的参数属性较多或者参数属性值过长,会造成一行代码过长。因此这两种方法,大家可以视具体情况综合使用。
接下来就让我们来看看上面代码的测试效果。
1. Test-Calc 1 Max a(参数类型验证,参数位置验证)
2. Test-Calc(强制用户输入参数,显示帮助信息)
3. Test-Calc 10000 max 1(参数值范围验证)
以上内容就是如何使用Param在高级函数中定义静态参数,大家可以结合参数属性列表多练习下就能掌握了。接下来我们来看下开始说到的ConfirmImpact。
在PowerShell中,当用户执行的操作涉及到PowerShell自身之外的系统环境时,PowerShell将根据cmdlet中的相关设置来请求用户是否要继续操作。这里我们可以通过观察Stop-Process cmdlet来了解一二。首先,我们可以打开一个记事本程序,然后使用“Stop-Process notepad”来终止进程。然后大家再尝试下使用“Stop-Process winlogon”来终止winlogon进程。很明显当我们执行第二个命令的时候,PowerShell发出确认请求,询问用户是否要终止“winlogon”进程:
(这部分测试请在虚拟机下进行,如果没有任何提示确认是否要结束winlogon进程,而导致用户强制被注销进而使得您未保存的文件内容丢失的话,本人不负任何责任)
在PowerShell V1中,为了达到类似的效果,Jeffrey为我们写了一个专门的函数,当时PowerShell Team也承诺将在PowerShell V2中原生支持这个功能,而不需要额外编写函数来实现。这就是ConfirmImpact的由来。下面就让我们来看看如何使用。
Function Test-Output
{
[CmdletBinding(SupportsShouldProcess=$True,
ConfirmImpact="High")]
Param
(
[Parameter(Mandatory=$True,
Position=0)]
[string]$Path
)
Process
{
if($path -like "*system*")
{
if ($PSCmdlet.ShouldProcess($path))
{
Out-File -FilePath $path
}
}
}
}
我们可以看到ConfirmImpact的参数值被设置为High,表示该高级函数所执行的操作比较危险,需要谨慎操作。(当然示例中只是演示了往不同的路径写入一个文件)。
以上代码的作用是在指定路径下写入一个文件,但是我们在高级函数中将写入路径中包含System的定义为危险操作。需要在用户确认才执行写入操作,因此我们用到了$PSCmdlet对象的ShouldProcess方法。该方法的作用是显示提示信息,返回值是一个布尔值,因此我们使用if语句来进行判断、最终该方法能在PowerShell提示符中生成以下效果的选项,让用户进行选择。
接下来我们可以受用下面两条命令来测试ConfirmImpact设置为High时高级函数的执行效果:
Test-Output -Path c:\PowerShell\a.txt
Test-Output -Path c:\windows\System32\a.txt
然后是ConfirmImpact设置为none时的测试结果
.png" width="639" height="79" />
大家可以看到完全没有出现任何提示信息。当然细心的朋友可能会发ConfirmImpact还可以设置两个参数值Low和Medium,这两个值在什么时候发挥作用呢?这里我们需要介绍下自动变量$ConfirmPreference。在PowerShell会话中,高级函数在进行确认操作时默认会和自动变量$ConfirmPreference进行比较,如果发现高级函数中设置的ConfirmImpact等级高于$ConfirmPreference时就会发出提示,比如下面例子中高级函数中ConfirmImpact被设置为Medium,而$ConfirmPreference设置为Low,那么在高级函数执行危险操作时就会发出提示。
如果$ConfirmPreference的值低于ConfirmImpact的值(比如None< Low),那么,PowerShell就不会请求用户是否执行操作了。
本次介绍的内容比起上次的介绍可能一下子深入了很多,可能有些朋友理解起来有些难度。但是千万不要因此而放弃,高级函数是PowerShell中很重要的一块内容,多写写相关代码就会熟悉起来的。
本次的介绍就到此结束了,下次我们将介绍在高级函数中如何利用注释信息作为高级函数的帮助提供给Get-Help cmdlet使用以及如何使用动态参数,敬请期待!