假设我有一个带有多个函数的脚本,它们采用完全相同的参数,位于相同的位置,并且具有相同的类型和约束,如下所示:
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
块?如果没有,有什么替代品吗?
答案 0 :(得分:3)
如果你能够,我建议你选择“构建PowerShell模块的C#项目”方法。根据您的具体情况,有许多好处,其中包括:
要开始使用,我找到了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 }
}
这应该有效,除非参考命令也有动态参数。