什么是 [cmdletbinding()] 以及它是如何工作的?

Posted

技术标签:

【中文标题】什么是 [cmdletbinding()] 以及它是如何工作的?【英文标题】:What is [cmdletbinding()] and how does it work? 【发布时间】:2013-01-18 05:26:08 【问题描述】:

根据get-help about_Functions_CmdletBindingAttribute

CmdletBinding 属性是函数的一个属性,使它们像编译的 cmdlet 一样运行

我们可以在脚本顶部使用它。这种情况下的功能是什么? PowerShell 引擎为其所有输入调用的内部隐式“main”函数?

关于这个语法:

[CmdletBinding(ConfirmImpact=<String>,
                     DefaultParameterSetName=<String>,
                     HelpURI=<URI>,
                     SupportsPaging=<Boolean>,
                     SupportsShouldProcess=<Boolean>,
                     PositionalBinding=<Boolean>)]

我们在做什么?实例化cmdlbinding 对象并将参数列表传递给它的构造函数?此语法可在 param() 中找到 - 例如:[Parameter(ValueFromPipeline=$true)]。此语法是否有特定名称,是否可以在其他地方找到?

最后,作为简单的 PowerShellers,我们是否能够模仿此功能并通过设置属性来修改脚本的行为?

【问题讨论】:

我猜这里的文档有点误导:所有这些都与任何类型的脚本块有关:正如 Shay 所提到的 - 以函数名、路径(脚本)命名,但 未命名,例如&amp; [CmdletBinding()]param() Write-Verbose 'Foo' -Verbose 像冠军一样工作。 @BartekB 感谢您提出问题的第一部分。 【参考方案1】:

一般来说,CmdletBinding 是将函数变成高级函数的原因。将它放在脚本的顶部会使脚本成为“高级”脚本。函数和脚本大体相同,脚本文件名相当于函数名,脚本内容相当于函数的scriptblock部分。

CmdletBinding 属性让您可以控制函数功能,例如添加 Confirm 和 WhatIf 支持(通过 SupportsShouldProcess)、禁用参数位置绑定等。

【讨论】:

"其中脚本文件名等同于函数名,脚本内容等同于函数的 scriptblock 部分" 这在上下文中是什么意思?例如,如果我在每个 param 部分之前继承了一个包含 Functions 和 [CmdletBinding()] 的单个文件,这与脚本文件名有什么关系?是吗?【参考方案2】:

CmdletBinding、Parameter 等是脚本编写者可以用来定义 PowerShell 行为的特殊属性类,例如使用 Cmdlet 功能使函数成为高级函数。

当您通过例如呼叫他们时[CmdletBinding()] 你初始化了一个新的类实例。

阅读更多关于 CmdletBindingAttribute 类的信息:MSDN

阅读更多关于 ParameterAttribute 类的信息:MSDN

更多关于属性类here和here

【讨论】:

好的。因此,当使用完整语法时,我们将哈希表传递给构造函数,用于设置公共成员值? 在某种程度上。哈希表由 ; 分隔。我认为这是 PowerShell 进程可以使用的一种特殊类型的类和构造方式。你可以把它想象成例如new Question Text = "Some question" ; 在 c# 中我猜。如果你想知道它是如何工作的,你可以尝试反编译我的 MSDN 链接中指定的库,看看它是否可读。 是的那种哈希表:)。 添加了一些关于属性类的链接,解释了如何创建和使用它。从System.Attribute 或其他东西继承的特殊类。我只是将学习脚本作为一种爱好,所以我远不是这方面的专家 :) @System.Collections.Hashtable类型,它实现了System.Collections.IDictionaryHashtable 自 1.1 以来一直在 .NET 中。 C# 中的等价物:new Hashtable "key1", "value1" , "key2", "value2" , 【参考方案3】:

关于语法问题,格式与您在 C# 中使用命名参数将 .NET 属性类应用于成员的方式非常匹配。

比较The PowerShell Language Specification 的B.2.4 部分与C# Language Specification 的C.2.13 部分的属性的(简化)语法:

B.2.4 属性 (PowerShell)

属性:[ attribute-name ( attribute-arguments ) ]

属性参数:  属性参数  属性参数 , 属性参数

属性参数:  简单名称 = 表达式


C.2.13 属性 (C#)

属性:[ attribute-name ( named-argument-list ) ]

named-argument-list: named-argument  named-argument-list , named-argument

named-argument: 标识符 = attribute-argument-expression


我同意从概念上的简洁感到例如重用哈希表初始化语法进行属性初始化。但是,我可以想象支持哈希表中的所有选项(如 [A(P=v)][A('P'=v)]$n = 'P'; [A($n=v)] 等,或它们的某些特定子集)只是使用 ; 作为分隔符会比这是值得的。

另一方面,如果你想使用高级函数,那么学习高级语法也许是有意义的:)

【讨论】:

属性不支持哈希表语法,因为它们不处理普通的键和值。键对应于扩展 System.Attribute 的类中定义明确的属性。 @Zenexer:这是支持类 C# 语法的参数,但不会对语言施加限制。同样,我可以定义一个哈希表$h = @ foo = 2 并使用$h.foo 属性语法访问该元素,即使该哈希表实际上没有“foo”属性。在一种情况下,语言设计者选择了灵活的语法,而在另一种情况下,他们选择支持更简单的语法。 当然涉及到一定程度的语言设计,但请记住,PowerShell 位于 .NET 之上。 PowerShell 属性是 .NET 属性,因此它们必须遵循 .NET 属性规则。当然可以扩展 .NET 属性并提供特定于 PowerShell 的版本,但由于 PowerShell 的性质,必须有一种方法来定义 .NET 属性。 我认为我们在谈论两个不同的事情 :) 我的答案集中在语法上:语言用来实例化 Attribute 对象的文本形式是什么(在这种情况下,@987654340 @ + '=' + value),而您的注意力似乎集中在属性类型本身的特性上。我同意支持哈希表或任意 PSObjects 而不是简单的 Attributes 是不必要的,并且无论您是否可以编写 "name"=value 而不是 name=value,这都不会改变 name 必须引用可分配属性的事实属性。

以上是关于什么是 [cmdletbinding()] 以及它是如何工作的?的主要内容,如果未能解决你的问题,请参考以下文章

跟踪 Windows 进程退出代码

检测并卸载防病毒软件

TFS中的Robocopy构建PowerShell步骤报告失败但没有错误

测试路径:路径中的非法字符

为啥脚本化的 cmdlet 被列为函数?

什么是 Android 上下文以及为什么需要它 [重复]