PowerShell/CLI: "Foreach" 循环使用多个数组

8
我有一个PowerCLI脚本,可以关闭虚拟机,更改其内存和CPU,然后重新启动。我已经改编了该脚本以利用变量。这一切都完美地运行。
现在,我正在尝试修改脚本以利用数组,以便循环遍历多个虚拟机。关闭和打开虚拟机的脚本部分完美地工作。
我遇到的问题是在foreach循环中使用两个数组中的变量。
对于$vm_name中的每个VM,我需要设置在$memory_gb中找到的相应内存量。
这就是我所拥有的(它目前为所有VM设置相同的内存量(“1”))...
$vm_name = @("OMAC-SBXWIN7AJM", "OMAC-SBXWIN2012R2AJM", "OMAC-SBXWIN2008R2AJM")
$memory_gb = 2,4,4

# SET THE VM MEMORY
Write-Host 'NOW SETTING THE VM MEMORY'
foreach ($objItem in $vm_name)
{Set-VM -VM $vm_name -MemoryGB 1 -confirm:$false 
Break
}

http://i.stack.imgur.com/E9hfY.png

...我已经尝试在第一个循环中嵌套第二个循环,但没有成功。

如何编写脚本,使$vm_name中的每个虚拟机都获得$memory_gb中相应的内存量?

5个回答

6
您可以使用Zip功能:
function Zip($a1, $a2) {
    while ($a1) {
        $x, $a1 = $a1
        $y, $a2 = $a2
        [tuple]::Create($x, $y)
    }
}

使用方法:

zip 'a','b','c' 1,2,3 |% {$_.item1 + $_.item2}

结果:

a1
b2
c3

@js2010 为了方便未来的读者,这里需要澄清一下:$x, $a1 = $a1 的语法是用于解包数组的下一个成员,而不是保留手动迭代器 $i 或类似的东西。 - Maximilian Burszley

6

你有两个选择。第一个选择(不是我建议的)是使用For()循环。代码如下:

For($I=0;$I -lt $vm_name.count;$I++){
    Set-VM -VM $vm_name[$I] -MemoryGB $memory_gb[$I] -confirm:$false
}

更好的方法是将其放入带有标题的 CSV 中,例如VMName,Memory,然后列出每个虚拟机和您想要的内存。 然后运行类似以下的内容:
Import-CSV C:\Path\To\File.CSV | ForEach{Set-VM -VM $_.VMName -MemoryGB $_.memory -confirm:$false}

将其放入数据文件中非常聪明,致敬。 - JensG
这个完美地运行了。谢谢!我肯定会使用 .CSV,因为我最终将修改许多机器。 - James McCallister
这个可以工作,但是我得到了这个错误...Set-VM: 无法将参数'MemoryGB'绑定到目标。设置"MemoryGB"时出现异常: "对象引用未设置为对象的实例。" 在U:\How To\PowerCLI\Test.ps1的第8行第36个字符:
  • Set-VM -VM $vm_name[$i] -MemoryGB $memory_gb[$i] -confirm:$false
  • ~~~~~~~~~~~~~~
    • CategoryInfo : WriteError: (:) [Set-VM], ParameterBindingExcept ion
    • FullyQualifiedErrorId : ParameterBindingFailed,VMware.VimAutomation.ViCo re.Cmdlets.Commands.SetVM
既然它能工作,那么这个错误真的重要吗?
- James McCallister
这可能是因为我使用了-le而不是-lt,所以它试图迭代第四个VM/内存集。我真的希望你能使用第二个选项,所以我没有像应该注意第一个选项那样仔细看。我会很快更新答案来纠正这个问题。 - TheMadTechnician

4
$vm_name = @("OMAC-SBXWIN7AJM", "OMAC-SBXWIN2012R2AJM", "OMAC-
SBXWIN2008R2AJM")
$memory_gb = 2,4,4

# SET THE VM MEMORY
Write-Host 'NOW SETTING THE VM MEMORY'
foreach ($objItem in $vm_name)
{
    Set-VM -VM $vm_name -MemoryGB $memory_gb[$vm_name.indexOf($objItem)] -confirm:$false 
    Break
}

只要这两个数组大小相同,这将起作用。

1
您是位绅士和学者,我无法想出如何将两个数组类型变量传递给foreach循环,而不是每次都对另一个数组项执行每个数组项。因此,本应运行4个循环的内容正在运行16个循环。但是,这部分代码 [$vm_name.indexof($objItem)] 拯救了我。 - moore1emu
索引是一个相当聪明的解决方案。 - nethero

3
另外一种更紧凑的解决方案是使用哈希表:
$vms = @{"OMAC-SBXWIN7AJM" = 2; "OMAC-SBXWIN2012R2AJM" = 4; "OMAC-SBXWIN2008R2AJM" = 4}

# SET THE VM MEMORY
Write-Host 'NOW SETTING THE VM MEMORY'
foreach ($vm in $vms.getEnumerator()){
    Set-VM -VM $vm.Name -MemoryGB $vm.Value -confirm:$false 
}

这对我也起作用了。谢谢!我之前没有考虑使用哈希表。 - James McCallister

1
$vm_name = @("OMAC-SBXWIN7AJM", "OMAC-SBXWIN2012R2AJM", "OMAC-SBXWIN2008R2AJM")
$memory_gb = (2,4,4)

# SET THE VM MEMORY
Write-Host 'NOW SETTING THE VM MEMORY'
for( $i = 0; $i -lt $vm_name.length; $i++) {
  $vm = $vm_name[$i]
  $gb = $memory_gb[$i]
  write-host setting $vm to $gb GB ...
  Set-VM -VM $vm -MemoryGB $gb -confirm:$false 
}

你只需要确保这两个数组具有相同的长度。

@JamesMcCallister:我很受宠若惊,但在SO上,感谢通常是通过点赞和/或接受最佳答案来表达的 :-) - JensG

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接