На сайте клиента мы используем службы Windows Server Update Services (WSUS) для развертывания обновлений продуктов на компьютерах в сети. Прежде чем служба WSUS установит обновления продуктов, необходимо вручную утвердить их для установки или включить режим автоматического утверждения, в котором нельзя выбирать устанавливаемые обновления (устанавливаются все). .

Работа ApproveUpdates.ps1 начинается с загрузки файла RequiredUpdates.txt, содержащего заголовок каждого обновления, как показано на экране. После проверки содержимого текстового файла выполняется инициализация счетчиков и файлов журналов. Сценарий записывает данные в пять журналов: found.log, expired.log, approved.log, failed.log и missing.log.

 

Экран. Тестовый файл RequiredUpdates.txt

Затем сценарий ApproveUpdates.ps1 загружает сборку Microsoft.UpdateServices.Administration, которая обеспечивает использование API-интерфейса Windows.NET Framework для подключения к серверу WSUS. В частности, метод Get UpdateServer класса AdminProxy передает интерфейс (с типом данных IUpdate Server) в сервер WSUS и вносит этот интерфейс в переменную $UpdateServer.

Интерфейс IUpdateServer используется для выполнения двух важных задач, как показано в листинге. Сначала сценарий задействует метод GetComputerTargetGroups класса IUpdateServer, чтобы получить глобально уникальный идентификатор (GUID) группы компьютеров, для которого утверждаются обновления (в данном случае группа All Computers). В переменную $TargetGroup вводится ссылка на эту группу компьютеров. Затем с помощью метода GetUpdates класса IUpdateServer переменная $updates заполняется коллекцией новейших версий обновлений из базы данных WSUS, в том числе замененных и отклоненных.

Для каждого обновления продукта в этой коллекции сценарий ApproveUpdates.ps1 ищет совпадение в файле RequiredUpdates.txt. Если совпадение обнаружено, обновление записывается в журнал found.log. Затем сценарий проверяет, не истек ли срок действия обновления. Просроченные обновления заносятся в журнал expired.log, остальные отмечаются как утвержденные для установки в службе WSUS. Если эта операция выполняется успешно, сценарий добавляет обновление в журнал approved.log; если она завершается неудачей, обновление вносится в журнал failed.log.

Проверив коллекцию, ApproveUpdates.ps1 сравнивает список обнаруженных обновлений в журнале found.log со списком требуемых обновлений в файле RequiredUpdates.txt. Если обновление присутствует в файле RequiredUpdates.txt, но не в found.log, значит, обновления нет на сервере WSUS. Все отсутствующие обновления записываются в журнал missing.log.

Наконец, сценарий отображает результаты. Их также можно искать в файлах журналов.

Пользователи службы WSUS, желающие опробовать ApproveUpdates.ps1, могут ознакомиться с его кодом в листинге. Сценарий нужно запускать из каталога, в котором расположен файл RequiredUpdates.txt.

М. Самер Савас — системный администратор в компании Datel Systems and Software. Имеет сертификаты MCSE и MCTS, специализируется на работе с Active Directory, развертывании и управлении системами

