Сценарий Powershell циклически перемещается по машинам, но зависает, если кто-то временно отключается от сети

#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:

Хм, это действительно Проблема.

Вы могли бы поэкспериментировать с:

Таким образом, у вас будет больше контроля над тем, что делают процессы. Вы запускаете фоновые задания с помощью Start-Job. Запуск-Задание возвращает объекты задания Обратно -> сохранить их в массиве или переменных

С помощью Get-Job вы видите все текущие запущенные задания

с помощью Receive-Job вы возвращаете результат работы, полученный до сих пор. Вы можете использовать receive-Job, чтобы вернуть все PSObjects, написанные фоновым заданием.

Не могу объяснить подробно, но это была бы еще одна попытка, которую я бы сделал для этой работы.