Approval of WSUS updates: import, export, copy

the Backstory


Until recently, I worked as edikasyon a major Russian company that has many offices throughout the country. In my jurisdiction there were eleven sites, located in different cities of the Far East (this is important). In each of these offices had its own, not connected with other network infrastructure — your domain AD own subnet, etc.

Once the leadership gave me the task to organize the automatic updating of the OS and programs from MS and allowed to expand on accountable sites WSUS.

Problem


After WSUS was deployed, binding policy, computers to WSUS groups are configured, the directory synchronization content server MS held, etc., the question arose: who and how will approve the update?

Imagine 11 cities that are so "fast" and "stable", that rare moment when latency of ICMP replies are only 800 MS, are perceived as unheard of luck. And in each you test all updates before deploying. The access to the servers at the sites was only via RDP, ie, had weekly (available to set exactly the same frequency) to connect to the server of each city and manually approve the use of new updates to a test group and, accordingly, to translate the updates tested in commercial operation:
image


Why reinvent the wheel


The reader, having experience with WSUS, probably, will ask: and in what actually a problem? Microsoft had it all planned: there is a replication mechanism, in which the "subordinate" (subordinate) server called "replica", downloads the update files and information about which updates have been approved for use in certain groups.

Really, it is. However, in this case, using the standard mechanism did not work, because it requires a wide enough channel between the root server and its replicas. I have such a channel was not. But it was the instruction that under no circumstances not to increase the cost of it.

the Idea


"No, no!" I thought and started to figure out how to get out of this situation. First, each of the WSUS servers or otherwise had access to the servers WindowsUpdate from MS or to a local WSUS servers, providers, or the WSUS servers neighbors in the office, etc. ie they were where to download the update files, it was only required to specify which updates you want to download. Second, I was allowed to use Powershell.

The idea was simple: you must implement a mechanism of import / export data on what the updates were approved. According to an old tradition, formed in the days at University, I decided to export in a simple XML file. The structure of this file turned out like this:
the
<Groups>
<!-- The name of the computer group, which includes the following updates -->
<gWSUS_wks_test>
<!-- The first update (Update) -->
<Update>
<!-- The product to which the update -->
<UpdateProduct>Windows XP</UpdateProduct>
<!-- Article on this update in the knowledge base MS -->
<UpdateKB>815021</UpdateKB>
<!-- Test description for update -->
<UpdateDescription>An identified security vulnerability in Microsoft Windows NT 4.0, Windows 2000, and Windows XP could allow an attacker to take control of the computer. This issue is most likely to affect computers used as web servers. You can help protect your computer from this and other identified issues by installing this update from Microsoft. After you install this item, you may have to restart your computer.</UpdateDescription>
<!-- Unique update ID -->
<UpdateID>4aed463b-3a3b-4ad8-976e-17baf6434da2</UpdateID>

<UpdateIsDeclined>False</UpdateIsDeclined>
<!-- Can a client refuse this update -->
<UpdateApprovalIsOptional>False</UpdateApprovalIsOptional>
<!-- Date of completion of installation (after the onset of the installation of this update will not be executed) -->
<UpdateApprovalDeadLine>12/31/9999 23:59:59</UpdateApprovalDeadLine>
<!-- The action that you want to approve (in this case launcher) -->
<UpdateApprovalAction>Install</UpdateApprovalAction>
</Update> 
</gWSUS_wks_test>
</Groups>


The scenario of using the said mechanism can be summarized as follows:
    the
  1. Administrator (or trusted helper) to its network approves some updates for use in certain groups, make sure that all is well, and uploads the file with information about which ones need to be applied to the different groups of computers, for example, on internal WEB-site;
  2. the
  3. Anycast in place (I, for example) configures the script which downloads generated by the administrator does in 1. file and loads its contents into the local database WSUS;
  4. the
  5. in the presence of several disconnected WSUS servers in the area of responsibility of anyadike — p. 2 runs multiple times


What this does in the end? First, anycast not decide what updates to approve, and what — not: this decision is made by a qualified system administrator, able to reasonably predict the impact of each update on used in the curves the original design, apparently, depend heavily on the specific bugs undocumented features of the OS, SQL server and MS Office.

Second, anycast can't be wrong (forget the need to approve the update, accidentally approve unnecessary, etc.)

Thirdly, the administrator receives a guarantee that all networks of the company approved to install the same updates (i.e. the question "which version of office is in Zamchische?" becomes irrelevant).

In addition to exports approvals required the transfer mechanism tested in the test groups updates on "combat". Preferably, a single button / command "approve everything that is not prohibited and is approved for use in the test group." This is necessary in order to avoid getting untested updates into production in a consequence of errors of the contractor ("Oh, not approved, not hit back!").

Implementation of


Code

Spending some time looking for ready-made solutions, and not finding such, I delved deep into the documentation for WSUS API, Powershell and .NET.

First I had to find out how to access the objects that allow to manipulate the WSUS server. For this you need to load the appropriate Assembly:
[reflection.assembly]::LoadWithPartialName("Microsoft.UpdateServices.Administration")|out-null


