#powershell
Вопрос:
У меня есть скрипт powershell, который анализирует txt-файл, полный имен машин, затем один за другим создает сеанс в системе, выполняет несколько команд и переходит к следующей системе. Выполнение сценария обычно занимает около 10-30 секунд в каждой системе в зависимости от случая, с которым столкнулся сценарий.
Время от времени система, которая в настоящее время проверяется, по какой-либо причине теряет сетевое соединение. Когда это происходит, консоль начинает писать желтые предупреждающие сообщения о попытке повторного подключения в течение 4 минут, а затем отключает сеанс, когда он не может подключиться. Даже если он снова установит соединение в течение 4 минут, после этого он ничего не сделает, как будто сценарий просто зависает. Он не перейдет к следующей системе и не остановит сценарий, я должен остановить его вручную, или, если я запущу сценарий вручную, я могу нажать control c, чтобы выйти из текущего цикла, а затем он перейдет к следующей машине в списке.
Есть ли какой-либо способ выйти из текущего цикла, если возникнет предупреждение, чтобы оно могло перейти на следующую машину? Это было бы моим идеальным решением. Спасибо!
Сценарий прост..
foreach($server in Get-Content .machines.txt) {
if($server -match $regex){
invoke-command $server -ErrorAction SilentlyContinue -ScriptBlock{
command1
command2
command3
}
}
вот что происходит
PS C:temp> .script.ps1
machine1
machine2
machine3
machine4
machine5
WARNING: The network connection to machine5 has been interrupted. Attempting to reconnect for up to 4 minutes...
WARNING: Attempting to reconnect to machine5 ...
WARNING: Attempting to reconnect to machine5 ...
WARNING: Attempting to reconnect to machine5 ...
WARNING: The network connection to machine5 has been restored.
Но это никогда не переходит в машину6
Комментарии:
1. Может быть, проще позволить
Invoke-Command
управлять этим.$Servers=Get-Content .machines.txt|Where{$_ -match $regex};Invoke-Command $Servers -ea SilentlyContinue -ScriptBlock {...
2. Спасибо.. проверим это, но вы думаете, что это решит проблему здесь? не уверен, что это действительно что-то меняет
3. Взгляните
-warningaction
наinvoke-command
это , возможно, стоит позволить ему потерпеть неудачу или продолжить, чтобы он мог продолжить обработку остальных4. пробовал -Предупреждающее действие:Остановитесь , но, к сожалению, это не сработало
Ответ №1:
Когда я работаю удаленно с несколькими машинами, я обычно запускаю процессы на машинах параллельно. Таким образом, я оказываю меньшее влияние, когда отдельные машины выходят из строя. Для этого я использую функцию powershell 7 для параллельной работы с каждым объектом https://devblogs.microsoft.com/powershell/powershell-foreach-object-parallel — особенность/
Попробуйте что-нибудь вроде этого:
$Credential=Get-Credential
#all Necessary parameters must be in the Object i give to ForEach Object
$myHosts = @(
#Hosts i want to connect to with values i want to use in the loop
@{Name="probook";cred=$Credential;param1="one_1";param2="two_1"}
@{Name="probook";cred=$Credential;param1="one_2";param2="two_2"}
)
$var1="one"
$var2="two"
$myHosts | ForEach-Object -Parallel {
#Variables outside of this "Parallel" Loop are not available. Because this is startet as separate SubProcess
#All Values come from the Object i piped in the ForEach-Object
$myHost=$_
#This is written to your local Shell
Write-Host ("Computer: " $env:Computername)
Write-Host $myHost.param1
Write-Host $myHost.param2
Write-Host $myHost.cred.UserName
Invoke-Command -ComputerName $myHost.Name -Credential $myHost.cred -ArgumentList @($myHost.param1,$myHost.param2) -ScriptBlock {
#Variables outside of of this Invoke Command Script Block are not available because this is a new Remote-Shell on the remote Host
#Parameters in Ordner of -Argument List
param($param1,$param2)
#Do your things on the Remote-Host here
#This is not Visbible -> it is only written on the "remote Shell"
Write-Host $env:Computername
#Here you get Back Values from the remote Shell
$env:Computername
$param1
$param2
}
} -ThrottleLimit 5
Комментарии:
1. проблема в том, что у меня каждая машина последовательно записывает данные в csv-файл, и когда все машины отчитываются, я затем манипулирую CSV-файлом и отправляю его по электронной почте. если я запущу все параллельно, то как я узнаю, когда все будет сделано, чтобы затем отправить csv-файл по электронной почте?
Ответ №2:
Хм, это действительно Проблема.
Вы могли бы поэкспериментировать с:
- Начало работы (https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/start-job?view=powershell-7.1)
- Устроиться на работу (https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/get-job?view=powershell-7.1)
- Получить-Работу (https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/receive-job?view=powershell-7.1)
Таким образом, у вас будет больше контроля над тем, что делают процессы. Вы запускаете фоновые задания с помощью Start-Job. Запуск-Задание возвращает объекты задания Обратно -> сохранить их в массиве или переменных
С помощью Get-Job вы видите все текущие запущенные задания
с помощью Receive-Job вы возвращаете результат работы, полученный до сих пор. Вы можете использовать receive-Job, чтобы вернуть все PSObjects, написанные фоновым заданием.
Не могу объяснить подробно, но это была бы еще одна попытка, которую я бы сделал для этой работы.