我定义了以下ScriptBlock:
[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工作。
答案 0 :(得分:3)
问题是 Invoke 方法接受一组参数(类似于具有 -ArgumentList 参数的命令),因此解析了数组中的每个元素作为一个单独的论点。第一个参数'String11'
被分配给第一个postitional参数 $ 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
}
答案 1 :(得分:1)
如果我理解你在做什么,你想要取两个数组,连接它们,并确保它们的独特性......
首先,由于参数上有[Parameter...]
,因此您可以在方法上获得[CmdletBinding()]
。这意味着您将自动将$ Modules拆分为多个调用。
其次,ScriptBlock.Invoke()接受一个params样式数组,并将它们作为单独的参数放入方法中。
我要尝试的第一件事是添加属性来收集所有值:
[Parameter(ValueFromRemainingArguments=$true, Position=0, Mandatory=$true)]
[String[]]$Modules
但是,对于Join,您可以更轻松地执行以下操作:
($modules + $defaultModules) | Select -Unique
答案 2 :(得分:0)
不确定原因,但它似乎不喜欢那个命名参数。似乎喜欢$ 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