Листинг. Сценарий ApproveUpdates.ps1
# FileName: ApproveUpdates.ps1
# Created: [04/26/2010], Author: M.Samer Sawas
# Requirments:  -Powershell version 2.0; -Must run on local WSUS server (not remote);
#  -Before running this script, change to the directory where the updates text file (RequiredUpdates.txt) is located
# Purpose: Approve updates for install to All Computers group, updates titles are stored in a text file
# When multiple updates have the same title, the script tries to approve all of them verify updates file
if (!(Test-Path -Path RequiredUpdates.txt)) {Write-Host "The updates file RequiredUpdates.txt is not located in the current directory !!!";break}
# Read required updates from file into $ReqUpdatesFile and verify that it's not empty
$ReqUpdatesFile = Get-Content "RequiredUpdates.txt"
if ($ReqUpdatesFile -eq $null) {Write-Host "The updates file is empty !!!";break}
# initialize variables and log files
$UpdatesCount = 0 # all updates in WSUS database
$FailedCount = 0 # updates with failed approval
$ApprovedCount = 0 # updates with succeeded approval
$FoundCount = 0  # matches (required updates found in WSUS database)
$MissingCount = 0  # missing updates (required updates not found in WSUS database)
$ExpiredCount = 0 # required updates found to be expired in WSUS database)
$ApprovalSucceeded = $True
Set-content Found.log $null
Set-Content Missing.log $null
Set-content Failed.log $null
Set-content Approved.log $null
Set-content Expired.log $null
# Load WSUS administration
[System.Reflection.Assembly]::LoadWithPartialName('Microsoft.UpdateServices.Administration') | out-null
# Connect to WSUS server
$updateServer = [Microsoft.UpdateServices.Administration.AdminProxy]::GetUpdateServer()
# Get the computer group ID for "All Computers" group
$updateServer.GetComputerTargetGroups() | foreach-object {
                if ($_.Name  -eq  "All Computers") {$TargetGroupID = $_.id;}
               }
$TargetGroup  = $updateServer.GetComputerTargetGroup($TargetGroupID)
# Get updates from WSUS server
$updates = $updateServer.GetUpdates()
# loop through updates for approval
foreach ($update in $updates)
{
    if ($ReqUpdatesFile –contains $update.Title )
 {
  $FoundCount = $FoundCount + 1
  $updateGuid = $update.id.UpdateId # Obtain update GUID
     $UpdateTitleAndGUID = [string]::Concat($update.Title,"-GUID:",$updateGuid) # GUID is attached to title to uniquely identify updates
     add-content Found.log $UpdateTitleAndGUID # Log found updates
 
  if ($update.PublicationState -eq [Microsoft.UpdateServices.Administration.PublicationState]::Expired)
  { $ExpiredCount = $ExpiredCount + 1;add-content Expired.log $UpdateTitleAndGUID }
  else
  {
  Try{$update.Approve("Install",$TargetGroup) | out-null}
  Catch # executes when approval failes
   {
   $ApprovalSucceeded = $False
   add-content Failed.log $([string]::Concat($UpdateTitleAndGUID,", reason:",$($_.Exception.Message)))
   add-content Failed.log "------------------------------------"
   $FailedCount = $FailedCount + 1
   }
        Finally {if ($ApprovalSucceeded) {add-content Approved.log $UpdateTitleAndGUID;$ApprovedCount = $ApprovedCount + 1}
                 else {$ApprovalSucceeded = $True } }
  }           
 }        
    $UpdatesCount = $UpdatesCount + 1
}
# Find missing updates
foreach ($ReqUpdate in $ReqUpdatesFile)
{
if (!(select-string -path Found.log -pattern $ReqUpdate -quiet -simplematch))
    {add-content Missing.log $ReqUpdate;$MissingCount = $MissingCount +1}
}
Function ReportUpdates($count,$state,$LogFile)
{
if ($Count -gt 0)
 {
 write-host $Count "update(s)" $state ":" -foregroundcolor «yellow»
 write-host «===============================================»
 Get-Content -path $LogFile | sort-object
 write-host
 }
else
 {
  write-host "No updates" $state -foregroundcolor "yellow"
  write-host «===============================================»
  write-host
 }
}
ReportUpdates $MissingCount "Missing from WSUS Database" "missing.log"
ReportUpdates $FoundCount "Found in WSUS Database" "Found.log"
ReportUpdates $FailedCount "failed approval" "Failed.log"
ReportUpdates $ExpiredCount "expired" "expired.log"
ReportUpdates $ApprovedCount "Approved successfully" "Approved.log"
write-host "Total number of updates processed: " $UpdatesCount -foregroundcolor "yellow"