我正在编写一个函数,它基本上是一个它将调用的外部程序的便捷包装器。一些参数将被转发到外部程序,但不是全部。
我正在写
$ArgsToFwd = @()
switch ($PSBoundParameters.Keys) {
'--server' {$ArgsToFwd += @('--server',$server)}
'--userid' {$ArgsToFwd += @('--userid',$userid)}
...
}
Run Code Online (Sandbox Code Playgroud)
但后来我认为定义一个自定义参数属性可能会更好,它可以让我做类似的事情:
params(
[Parameter()]
[IsExternal()]
[string]$Server
)
#...
foreach ($key in $PSBoundParameters.Keys) {
if (<#a test for the custom [IsExternal] attribute#>) {
$ArgsToFwd += @($key, $PSBoundParameters[$key])
}
}
Run Code Online (Sandbox Code Playgroud)
但我不太明白。可以吗?
如果你想使用自定义属性,你需要做3件事:
Attribute类型让我们从第 1 步开始,定义一个继承自 的自定义类System.Attribute:
class ProxyParameterAttribute : Attribute
{
[string]$Target
ProxyParameterAttribute([string]$Target){
$this.Target = $Target
}
}
Run Code Online (Sandbox Code Playgroud)
属性注释直接映射回目标属性的构造函数,因此在本例中,我们将像使用它一样使用它[ProxyParameter('someValue')],'someValue'然后将其存储在$Target属性中。
现在我们可以继续步骤 2,用新属性装饰我们的参数。在块中应用它时,您可以省略Attribute名称的一部分param,PowerShell无论如何都希望所有注释都与属性相关:
function Invoke-SomeProgram
{
param(
[ProxyParameter('--server')]
[Parameter()]
[string]$Server
)
# ... code to resolve ProxyParameter goes here ...
}
Run Code Online (Sandbox Code Playgroud)
对于第 3 步,我们需要一段代码来发现当前命令参数上的属性注释,并使用它们将输入参数参数映射到适当的目标名称。
要发现当前命令声明的参数元数据,最佳入口点是$MyInvocation:
# Create an array to hold all the parameters you want to forward
$argumentsToFwd = @()
# Create mapping table for parameter names
$paramNameMapping = @{}
# Discover current command
$currentCommandInfo = $MyInvocation.MyCommand
# loop through all parameters, populate mapping table with target param names
foreach($param in $currentCommandInfo.Parameters.GetEnumerator()){
# attempt to discover any [ProxyParameter] attribute decorations
$proxyParamAttribute = $param.Value.Attributes.Where({$_.TypeId -eq [ProxyParamAttribute]}, 'First') |Select -First 1
if($proxyParamAttribute){
$paramNameMapping[$param.Name] = $proxyParamAttribute.Target
}
}
# now loop over all parameter arguments that were actually passed by the caller, populate argument array while taking ProxyParameter mapping into account
foreach($boundParam in $PSBoundParameters.GetEnumerator()){
$name = $boundParam.Name
$value = $boundParam.Value
if($paramNameMapping.ContainsKey[$name]){
$argumentsToFwd += $paramNameMapping[$name],$value
}
}
Run Code Online (Sandbox Code Playgroud)
现在参数已被适当过滤和重命名,您可以通过 splatting 使用正确的参数调用目标应用程序:
.\externalApp.exe @argumentsToFwd
Run Code Online (Sandbox Code Playgroud)
把它们放在一起,你最终会得到类似的结果:
class ProxyParameterAttribute : Attribute
{
[string]$Target
ProxyParameterAttribute([string]$Target){
$this.Target = $Target
}
}
function Invoke-SomeProgram
{
param(
[ProxyParameter('--server')]
[Parameter()]
[string]$Server
)
# Create an array to hold all the parameters you want to forward
$argumentsToFwd = @()
# Create mapping table for parameter names
$paramNameMapping = @{}
# Discover current command
$currentCommandInfo = $MyInvocation.MyCommand
# loop through all parameters, populate mapping table with target param names
foreach($param in $currentCommandInfo.Parameters.GetEnumerator()){
# attempt to discover any [ProxyParameter] attribute decorations
$proxyParamAttribute = $param.Value.Attributes.Where({$_.TypeId -eq [ProxyParamAttribute]}, 'First') |Select -First 1
if($proxyParamAttribute){
$paramNameMapping[$param.Name] = $proxyParamAttribute.Target
}
}
# now loop over all parameter arguments that were actually passed by the caller, populate argument array while taking ProxyParameter mapping into account
foreach($boundParam in $PSBoundParameters.GetEnumerator()){
$name = $boundParam.Name
$value = $boundParam.Value
if($paramNameMapping.ContainsKey[$name]){
$argumentsToFwd += $paramNameMapping[$name],$value
}
}
externalApp.exe @argumentsToFwd
}
Run Code Online (Sandbox Code Playgroud)
您可以向属性添加其他属性和构造函数参数以存储更多/不同的数据(例如,指示某物是否只是一个开关或转换输入值的脚本块的标志)。
如果您需要对多个不同的命令执行此操作,请将步骤 3 的逻辑(发现属性和解析参数名称)提取到单独的函数中,或将其封装在属性类的静态方法中。
| 归档时间: |
|
| 查看次数: |
208 次 |
| 最近记录: |