📜 ⬆️ ⬇️

WSUS update approvals: import, export, copy

Prehistory


Until recently, I worked as an enikeyschik in a large Russian company with many offices throughout the country. In my charge were eleven sites located in different cities of the Far East (this is important). Each of these offices had its own, unrelated to others, network infrastructure - its own AD domain, its own subnet, etc.

Once, the management set me the task of organizing the process of automatically updating the OS and programs from MS and allowed me to deploy WSUS at the accountable sites.

Problem


After WSUS was deployed, computer mapping policies to WSUS groups were configured, content directories were synchronized with MS servers, etc., the question arose: who will, and, most importantly, how will approve updates?
')
Imagine: 11 cities, the connection with which is so “fast” and “stable”, that rare minutes when ICMP response delays are only 800 ms are perceived as unheard of luck. And in each it is necessary to conduct testing of all updates before deployment. At the same time, access to servers on the sites was only via RDP, i.e. it was necessary to weekly (the order established such a frequency) to connect to the server of each city and manually approve the use of new updates in test groups and, accordingly, transfer the tested updates to commercial operation:
image


Why reinvent the wheel


A reader who has experience working with WSUS will most certainly ask: what is the problem? Microsoft has foreseen everything: there is a replication mechanism in which the “downstream” (subordinate) server, called the “replica”, downloads both the update files themselves and information about which updates have been approved for use in various groups.

Indeed it is. However, in the case under consideration, the use of a regular mechanism did not work, since it requires a wide enough channel between the root server and its replicas. I did not have such a channel. But there was an indication - under no circumstances increase the cost of IT.

Idea


“No, no!” I thought, and began to figure out how to get out of this situation. First, each of the WSUS servers somehow had access to either the WindowsUpdate servers from MS, or to the local WSUS servers of the providers, or to the WSUS servers of the neighbors in the office, etc. Those. they had, from where to download update files, they only needed to specify which updates to download. Secondly, I was allowed to use Powershell .

The idea was simple: you need to implement a mechanism for importing / exporting data on which updates were approved. According to the old tradition, which was formed at the time of studying at the university, I decided to export to a simple XML file. The structure of this file is like this:
<Groups> <!--   ,       --> <gWSUS_wks_test> <!--   (Update) --> <Update> <!-- ,      --> <UpdateProduct>Windows XP</UpdateProduct> <!--  ,   ,    MS --> <UpdateKB>815021</UpdateKB> <!--    --> <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> <!--    --> <UpdateID>4aed463b-3a3b-4ad8-976e-17baf6434da2</UpdateID> <!--     --> <UpdateIsDeclined>False</UpdateIsDeclined> <!--        --> <UpdateApprovalIsOptional>False</UpdateApprovalIsOptional> <!--    (        ) --> <UpdateApprovalDeadLine>12/31/9999 23:59:59</UpdateApprovalDeadLine> <!-- ,    (   - ) --> <UpdateApprovalAction>Install</UpdateApprovalAction> </Update> </gWSUS_wks_test> </Groups> 


The scenario of using this mechanism can be represented as follows:
  1. The administrator (or his trusted assistant) on his network approves some updates for use in certain groups, makes sure that everything is fine, and uploads a file with information about which of them should be applied to certain groups of computers, for example, on the internal WEB -site;
  2. Enikeyschik on site (I, for example) configures a script that downloads the file generated by the administrator in claim 1 and loads its contents into the local WSUS database;
  3. If there are several unrelated WSUS servers in the area of ​​responsibility of enikeyschik - step 2 is performed several times


What does this give in the end? First, enikeyshik does not decide which updates to approve and which not - this decision is made by a qualified system administrator who can reasonably predict the effect of each update on the original development curves used in the work, which seem to be strongly tied to specific glitches undocumented features of the OS, SQL server and MS Office.

Secondly, enikeyschik cannot be mistaken (forget to approve the necessary update, accidentally approve the unnecessary, etc.)

