PowerShell/CLI: цикл Foreach с несколькими массивами

У меня есть сценарий PowerCLI, который выключает виртуальную машину, изменяет ее память и процессор, а затем снова включает ее. Я адаптировал скрипт для использования переменных. Это все работает отлично.

Сейчас я пытаюсь изменить сценарий для использования массивов, чтобы циклически переключаться между многочисленными виртуальными машинами. Части сценария, которые выключают и включают виртуальные машины, работают отлично.

У меня возникла проблема с использованием переменных из двух массивов в цикле foreach.

Для каждой виртуальной машины в $vm_name мне нужно установить соответствующий объем памяти, найденный в $memory_gb.

Это то, что у меня есть (в настоящее время он устанавливает одинаковый объем памяти («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

... Я пытался вложить второй цикл foreach внутри первого, но безрезультатно.

Как написать сценарий, чтобы каждая виртуальная машина в $vm_name получала соответствующий объем памяти, найденный в $memory_gb?


person James McCallister    schedule 07.08.2014    source источник


Ответы (5)


У вас есть 2 варианта. Во-первых (и не то, что я бы предложил) это цикл 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}
person TheMadTechnician    schedule 07.08.2014
comment
Поместить его в файл данных довольно умно, снимаю шляпу. - person JensG; 08.08.2014
comment
Это сработало отлично. Благодарю вас! Я, безусловно, буду использовать .CSV, так как со временем буду модифицировать множество машин. - person James McCallister; 08.08.2014
comment
Это сработало, но я получил эту ошибку.... Set-VM: невозможно привязать параметр «MemoryGB» к цели. Параметр исключения MemoryGB: ссылка на объект не указывает на экземпляр объекта. В U:\How To\PowerCLI\Test.ps1:8 char: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 Поскольку это сработало, имеет ли значение ошибка? - person James McCallister; 08.08.2014
comment
Вероятно, это потому, что я использовал -le вместо -lt, поэтому он пытался повторить 4-й набор виртуальных машин/памяти. Я действительно ожидал, что вы воспользуетесь вторым вариантом, поэтому я не уделял должного внимания первому. Я скоро обновлю ответ, чтобы исправить это. - person TheMadTechnician; 08.08.2014

Вы можете использовать функцию 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
person Marek Toman    schedule 12.01.2015
comment
Ничего себе, я должен был понять, как это работает. - person js2010; 30.12.2020
comment
@ js2010, чтобы прояснить это для будущих читателей: синтаксис $x, $a1 = $a1 распаковывает следующий элемент массива вместо сохранения ручного итератора $i или подобного - person Maximilian Burszley; 12.04.2021

Другим, более компактным решением является использование хеш-таблицы:

$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 
}
person Raf    schedule 08.08.2014
comment
Это также сработало для меня. Спасибо! Я не рассматривал использование хеш-таблицы. - person James McCallister; 08.08.2014

$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
}

Это будет работать до тех пор, пока два массива имеют одинаковый размер.

person thepi    schedule 22.11.2017
comment
Вы, сэр, джентльмен и ученый, я не мог понять, как передать две переменные типа массива в цикл foreach без того, чтобы он каждый раз выполнял каждый элемент массива для других элементов массива. так что то, что должно было выполнить 4 цикла, делало 16. Но эта часть спасла меня: [$vm_name.indexof($objItem)] - person moore1emu; 25.10.2018
comment
Index of - довольно умное решение. - person nethero; 03.12.2019

$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 
}

Вам просто нужно убедиться, что оба массива имеют одинаковую длину.

person JensG    schedule 07.08.2014
comment
@JamesMcCallister: я польщен, но на ТАК спасибо обычно выражается в голосовании и/или принятии лучшего ответа :-) - person JensG; 08.08.2014