PowerShell: Invoke-Command с Try/Catch и добавлением во внешний массив

Вопрос или проблема

Как добавить компьютер в массив в пределах Invoke-Command с использованием оператора try/catch?

У меня есть следующий код, который не ведет себя так, как я ожидаю:

$IisServers = "Server1","Server2","Server3"
$Action = "remove"
$FileName = "iisstart.htm"

If ($Action -eq "remove") {
    "`n`r*** НАСТРОЙКА IIS НА УДАЛЕННЫХ КОМПЬЮТЕРАХ ***" #| Tee-Object -Append $LogFile
    # Запуск команды настройки на массиве - Результаты будут приходить несортированными из-за параллельной обработки invoke-command
    Invoke-Command -ComputerName $IisServers -ErrorAction stop {
        Try {
            # Импорт модуля PowerShell (необходимо только для серверов Win 2k8r2)
            Import-Module WebAdministration
            # Удаление имени файла из списка, если оно существует
            If (Get-WebConfiguration -PSPath 'MACHINE/WEBROOT/APPHOST' -Filter 'system.webServer/defaultDocument/files/add' | Where-Object {$_.value -eq $Using:FileName}) {
                Remove-webconfigurationproperty /system.webServer/defaultDocument -name files -atElement @{value=$Using:Filename}
                Write-Output "$Env:ComputerName`: '$Using:FileName' удалено из списка документов по умолчанию"
                }
            Else {
                Write-Output "$Env:ComputerName`: '$Using:FileName' не существует в списке документов по умолчанию"
                }
            }
        Catch {
            $ErrorMessage = $_.Exception.Message
            Write-Output "$Env:ComputerName`: $ErrorMessage" 
            $ExecutionIssues += $Env:ComputerName
            }
        $props = @{ComputerName=$ExecutionIssues}
        New-Object -Type PSObject -Prop $Props
        } #| Tee-Object -Append $LogFile
    }
  • Цикл If/Else игнорируется, и каждый раз при запуске просто выполняется секция If независимо.
  • Try/Catch, похоже, работает для выполнения команд ошибок If, но аргумент “ErrorAction Stop” останавливает сценарий на первой ошибке подключения WinRM, с которой он сталкивается, вместо логирования и продолжения с остальными.
  • Ничего не добавляется в переменную $ExecutionIssues в случае ошибки.

Я что-то очевидное упустил?

Ответ Кита в следующем посте дал мне подходящее решение:

https://stackoverflow.com/questions/12600921/handle-errors-in-scriptblock-in-invoke-command-cmdlet

Использование этого без оператора try/catch решило все вышеуказанные проблемы.

Ответ или решение

Теория

Когда вы работаете с PowerShell и используете Invoke-Command, важно правильно организовать обработку ошибок и управление данными. Особенно если вы параллельно отправляете команды на несколько удалённых серверов, как в вашем случае с $IisServers. Для управления ошибками обычно используют конструкцию Try/Catch, чтобы перехватывать и обрабатывать исключения. Однако в вашем случае ErrorAction Stop останавливает выполнение скрипта при первой же ошибке, что мешает обработке других серверов. Также важно правильно инициализировать и использовать переменные, такие как $ExecutionIssues, чтобы накапливать данные об ошибках.

Пример

Рассмотрим ваш код:

Invoke-Command -ComputerName $IisServers -ErrorAction stop {
    Try {
        Import-Module WebAdministration
        If (Get-WebConfiguration -PSPath 'MACHINE/WEBROOT/APPHOST' -Filter 'system.webServer/defaultDocument/files/add' | Where-Object {$_.value -eq $Using:FileName}) {
            Remove-webconfigurationproperty /system.webServer/defaultDocument -name files -atElement @{value=$Using:Filename}
            Write-Output "$Env:ComputerName`: '$Using:FileName' removed from Default Document list"
        } Else {
            Write-Output "$Env:ComputerName`: '$Using:FileName' doesn't exist in Default Document list"
        }
    } Catch {
        $ErrorMessage = $_.Exception.Message
        Write-Output "$Env:ComputerName`: $ErrorMessage" 
        $ExecutionIssues += $Env:ComputerName
    }
    $props = @{ComputerName=$ExecutionIssues}
    New-Object -Type PSObject -Prop $Props
}

Применение

  1. Обработка ошибок: Вместо того чтобы останавливать скрипт при ошибке с помощью ErrorAction Stop, лучше использовать Continue и регистрировать ошибки в переменной. Измените ErrorAction или удалите его.
  2. Инициализация переменных: Убедитесь, что переменная $ExecutionIssues инициализирована как массив вне Invoke-Command, чтобы к ней можно было добавлять данные:
    $ExecutionIssues = @()
  3. Использование массива: Добавление данных в массив лучше производить с помощью подходящих методов. Внутри Invoke-Command правильно накопите имена компьютеров с проблемами:
    Catch {
        $ErrorMessage = $_.Exception.Message
        Write-Output "$Env:ComputerName`: $ErrorMessage"
        $ExecutionIssues = $ExecutionIssues + $Using:Env:ComputerName
    }
  4. Корректная работа с выводом: Если необходимо возвращать объекты с информацией, убедитесь, что они создаются и возвращаются правильно.

Таким образом, вы сможете корректно обрабатывать ошибки и накапливать нужные данные в массиве, обеспечив параллельное выполнение на всех серверах из $IisServers. Если у вас остались вопросы или требуются дополнительные пояснения, рассмотрите использование -ErrorVariable для накопления ошибок на уровне cmdlet, чтобы глубже разобраться в механике работы ошибок в PowerShell.

Оцените материал
Добавить комментарий

Капча загружается...