Powershell 脚本块截断数组上的Invoke方法
我已定义以下脚本块:Powershell 脚本块截断数组上的Invoke方法,powershell,Powershell,我已定义以下脚本块: [ScriptBlock]$strSb = { param( [Parameter(Mandatory=$false,Position=0)] [String[]]$Modules = @('String3','String4') ) Write-Host "Passed in params:" foreach($m in $Modules){ Write-Host $m } $
[ScriptBlock]$strSb = {
param(
[Parameter(Mandatory=$false,Position=0)]
[String[]]$Modules = @('String3','String4')
)
Write-Host "Passed in params:"
foreach($m in $Modules){
Write-Host $m
}
$defaultModules = @('String3','String4')
# Add Default Modules back if not present #
foreach($module in $defaultModules){
if($Modules -notcontains $module){
$Modules += $module
}
}
Write-Host "Final set:"
# Load Dependencies #
foreach($m in $Modules){
Write-Host $m
}
}
正如ScriptBlock中的参数所述,我希望能够传入一个字符串数组。当我调用$strSb.Invoke(@('String11','String12'))
时,我收到以下消息:
Passed in params:
String11
Final set:
String11
String3
String4
我所期望的是:
Passed in params:
String11
String12
Final set:
String11
String12
String3
String4
为什么invoke方法会将数组截断为输入的第一项?我该如何处理它,以便传入一个字符串数组
FWIW:我在v2和v3中工作。不确定确切原因,但它似乎不喜欢那个命名参数。似乎喜欢$args,tho:
[ScriptBlock]$strSb = {
$Modules = $args
Write-Host "Passed in params:"
foreach($m in $modules){
Write-Host $m
}
$defaultModules = @('String3','String4')
# Add Default Modules back if not present #
foreach($module in $defaultModules){
if($Modules -notcontains $module){
$Modules += $module
}
}
Write-Host "Final set:"
# Load Dependencies #
foreach($m in $Modules){
Write-Host $m
}
}
$strSb.Invoke('String11','String12')
Passed in params:
String11
String12
Final set:
String11
String12
String3
String4
不确定确切原因,但它似乎不喜欢那个命名参数。似乎喜欢$args,tho:
[ScriptBlock]$strSb = {
$Modules = $args
Write-Host "Passed in params:"
foreach($m in $modules){
Write-Host $m
}
$defaultModules = @('String3','String4')
# Add Default Modules back if not present #
foreach($module in $defaultModules){
if($Modules -notcontains $module){
$Modules += $module
}
}
Write-Host "Final set:"
# Load Dependencies #
foreach($m in $Modules){
Write-Host $m
}
}
$strSb.Invoke('String11','String12')
Passed in params:
String11
String12
Final set:
String11
String12
String3
String4
如果我理解你在做什么,你需要2个数组,连接它们,并确保唯一性 首先,由于您的参数上有一个
[Parameter…]
,因此您神奇地在方法上获得了[CmdletBinding()]
。这意味着您将自动将$Modules拆分为多个调用
其次,ScriptBlock.Invoke()接受一个params样式的数组,并将它们作为单独的参数放入方法中
我要尝试的第一件事是添加属性以收集所有值:
[Parameter(ValueFromRemainingArguments=$true, Position=0, Mandatory=$true)]
[String[]]$Modules
但是,对于Join,您可以更轻松地执行以下操作:
($modules + $defaultModules) | Select -Unique
如果我理解你在做什么,你需要2个数组,连接它们,并确保唯一性 首先,由于您的参数上有一个
[Parameter…]
,因此您神奇地在方法上获得了[CmdletBinding()]
。这意味着您将自动将$Modules拆分为多个调用
其次,ScriptBlock.Invoke()接受一个params样式的数组,并将它们作为单独的参数放入方法中
我要尝试的第一件事是添加属性以收集所有值:
[Parameter(ValueFromRemainingArguments=$true, Position=0, Mandatory=$true)]
[String[]]$Modules
但是,对于Join,您可以更轻松地执行以下操作:
($modules + $defaultModules) | Select -Unique
问题是,Invoke方法接受一个参数数组(类似于具有-ArgumentList参数的命令),因此数组中的每个元素都被解析为一个单独的参数。第一个参数
'String11'
,被分配给第一个位置参数$Modules,任何后续参数都将被丢弃,因为没有更多的位置参数。$Modules声明为字符串数组并不重要;由于参数列表中的每个元素都是一个单独的参数,因此将$Modules设置为一个元素的数组
如果使用,
运算符指示传入的是单个数组参数,则它将按预期工作:
$strSb.Invoke((,@('String11','String12')))
顺便说一句,您并不真正需要@
,因为默认情况下,逗号分隔的字符串列表被解释为数组。不仅在这一特定背景下,而且在一般情况下。所以只要用这个:
$strSb.Invoke((,('String11','String12')))
要验证上述解释,请尝试此脚本块,除了声明第二个参数(创造性地命名为$SecondParameter)并在显示第一个参数值的循环后显示外,其他都是相同的:
[ScriptBlock]$strSb = {
param(
[Parameter(Mandatory=$false,Position=0)]
[String[]]$Modules = @('String3','String4'),
[String]$SecondParameter
)
Write-Host "Passed in params:"
foreach($m in $Modules){
Write-Host $m
}
Write-Host "`nSecondParameter: $SecondParameter`n"
$defaultModules = @('String3','String4')
# Add Default Modules back if not present #
foreach($module in $defaultModules){
if($Modules -notcontains $module){
$Modules += $module
}
}
Write-Host "Final set:"
# Load Dependencies #
foreach($m in $Modules){
Write-Host $m
}
}
如果随后按原样传入参数,$strSb.Invoke(@('String11','String12'))
,则会得到以下结果:
11-26-13 19:02:12.55 D:\Scratch\soscratch» $strSb.Invoke(@('String11','String12'))
Passed in params:
String11
SecondParameter: String12
Final set:
String11
String3
String4
11-26-13 19:02:29.34 D:\Scratch\soscratch»
最后一个与问题没有直接关系的提示是,您可以使用管道压缩foreach循环,这不仅更加简洁,而且通常效率更高。以下是您的代码的压缩版本:
[ScriptBlock]$strSb = {
param(
[Parameter(Mandatory=$false,Position=0)]
[String[]]$Modules = ('String3','String4')
)
Write-Host "Passed in params:"
$Modules | Write-Host
$defaultModules = 'String3','String4'
# Add Default Modules back if not present #
$defaultModules | ?{$Modules -notcontains $_} | %{$Modules += $_}
Write-Host "Final set:"
# Load Dependencies #
$Modules | Write-Host
}
问题是,Invoke方法接受一个参数数组(类似于具有-ArgumentList参数的命令),因此数组中的每个元素都被解析为一个单独的参数。第一个参数
'String11'
,被分配给第一个位置参数$Modules,任何后续参数都将被丢弃,因为没有更多的位置参数。$Modules声明为字符串数组并不重要;由于参数列表中的每个元素都是一个单独的参数,因此将$Modules设置为一个元素的数组
如果使用,
运算符指示传入的是单个数组参数,则它将按预期工作:
$strSb.Invoke((,@('String11','String12')))
顺便说一句,您并不真正需要@
,因为默认情况下,逗号分隔的字符串列表被解释为数组。不仅在这一特定背景下,而且在一般情况下。所以只要用这个:
$strSb.Invoke((,('String11','String12')))
要验证上述解释,请尝试此脚本块,除了声明第二个参数(创造性地命名为$SecondParameter)并在显示第一个参数值的循环后显示外,其他都是相同的:
[ScriptBlock]$strSb = {
param(
[Parameter(Mandatory=$false,Position=0)]
[String[]]$Modules = @('String3','String4'),
[String]$SecondParameter
)
Write-Host "Passed in params:"
foreach($m in $Modules){
Write-Host $m
}
Write-Host "`nSecondParameter: $SecondParameter`n"
$defaultModules = @('String3','String4')
# Add Default Modules back if not present #
foreach($module in $defaultModules){
if($Modules -notcontains $module){
$Modules += $module
}
}
Write-Host "Final set:"
# Load Dependencies #
foreach($m in $Modules){
Write-Host $m
}
}
如果随后按原样传入参数,$strSb.Invoke(@('String11','String12'))
,则会得到以下结果:
11-26-13 19:02:12.55 D:\Scratch\soscratch» $strSb.Invoke(@('String11','String12'))
Passed in params:
String11
SecondParameter: String12
Final set:
String11
String3
String4
11-26-13 19:02:29.34 D:\Scratch\soscratch»
最后一个与问题没有直接关系的提示是,您可以使用管道压缩foreach循环,这不仅更加简洁,而且通常效率更高。以下是您的代码的压缩版本:
[ScriptBlock]$strSb = {
param(
[Parameter(Mandatory=$false,Position=0)]
[String[]]$Modules = ('String3','String4')
)
Write-Host "Passed in params:"
$Modules | Write-Host
$defaultModules = 'String3','String4'
# Add Default Modules back if not present #
$defaultModules | ?{$Modules -notcontains $_} | %{$Modules += $_}
Write-Host "Final set:"
# Load Dependencies #
$Modules | Write-Host
}
谢谢这就是我要找的。我的持续调查使我相信它将数组视为参数列表。这回答了如何让它将数组视为参数。这将需要我几天来确认这是工作。当我做的时候,我会把这个标记为答案。谢谢!这就是我要找的。我的持续调查使我相信它将数组视为参数列表。这回答了如何让它将数组视为参数。这将需要我几天来确认这是工作。当我这样做时,我会将此标记为答案。感谢您的建议,但是由于某些原因,
来自RemaingArguments的值不起作用。它仍然只使用第一个值。我最终还是使用了加入建议