是否可以重复使用' param'阻止多个功能?

时间:2014-11-13 14:08:22

标签: powershell parameters

假设我有一个带有多个函数的脚本,它们采用完全相同的参数,位于相同的位置,并且具有相同的类型和约束,如下所示:

function Verb1-MyValue {
    [CmdletBinding()]
    param (
        [parameter(Mandatory = $true)][String]$Param1,
        [parameter(Mandatory = $true)][String]$Param2,
        [ValidateSet("Value1","Value2")][String]$Param3 = "Value1"
    )
    # code ...
}

function Verb2-MyValue {
    [CmdletBinding()]
    param (
        [parameter(Mandatory = $true)][String]$Param1,
        [parameter(Mandatory = $true)][String]$Param2,
        [ValidateSet("Value1","Value2")][String]$Param3 = "Value1"
    )
    # code ...
}

# and so on ...

我希望与所有功能共享param块以避免潜在问题(它们需要对所有功能都相同)并避免冗余。

PowerShell中是否有一种方法可以在同一个脚本中跨多个函数共享param块?如果没有,有什么替代品吗?

2 个答案:

答案 0 :(得分:3)

如果你能够,我建议你选择“构建PowerShell模块的C#项目”方法。根据您的具体情况,有许多好处,其中包括:

  1. 编译时安全。我知道一些开发者会更喜欢 编译/强类型语言,因为增加了安全性
  2. 更容易编写自动化测试。这可能有争议,但在我的 意见,拥有像nUnit和其他测试框架这样的库 是一个巨大的优势
  3. 语言熟悉度。我遇到过很多 开发人员熟悉c#,但不熟悉powershell,所以他们 斗争。
  4. 要开始使用,我找到了this article。基本上,它表示将 System.Management.Automation.dll 的引用添加到项目中,然后一个非常基本的cmdlet如下所示:

    using System;
    using System.Collection.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.Management.Automation;
    
    namespace MyModule
    {
        [Cmdlet(VerbsCommon.Get, "Saluation")]
        public class GetSaluation : PSCmdlet
        {
            private string[] nameCollection;
    
            [Parameter(
                Mandatory = true,
                ValueFromPipelineByPropertyName = true,
                ValueFromPipelin = true,
                Position = 0,
                HelpMessage = "Name to get salutation for."
            )]
            [Alias("Person", "FirstName")]
            public string[] Name
            {
                get { return nameCollection;}
                set { nameCollection = value;}
            }
    
            protected override void BeginProcessing()
            {
                base.BeginProcessing();
            }
    
            protected override void ProcessRecord()
            {
                foreach (string name in nameCollection)
                {
                    WriteVerbose("Creating salutation for " + name);
                    string salutation = "Hello, " + name;
                    WriteObject(salutation);
                }
            }
    
            protected override void EndProcessing()
            {
                base.EndProcessing();
            }
    
        }
    

    然后,要使用此模块,请打开powershell提示符,导航到构建dll的位置并使用Import-Module cmdlet。

    然后针对您的具体问题(如何重用具有不同cmdlet的param块?),您可以拥有一个定义参数的基本cmdlet,并且您希望编写的所有cmdlet都可以继承来自基类。

答案 1 :(得分:2)

我建议使用Travis'建议并转到编译的cmdlet路由。你在其中一条评论中询问是否只使用脚本可以实现这一点,所以我将尝试提供一个这样做的例子。高级功能支持创建动态参数,您可以将该功能与Get-Command cmdlet结合使用,以创建指定命令参数的动态版本:

function GetDynamicParamDictionary {
    [CmdletBinding()]
    param(
        [Parameter(ValueFromPipeline=$true, Mandatory=$true)]
        [string] $CommandName
    )

    begin {
        # Get a list of params that should be ignored (they're common to all advanced functions)
        $CommonParameterNames = [System.Runtime.Serialization.FormatterServices]::GetUninitializedObject([type] [System.Management.Automation.Internal.CommonParameters]) | 
            Get-Member -MemberType Properties | 
            Select-Object -ExpandProperty Name
    }

    process {

        # Create the dictionary that this scriptblock will return:
        $DynParamDictionary = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary

        # Convert to object array and get rid of Common params:
        (Get-Command $CommandName | select -exp Parameters).GetEnumerator() | 
            Where-Object { $CommonParameterNames -notcontains $_.Key } |
            ForEach-Object {
                $DynamicParameter = New-Object System.Management.Automation.RuntimeDefinedParameter (
                    $_.Key,
                    $_.Value.ParameterType,
                    $_.Value.Attributes
                )
                $DynParamDictionary.Add($_.Key, $DynamicParameter)
            }

        # Return the dynamic parameters
        $DynParamDictionary
    }
}

function TestFunction {
    # Create some dummy params
    param(
        [string] $StringParam,
        [switch] $Switch1,
        [switch] $Switch2,
        [int] $IntParam
    )
}

function MimicTestFunction {
    [CmdletBinding()]
    # Empty param block (you could add extra params here)
    param()

    # Mimic TestFunction's parameters
    dynamicparam { GetDynamicParamDictionary TestFunction }
    process { $PSBoundParameters }
}

function MimicGetChildItem {
    [CmdletBinding()]
    param()

    dynamicparam { GetDynamicParamDictionary Get-ChildItem }
    process { $PSBoundParameters }
}

这应该有效,除非参考命令也有动态参数。