我正在尝试编写一些代码,这些代码需要检查函数元数据并根据命令的参数处理一些其他数据。在此过程中,我发现了一些我无法理解的非常奇怪的行为。
我在 psm1 脚本模块中有一个函数,它是通过导入将其声明为嵌套模块的相邻 psd1 模块 list 来加载的。我已经明确声明了 14 个参数。当我 Get-Command
并检查 Parameters
时,我可以看到它有 23 个参数。 14个是我的;其余的是 common parameters .
PS> (Get-Command Install-MyFunctionFromModule).Parameters.Count
23
PS> (Get-Command Install-MyFunctionFromModule).Parameters.keys
MyParameter1
MyParameter2
MyParameter3
MyParameter4
MyParameter5
MyParameter6
MyParameter7
MyParameter8
MyParameter9
MyParameter10
MyParameter11
MyParameter12
MyParameter13
MyParameter14
Verbose
Debug
ErrorAction
WarningAction
ErrorVariable
WarningVariable
OutVariable
OutBuffer
PipelineVariable
(我的函数名称确实以Install-
开头。不过,我的参数不以数字结尾。这些只是虚拟占位符,因为我不想使用真实姓名。)
这是意料之中的事情。函数应该有共同的参数。
但是为了测试处理参数的代码,我尝试创建一个测试模块。这是它的样子:
testfun.psm1
:
$ErrorActionPreference = 'Stop'
Set-StrictMode -Version Latest
function test-noparams() {
Write-Host 'None'
}
function test-differentnamedparams([string]$hello, [switch]$bye) {
Write-Host "names that don't conflict with common params"
}
然后当我导入模块时,两个函数都没有任何公共(public)参数:
PS> Import-Module .\testfunc.psm1
PS> (Get-Command test-differentnamedparams).Parameters.Count
2
PS> (Get-Command test-differentnamedparams).Parameters | Format-Table -AutoSize
Key Value
--- -----
hello System.Management.Automation.ParameterMetadata
bye System.Management.Automation.ParameterMetadata
PS> (Get-Command test-noparams).Parameters.Count
0
我已经尝试了一些方法,看看它们是否有所不同:
- 使用
Export-ModuleMember
显式导出函数 - 使用将脚本模块导入为
NestedModule
的 list
- 使用脚本并通过
包含它。 .\testfunc.ps1
而不是模块 - 直接在 shell 中定义函数
他们都没有改变任何东西。
什么决定了一个函数是否有公共(public)参数?什么会导致他们不这样做?
最佳答案
仅advanced functions or scripts支持common parameters .
使脚本/函数成为高级函数的显式方法是用 param(...)
block 装饰 < strong>[CmdletBinding()]
属性。
然而,作为jpmc26他自己发现,使用每个参数 [Parameter()]
属性隐式地使脚本或函数更高级。
- 但是,请注意每个参数的属性 other
[Parameter()]
- 例如[AllowNull()]
或[Alias()]
- 自己不制作脚本/函数和高级函数。
一种发现给定脚本/函数是否高级(支持通用参数)的简单方法是将其名称传递给Get-Help
:
# Define a NON-advanced function - no [CmdletBinding()] or [Parameter()] attributes.
PS> function foo { param([string] $bar) 'hi' }; Get-Help foo
NAME
foo
SYNTAX
foo [[-bar] <string>]
ALIASES
None
REMARKS
None
# Define an ADVANCED function EXPLICITLY - note the [CmdletBinding()] attribute
# BEFORE the param(...) block.
PS> function foo { [CmdletBinding()] param([string] $bar) 'hi' }; Get-Help foo
NAME
foo
SYNTAX
foo [[-bar] <string>] [<CommonParameters>]
ALIASES
None
REMARKS
None
# Define an ADVANCED function IMPLICITLY - note the [Parameter(Mandatory)] attribute
# FOR PARAMETER $bar.
PS> function foo { param([Parameter(Mandatory)] [string] $bar) 'hi' }; Get-Help foo
NAME
foo
SYNTAX
foo [[-bar] <string>] [<CommonParameters>]
ALIASES
None
REMARKS
None
可选阅读:陷阱:名称与通用参数的冲突
从 PSv5.1 开始:
jpmc26还发现,如果您不小心声明了一个名称与通用参数名称冲突的参数,您在定义函数时不会收到错误,但只会在稍后调用它,包括将其传递给 Get-Help
:
# Define advanced function that mistakenly names a a parameter for
# a common parameter:
PS> function foo { [CmdletBinding()] param([string] $Verbose) 'hi' }
# NO error is reported at this point.
# Later invocation of the function, including introspection of its parameters
# when you pass it to Get-Help, then surfaces the problem:
PS> Get-Help foo
Get-Help : A parameter with the name 'Verbose' was defined multiple times for the command.
At line:1 char:1
+ Get-Help foo
+ ~~~~~~~~~~~~
+ CategoryInfo : MetadataError: (:) [Get-Help], MetadataException
+ FullyQualifiedErrorId : ParameterNameAlreadyExistsForCommand,Microsoft.PowerShell.Commands.GetHelpCommand
关于function - 为什么我的函数没有公共(public)参数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42591569/