#powershell
Вопрос:
У меня около 20 файлов, каждый из которых содержит IP-адреса. У меня есть функция, которая загружает IP-адреса в правила, которые у меня есть в azure. Сценарий будет работать просто отлично, если запускать его по одному, но мне нужно, чтобы он был параллельным.
$i=1
foreach ($file in (gci . -name "auto_farm_protection_*") ){
Start-Job -ScriptBlock {
[string[]]$ipsarry = Get-Content $file
az network nsg rule update -g Testim --nsg-name sg-test -n "test_$i" --source-address-prefix $ipsarry
} -ArgumentList file,i
$i
}
Следует прочитать «test_1» и передать его, «test_2» и передать его и так далее.
По какой-то причине аргументы не передаются в start-job
часть, но я их использую -ArgumentsList
.
Ответ №1:
Вероятно, это быстрее с помощью start-threadjob из галереи powershell или foreach-object -parallel в powershell 7. Вам также понадобится полный путь к файлам, которые вы открываете, так как, к сожалению, задания используют каталог по умолчанию ~documents (у потоковых заданий этой проблемы нет). Я дважды процитировал команду az в качестве демонстрации, так как у меня ее нет.
# echo 192.168.1.1 > auto_farm_protection_a
# echo 192.168.1.2 > auto_farm_protection_b
# Install-Module -Name ThreadJob
$i=1
$result = foreach ($file in (gci . "auto_farm_protection_*") ){
Start-ThreadJob -ScriptBlock {
param($file, $i)
[string[]]$ipsarry = Get-Content $file.fullname
"az network nsg rule update -g Testim --nsg-name sg-test -n test_$i --source-address-prefix $ipsarry"
} -Argumentlist $file,$i
$i
}
$result | receive-job -wait -autoremove
az network nsg rule update -g Testim --nsg-name sg-test -n test_1 --source-address-prefix 192.168.1.1
az network nsg rule update -g Testim --nsg-name sg-test -n test_2 --source-address-prefix 192.168.1.2
Комментарии:
1. Большое спасибо
Ответ №2:
В вашем коде есть две ошибки. Первый из них находится в:
-ArgumentList file,i
Вы передаете литеральные строки «файл» и «я» в качестве аргументов, так как вы отсутствуете $
перед именами переменных.
Во-вторых, вы ссылаетесь на аргументы по имени из блока сценария, не объявив именованные параметры. Это можно исправить, добавив param( $file, $i )
строку в блок сценария.
Полное исправление:
$i=1
foreach ($file in (gci . -name "auto_farm_protection_*") ){
Start-Job -ScriptBlock {
param( $file, $i )
[string[]]$ipsarry = Get-Content $file.FullName
az network nsg rule update -g Testim --nsg-name sg-test -n "test_$i" --source-address-prefix $ipsarry
} -ArgumentList $file, $i
$i
}
Как вы заметили, модификатор области «использование:» намного проще в использовании, так как он делает параметры устаревшими:
$i=1
foreach ($file in (gci . -name "auto_farm_protection_*") ){
Start-Job -ScriptBlock {
[string[]]$ipsarry = Get-Content $using:file.FullName
az network nsg rule update -g Testim --nsg-name sg-test -n "test_$using:i" --source-address-prefix $ipsarry
}
$i
}
Комментарии:
1. для получения содержимого потребуется файл$. полное имя тоже, так как каталог заданий по умолчанию ~documents.
2. @js2010 Не требуется, так как
Get-Content
автоматически считываетFullName
поле приFileInfo
передаче объекта.3. gci -имя передает только строку.
4. @js2010 На самом деле приведенный выше код работает в ядре PS 7, но не работает в PS 5. См. Проблему с GitHub . Так что я добавлю
.FullName
на всякий случай.5. get-content -путь преобразуется в строки. Странно, что он получает полный путь в powershell 5.1 в заданиях. get-childitem-name вернет только строку, а не объект fileinfo.
Ответ №3:
По какой-то причине пришлось использовать $using:varname
Комментарии:
1. Блок сценариев
Start-Job
выполняется в своей собственной удаленной области. Эта область ничего не знает о вызывающей области, в которой$i
она определена.