Предложения, необходимые для потока сценариев Powershell - PullRequest
0 голосов
/ 22 марта 2012

Я администратор Microsoft System Center Configuration Manager. Я управляю около 4000 рабочих станций Windows, состоящих из комбинации Win7 и XP. Я отвечаю за хранение обновлений программного обеспечения на этих рабочих станциях и за периодическое развертывание программного обеспечения.

К сожалению, не было никакого реального стандарта для конфигурации этих клиентов, поэтому, когда возникает проблема, которая не позволяет мне переместить программное обеспечение к одному, обычно это один экземпляр. Я устал все время ремонтировать эти рабочие станции вручную, поэтому решил создать чудовищный скрипт Powershell, чтобы исправить все мелкие проблемы.

В настоящее время сценарий запускается из центрального расположения и синхронно подключается ко всем этим рабочим станциям (идут задания Powershell). Этот набор функций и логики выходит из-под контроля. Я продолжаю добавлять к нему каждый раз, когда нахожу другую проблему, из-за которой она становится неуправляемой.

Сначала я назову проблему, скажем, "сломанный WMI". Затем я создаю функции Test-BrokenWmi, Get-BrokenWmi и Fix-BrokenWmi, например. Эти функции входят в один из моих модулей и вызываются из основного скрипта.

В этом случае основной сценарий имеет параметры только для поиска проблем или их устранения в зависимости от переданных ему параметров. Вот фрагмент. Есть ли лучший способ сделать это, чтобы я мог легко добавить эти проверки? Чтобы сделать вещи более сложными, некоторые проверки имеют зависимости, например, вы не можете получить что-либо от WMI, если он на самом деле не работает.

param($ComputerName,[bool]$Remediate)

Write-Debug 'Starting script...'
$oPc = New-Object System.Object;
$oPc | Add-Member -Type NoteProperty -Name Name -Value $ComputerName;

try {
    if (!(Test-BrokenWmi $ComputerName)) {
        throw 'WMI is broken';
    } elseif (!(Test-ServiceNotStarted $ComputerName)) {
        throw 'Service not started';
    } elseif (............) {
      .....continue more elseifs
    ## Client looks to be OK since it didn't catch any health checks
    } else {
      $oPc | Add-Member -Type NoteProperty -Name TestResult -Value 'Healthy';
      $oPc | Add-Member -Type NoteProperty -Name RemediationAttempt -Value 'N/A';
  $oPc | Add-Member -Type NoteProperty -Name RemediationResult -Value 'N/A';
  return $oPc
    }
} catch [system.exception] {
    $problemfound = $_.Exception.Message;
    $oPc | Add-Member -type NoteProperty -Name TestResult -Value $problemfound;
    if (!$Remediate) {
        $oPc | Add-Member -Type NoteProperty -Name RemediationAttempt -Value 'TestOnlyMode';
    $oPc | Add-Member -Type NoteProperty -Name RemediationResult -Value 'TestOnlyMode';
    return $oPc;
     } else {
        try {
             switch ($problemfound) {
                  'WMI is broken' {
                      $oPc | Add-Member -Type NoteProperty -Name RemediationAttempt -Value 'Fix WMI';
                       throw Fix-Wmi $ComputerName
                  } 'Service is stopped' {
                      $oPc | Add-Member -Type NoteProperty -Name RemediationAttempt -Value 'Start service';
                      throw Fix-Service $ComputerName
                   }
              }
          } catch [system.exception] {
              if ($_.Exception.Message -eq $false) {
                   $oPc | Add-Member -Type NoteProperty -Name RemediationResult -Value 'Failed';
              } elseif ($_.Exception.Message -eq $true) {
           $oPc | Add-Member -Type NoteProperty -Name RemediationResult -Value 'Succeeded';
      } else {
        $oPc | Add-Member -Type NoteProperty -Name RemediationResult -Value $_.Exception.Message;
      }##endif
      return $oPc;
          }
     }
}

}

1 Ответ

1 голос
/ 22 марта 2012

Вот мое мнение, FWIW. Сначала обменяйте этот объект на упорядоченную хеш-таблицу до конца.

function new-test {($computername)
$oPc = new-object collections.specialized.ordereddictionary
$oPc.computername = $computername
}

Это версия V2. В V3 вы сможете сделать

$opc = [ordered]@{}
$oPc.computername = $computername

Затем измените свои функции, чтобы взять это из конвейера. При каждом тесте добавьте его имя в таблицу вместе с результатом:

$oPc.TestBrokeWMI = "Fail"

Это намного проще, чем добавить элемент к объекту.

Затем передайте весь объект по конвейеру.

Для тестов, которые имеют зависимости, проверьте, есть ли в хэш-таблице ключ для зависимости и значение «Пропущено».

Создайте функцию для использования в конце для преобразования хеш-таблицы в объект, чтобы у вас было что-то удобное для работы с форматированием или экспортом Опять же, в V3 вы сможете просто сделать

new-object -property $oPc

и он будет работать с заказанным хеш-таблицей. Вы захотите использовать упорядоченную хеш-таблицу, чтобы тесты оставались в том порядке, в котором они были выполнены в результирующем объекте.

Тогда ваш тестовый стек начинает выглядеть так:

'Computer1' | New-Test | 
 Test-BrokenWmi | Get-BrokenWmi | Fix-BrokenWmi |
 Test-ServiceNotStarted | TestServiceStart |
 | New-TestResult
...