After that, create a function that would return an object that represents a WSUS server installed locally:
the
<#
.SYNOPSIS 
Returns an instance of the server object, WSUS
.DESCRIPTION
To create the object using a local (the one running the script), the WSUS server
.OUTPUTS
An object of type IUpdateServer representing a local WSUS server
#>
Function Get-WsusServerInstance()
{ 
#Global variable $Script:WSUS is used to "cache" the result.
$WSUSServer = $Script:WSUS
#Get a reference to the current instance of the WSUS server.
if ($WSUSServer -eq $null) 
{
$WSUSServer =[Microsoft.UpdateServices.Administration.AdminProxy]::GetUpdateServer();
}
Return $WSUSServer
}


Since the formulation of the problem involves working with groups in WSUS, you must learn to obtain their performance. I used code like this:
the
<#
.SYNOPSIS 
Returns a WSUS computer group on her behalf.

.PARAMETER Name
The name of the WSUS group that you want to retrieve.

.OUTPUTS
Interface IComputerTargetGroup representing the specified WSUS group if the group is found. null otherwise.

Function Get-WsusGroupByName([STRING]$Name)
{ 
$wsus = $null
$wsus = Get-WsusServerInstance
$Groups = $wsus.GetComputerTargetGroups()
Foreach ($Group in $Groups)
{
if ($Group.Name-eq $Name)
{
Return $Group
}
}
Return $null 
}


Now that we have the mechanism to access performance of the group WSUS, it is easy to obtain the list of updates approved for a specific group:
the
<#
.SYNOPSIS 
Returns an array of updates that are approved for the specified group.

.DESCRIPTION
Returns an array of objects representing the maps 
defined for the specified group. Each object contains information about the update (ID)
and his confirmation.

.PARAMETER GroupName 
The group name for which you want to receive the list of approvals

.OUTPUTS
An array of objects. Each object contains two fields: objUpdate (update) and objApproval (the result of the approval)
#>
Function Get-UpdatesApprovedToGroup([STRING]$GroupName)
{ 
#Reset result variable
$ApprovedUpdates = @()

#Create object representing the WSUS server
$wsus = Get-WsusServerInstance

#Get representation of a given group
$Group = Get-WsusGroupByName -Name $GroupName

Write-Host "Querying updates from the WSUS server info..." 

#Get information about all the updates known to this server
$WsusUpdates = $wsus.GetUpdates()
$TotalWsusUpdates = $WsusUpdates.Count
$i = 0

#Iterate through the updates in a loop, specifying for each of them relevant to specified computer group
foreach ($Update in $WsusUpdates)
{ 
$i++
#KBID (the article number in MS KB) updates
[STRING]$UpdateKB = $Update.KnowledgebaseArticles
Write-Host "Gathering approvals for update. Last porcessed is KB$UpdateKB"

#Check whether the decision approving the current updates for use in specified group.
$CurrentApprovals = $update.GetUpdateApprovals($group) 

#If the upgrade was made the decision (approval, prohibition), create a corresponding 
#object and add it to result list.
if ($CurrentApprovals.Count-gt 0)
{ 
foreach ($Approval in $CurrentApprovals)
{
#Create an object that encapsulates the properties of the update and confirmation. 
$Record = New-Object Object 
Add-Member -InputObject $Record-MemberType NoteProperty -Value $Update -Name "objUpdate" | Out-Null 
Add-Member -InputObject $Record-MemberType NoteProperty -Value $Approval -Name "objApproval" | Out-Null

$ApprovedUpdates = $ApprovedUpdates + $Record 
}


}
}

Return $ApprovedUpdates
}


The result of this feature you can save the information to a file, and then import it to another WSUS server, for example, using this function:
the
<#
.SYNOPSIS 
Imports the data about the approval of WSUS updates from a file

.DESCRIPTION
Imported not only information about approvals (Approval), but information on prohibitions (Decline)

.PARAMETER FilePath
XML file that contains information about the approvals WSUS updates.