Thirdly, the administrator receives a guarantee that the same updates are approved for installation in all the company's networks (i.e. the question “What version of the office is used in Zamkadsk?” Loses its relevance).

In addition to the export of approvals, a mechanism was needed to transfer the upgrades to “combat” that had been tested in test groups. It is desirable, with one button / command - “to approve everything that is not prohibited and approved for use in the test group”. This is necessary in order to exclude non-tested updates from getting into production as a result of the contractor’s mistake (“oh, I didn’t approve it, I didn’t click it!”).

Implementation


Code

After spending some time looking for a ready-made solution, and not finding one, I went deep into studying the documentation on the WSUS API , Powershell, and .NET .

First I had to figure out how to get access to the objects that allow you to manipulate the WSUS server. To do this, download the appropriate assembly:
 [reflection.assembly]::LoadWithPartialName("Microsoft.UpdateServices.Administration")|out-null 


After this, create a function that would return an object representing the WSUS server installed locally:
 <# .SYNOPSIS    -  WSUS .DESCRIPTION      (,    )  WSUS .OUTPUTS   IUpdateServer,    WSUS #> Function Get-WsusServerInstance() { #  $Script:WSUS   "" . $WSUSServer = $Script:WSUS #      WSUS. if ($WSUSServer -eq $null) { $WSUSServer =[Microsoft.UpdateServices.Administration.AdminProxy]::GetUpdateServer(); } Return $WSUSServer } 


Since the formulation of the problem involves working with WSUS groups, you need to learn how to get their idea. I used something like this:
 <# .SYNOPSIS   -   WSUS   . .PARAMETER Name   WSUS,    . .OUTPUTS  IComputerTargetGroup,    WSUS,   . $null -   . #> 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 a mechanism for accessing the WSUS group view, it’s easy to get a list of updates approved for a given group:
 <# .SYNOPSIS   ,    . .DESCRIPTION   ,  ,    .       (ID)   . .PARAMETER GroupName  ,       .OUTPUTS  .     : objUpdate ()  objApproval ( ) #> Function Get-UpdatesApprovedToGroup([STRING]$GroupName) { #   $ApprovedUpdates = @() # ,   WSUS $wsus = Get-WsusServerInstance #    $Group = Get-WsusGroupByName -Name $GroupName Write-Host "Querying updates info from WSUS server..." #    ,    $WsusUpdates = $wsus.GetUpdates() $TotalWsusUpdates = $WsusUpdates.Count $i = 0 #   ,           foreach ($Update in $WsusUpdates) { $i++ #KBID (    MS)  [STRING]$UpdateKB = $Update.KnowledgebaseArticles Write-Host "Gathering approvals for update. Last porcessed is KB$UpdateKB" #,             . $CurrentApprovals = $update.GetUpdateApprovals($group) #      (, ),   #      . if ($CurrentApprovals.Count -gt 0) { foreach ($Approval in $CurrentApprovals) { # ,      . $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 } 


Information obtained as a result of this function can be saved to a file and then imported on another WSUS server, for example, using this function:
 <# .SYNOPSIS      WSUS   .DESCRIPTION       (Approval),      (Decline) .PARAMETER FilePath XML-,        WSUS. .OUTPUTS $null (    ). #> Function Import-Approvals([STRING]$FilePath) { #    WSUS $WSUS = Get-WsusServerInstance #   WSUS,      . $XML = [xml](get-content $FilePath) $Groups = $XML.Groups $Groups = $Groups.ChildNodes #        Foreach ($Group in $Groups) { #  XML if ($Group.get_NodeType() -ne $XML_TYPE_COMMENT) { $GroupName = $Group.Name Write-Host "Importing updates for WSUS group: $GroupName" #   $objGroup = Get-WsusGroupByName -Name $GroupName #    ,       $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" # Update   ID  : $UpdateGUID = [System.Guid]$UpdateGUID $objUpdateID = [Microsoft.UpdateServices.Administration.UpdateRevisionId]$UpdateGUID $objUpdate = $WSUS.GetUpdate($objUpdateID) #       XML-,       [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 } #  $objUpdate.Approve($UpdateApprovalAction,$objGroup,$UpdateApprovalDeadline) | Out-Null #  ""    ,     $objUpdate.IsDeclined = $UpdateIsDeclined } } } Write-host -Message "Import finished for group: $GroupName" } } 