.OUTPUTS
$null (this function does not return a value).
#>
Function Import-Approvals([STRING]$FilePath)
{
#Get local WSUS server
$WSUS = Get-WsusServerInstance 

#Get list of WSUS groups, information about which is contained in the file.
$XML = [xml](get-content $FilePath) 
$Groups = $XML.Groups 
$Groups = $Groups.ChildNodes

#For each group viewed a list of approvals in the file
Foreach ($Group in $Groups)
{ 
#Skip XML comments
if ($Group.get_NodeType() -ne $XML_TYPE_COMMENT)
{
$GroupName = $Group.Name
Write-Host "Importing updates for WSUS group: $GroupName" 

#Create a group presentation
$objGroup = Get-WsusGroupByName -Name $GroupName

#Iterate through all of the updates listed in the file for this group
$Updates = $Group.ChildNodes
$TotalUpdates = $Updates.Count
$i = 0 
Foreach ($Update in $Updates)
{
$i++
$UpdateGUID = $Update.UpdateID 
if ($UpdateGUID -ne "")
{

$UpdateKB = $Update.UpdateKB
Write-Host "Importing updates for $GroupName. Last processed is KB$UpdateKB"

#Find the Update with that ID on the server:
$UpdateGUID = [System.Guid]$UpdateGUID
$objUpdateID = [Microsoft.UpdateServices.Administration.UpdateRevisionId]$UpdateGUID
$objUpdate = $WSUS.GetUpdate($objUpdateID)

#Get the properties of the update and its approval from an XML key, convert it all to the desired types 
[DateTime]$UpdateApprovalDeadline = Get-XmlValue -XML $Update.UpdateApprovalDeadLine
[Microsoft.UpdateServices.Administration.UpdateApprovalAction]$UpdateApprovalAction = Get-XmlValue -XML $Update.UpdateApprovalAction
if ($Update.UpdateIsDeclined -eq "true")
{
$UpdateIsDeclined = $true 
} else
{
$UpdateIsDeclined = $false 
}

#Confirm update
$objUpdate.Approve($UpdateApprovalAction,$objGroup,$UpdateApprovalDeadline) | Out-Null
#Set status "Canceled" in accordance with what is  stated  in the file
$objUpdate.IsDeclined = $UpdateIsDeclined 
}
}
}
Write-host -Message "Import finished for group: $GroupName" 
}
}


In General, it's pretty simple. Export is similar to import (you can find the appropriate option in full script source).
user Interface


As the script was supposed to use not only I, but my colleagues are generalists in other regions, it was decided to implement it graphical user interface:


I tried to keep the minimalist look of the main window and avoided the inclusion of the parameters of the script in the interface, only hardcore hardcod. Because WPF not installed on all computers that use this script, the GUI is implemented using System.Windows.Forms and not more suitable for such tasks XAML.

Of course, Powershell is designed to automate routine operations, must have the command-line interface, otherwise the user will not be able to use it in their scripts (or at least start on schedule).

The described scenario takes the following parameters:

    DoImportFromFile — the Path to the file from which to import information about approvals. If this parameter is blank, the import does not occur;

    DoExportToFile — the path to the file to which you want to upload information about approvals. Similarly, in the absence of this parameter, the export fails;

    ServersCopyTestApprovals Approve all the updates that are approved for use in the test server group, for use in "battle" servers (see below); the

  1. WorkstationsCopyTestApprovals — Similar to the previous one, but for workstations;
  2. PathToLog — the path to the log file (by default created in a temporary folder "%Temp%")



implementation of


In order to successfully use this script, had to perform a number of preparatory activities.

Initially each network was allocated at least one test workstation and at least one test server. Whenever possible, we tried to include in the test group is not critical for the main business nodes. Before the updates are approved for use across the network, they are a few days (at the discretion of the system administrator) is checked on the test computers. Those updates that cause any problems are excluded (decline), and the rest, after testing, approved for use in military groups. Copy of the approvals described scenario is used.

On all WSUS servers, where it is supposed to use the described scenario, we created the following groups of machines:

    gWSUS_srv_test — test server;

    gWSUS_wks_test — test workstations;

    gWSUS_srv_prod "fighting" servers;

    gWSUS_wks_prod — business critical workstations


The group names are hard-coded in the script and cannot be changed without his edits. On each WSUS server was configured to run a script in the copy mode approvals from a test group on "fighting" on a schedule every two weeks (it was agreed that a period of time will, on the one hand, to manage to eliminate the "problem" updates from the list and will not be too much to defer the delivery of updates to computers).

Every few days (at the discretion of the system administrator) designated unicast the test network performs approval of new (non-approved and not canceled) updates. After receiving permission from the system administrator it downloads the list of approvals in the form of an XML file to a special site inside the network.

Once a day on each WSUS server is running a simple batch file that downloads the current version of the list of updates from this site and importing approvals:

the
REM Go to the folder with the script
cd /d d:\WSUS_script\

REM Remove obsolete file approvals
del /f .\WSUS_updates_approvals.waf

REM Download new file approvals
wget --tries=100 --retry-connrefused --continue http://server.network.lan/wsus_approvals/WSUS_updates_approvals.waf

REM Import approval from a file
powershell -command-ExecutionPolicy Bypass ".\wsus_admin_tool.ps1-DoImportFromFile 'c:\WSUS_updates_approvals.waf'"


Opinion


Of course, the solution described is not without certain shortcomings: the script does not check the demand for downloadable approval (whether the approval servispak for SQL on the network if the DBMS isn't there?), the script requires access to the upstream WSUS server (or the server WindowsUpdate), and the code itself is probably far from ideal.

However, the task was successfully solved, and the practice is known as the criterion of truth. I hope this solution will be useful to someone else.

PS. The complete code script available on PasteBin.
Article based on information from habrahabr.ru

Популярные сообщения из этого блога

The Hilbert curve vs. Z-order

Kaspersky Security Center — the fight for automation