In general, everything is quite simple. The export is carried out similarly to the import (those who wish can find the corresponding function in the full text of the script ).

User interface


Since the script was supposed to be used not only by me, but also by my colleagues - the same enikeyschiki in other regions, it was decided to provide it with a graphical user interface:


I tried to keep minimalism in the guise of the main window and avoided including script parameters in the interface, only hardcore hardcode. Since WPF is not installed on all computers that use this script, the graphical interface is implemented using System.Windows.Forms , rather than the more appropriate XAML for such tasks.

Of course, a Powershell solution created to automate routine operations must have a command line interface, otherwise the user will not be able to use it in his scripts (or at least run on a schedule).

The described script takes the following parameters:
  1. DoImportFromFile — The path to the file from which you want to import approval information. If this parameter is empty, the import does not occur;
  2. DoExportToFile - The path to the file to which the approval information should be uploaded . Similarly, if there is no value for this parameter, the export is not performed;
  3. ServersCopyTestApprovals - Approve all updates allowed for use in a test group of servers for use on “combat” servers (see below);
  4. WorkstationsCopyTestApprovals - Same as above, but for workstations;
  5. PathToLog - Path to the log file (by default it is created in the temporary folder "% Temp%")


Implementation activities


In order to successfully use the described scenario, we had to perform a number of preparatory activities.

Initially, at least one test workstation and at least one test server were allocated on each network. Whenever possible, we tried to include non-critical nodes for the main business into test groups. Before updates are approved for use throughout the network, they are checked on test computers for several days (at the discretion of the system administrator). Those updates that cause any problems are excluded (decline), the rest, at the end of testing, are approved for use in combat groups. To copy approvals, use the described script.

The following computer groups were created on all the WSUS servers where the described script was supposed to be used:
  1. gWSUS_srv_test - test servers;
  2. gWSUS_wks_test - test workstations;
  3. gWSUS_srv_prod - “combat” servers;
  4. gWSUS_wks_prod — business-critical workstations;

The names of groups are hard-coded in the script and cannot be changed without editing it. Each WSUS server was configured to run the script in the copy approval mode from test groups to “battle” on a schedule every two weeks (it was decided that such a period of time would, on the one hand, have time to eliminate “problematic” updates from the list a, c the other one will not delay the delivery of updates to computers too much).

Once every few days (at the discretion of the system administrator), a specially assigned enikeyschik in the test network performs the approval of new (not yet approved and not canceled) updates. After obtaining permission from the system administrator, he uploads the list of approvals as an XML file to a special site within the network.

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

 REM      cd /dd:\WSUS_script\ REM     del /f .\WSUS_updates_approvals.waf REM     wget --tries=100 --retry-connrefused --continue http://server.network.lan/wsus_approvals/WSUS_updates_approvals.waf REM     powershell -command -ExecutionPolicy Bypass ".\wsus_admin_tool.ps1 -DoImportFromFile 'c:\WSUS_updates_approvals.waf'" 


Conclusion


Of course, the solution described is not without certain flaws: the script doesn’t check whether the approvals are in demand (does the server need SQL server’s approval in the network if this DBMS is not there?), The script requires access to the upstream WSUS server (or WindowsUpdate server), yes and the code itself is probably far from ideal.

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

Ps Full script code is available at PasteBin .

Source: https://habr.com/ru/post/160069/


All Articles