WSUS synchronization report

The other day I wondered how to get the equivalent of this WSUS synchronization summary and its details.
More precisely I wanted to get the summary of what you see in the mmc snap-in under the synchronizations node:
wsus-sync-01
and the details that you get when you right-click a synchronization and hit ‘Synchronization report’ but I got instead the following message telling me that the report viewer wasn’t installed
wsus-sync-02

After a few minutes, I found the following MSDN page about Reporting Newly Synchronized Updates
I first looked at the GetUpdates method that has many ways to call it.
wsus-sync-03
The msdn article proposes to use the 2nd one where you specify all the 5 arguments:

  • Microsoft.UpdateServices.Administration.ApprovedStates approvedStates,
  • datetime fromArrivalDate,
  • datetime toArrivalDate,
  • Microsoft.UpdateServices.Administration.UpdateCategoryCollection updateCategories,
  • Microsoft.UpdateServices.Administration.UpdateClassificationCollection updateClassifications

where both the updatecategories and updateclassifications are set to $null
I gave it a try but I couldn’t get reliable results 😦 even when the two collections (UpdateCategoryCollection and UpdateClassificationCollection) were properly defined and not set to null.
Forget that method, it’s too unpredictable.

I switched to the 3rd method where you just use a single updateScope object as argument instead of the above 5 arguments and finally got the expected reliability πŸ˜€

# Get the last sync info (start and end times)
$lastSync = (Get-WsusServer).GetSubscription().GetLastSynchronizationInfo()

# Create an updatescope object
$UpdateScope = New-Object -TypeName Microsoft.UpdateServices.Administration.UpdateScope

# Set the start time
$UpdateScope.FromArrivalDate = $lastSync.StartTime
# Set the end time
$UpdateScope.ToArrivalDate = $lastSync.EndTime

# Invoke the getupdates method using the update scope object
$SyncUpdates = (Get-WsusServer).GetUpdates($UpdateScope)

Now to get the summary, I just do

$SyncUpdates | 
Group-Object -Property publicationstate -NoElement

wsus-sync-04
To view the details of what was synchronized I do:

$SyncUpdates | Out-GridView
# or 
$SyncUpdates | 
Select Title,SecurityBulletins,UpdateClassificationTitle,PublicationState | 
Sort PublicationState | 
Format-Table -AutoSize

wsus-sync-05

Easy-peasy and as always PowerShell rocks 😎

Testing WSUS server operational status

During the summer, someone asked the following questionwsus-monitoring-question on the WSUS patchmanagement.org mailing list.

I replied and immediately thought that Pester would do the job and quickly showed how he could test if he can connect to the console.

I’ve actually more than a WSUS server to manage. So, I started separating the environmental configuration data from the pester tests code almost the same way Mike F. Robbins did in his recent post where he goes far beyond to what I did.

I think it’s a great idea and here’s what I did in my case to monitor my WSUS server operational status.

To get started, I copied the Pester module on my WSUS server, imported the module and did in the ISE:

# helper to create the required files and folder if not present
New-Fixture -Path  ~/Documents/Pester -Name Test-WSUS
# Put the config data into that file:
psEdit ~/Documents/Pester/Test-WSUS.ps1
# Put the pester code into that file:
psEdit ~/Documents/Pester/Test-WSUS.Tests.ps1

After the first 3 commands, here’s what the ISE console looked liked
pester-new-fixture-wsus-tests

The first file Test-WSUS.ps1 looks like this by default.
It will be used to store my configuration data.
pester-wsus-tests-01

The second file Test-WSUS.Tests.ps1 is where I’ll write the pester tests code
pester-wsus-tests-02

After editing the 1rst file Test-WSUS.ps1 like this:
pester-test-wsus-file (fake data in this case)

…and the 2nd file Test-WSUS.Tests.ps1 like this:

…I’m actually ready to assess the operational readiness of my WSUS configuration by using the following cmdlet:

Invoke-Pester -Script ~/Documents/Pester/Test-WSUS.Tests.ps1

wsus-server-config-invoke-pester

I still feel like a Pester newbie but no doubt that Pester rocks 😎

Import the convenience update into WSUS

My WSUS server runs on a Windows Core edition where I don’t have Internet Explorer installed.

Whatif I want to import the Convenience rollup update for Windows 7 SP1 and Windows Server 2008 R2 SP1 from the catalog?

Here’s the way to go:

On a client computer with a GUI, launch internet explorer with high privileges to be able to install the ActiveX.

$HT = @{
 FilePath = 'C:\Program Files (x86)\Internet Explorer\iexplore.exe' ;
 ArgumentList = 'http://catalog.update.microsoft.com/v7/site/Search.aspx?q=KB3125574' ;
 Verb = 'Runas'
}
Start-Process @HT

MS-catalog-ActiveX-install

Install the ActiveX, add the update to the basket, view your basket, download, browse…
Move the file onto the WSUS server…and check if the file is digitally signed

Get-AuthenticodeSignature -FilePath ~\downloads\Catalog\*\*.msu

The WSUS API has an ImportUpdateFromCatalogSite, documented here on msdn.
WSUS-import-method

I’m missing the UpdateID. Where do I find this Id?

It appears that if you click on the link highlighted below…

MS-catalog-KB-link

…you get on a page where you’ve more details about the update.

Convenience-update-Id

The updateId actually appears in the address bar. πŸ˜€

Now, to import the update into WSUS, I do:

$MSUfile = 'C:\Users\administrator\Downloads\Catalog\Update for Windows 7 for x64-based Systems (KB3125574)\AMD64-all-windows6.1-kb3125574-v4-x64_2dafb1d203c8964239af3048b5dd4b1264cd93b9.msu'
(Get-WsusServer).ImportUpdateFromCatalogSite(
    '49924c88-1b31-4b0f-ad3d-48df9877f385',
    $MSUfile
)
# Find the imported file
(Get-WsusServer).SearchUpdates('3125574') | fl *

The convenience update has been successfully imported and can now be approved.

Easily identify your WSUS updates

I’ve been using some piece of code on WSUS to enrich non-security updates to help me identify what problem they address.

Let’s first have a look at the result as a picture is worth a thousand words πŸ˜€
Enrich-WSUS-updates

Now, let’s see the code

I wanted to share this a long time ago but the initial piece of code broke while Microsoft was upgrading their support.microsoft.com website.
It may broke again of course…

Switch WSUS to https

The following was presented at Black Hat 2015 USA during the summer.

The whitepaper is available at http://ctx.is/WSUSpect
The slides are available at http://www.contextis.com/documents/162/WSUSpect_Presentation.pdf
The code is available at https://github.com/ctxis/wsuspect-proxy

The only mitigation identified was an HTTPS-enabled WSUS. In this post, I’d like to show how to switch your HTTP based WSUS to HTTPS.

I’ll assume that:

  • your server is running Windows 2012 R2, has already an http based WSUS
  • your server may not be connected directly to the Internet
  • you don’t want to buy a certificate from a public certiticate authority
  • you don’t have PKI in your infrastructure

This official documentation is available on Technet on this page

But let’s do this with PowerShell πŸ™‚


# 1. Create a self-signed certificate
$SelfSignedHT = @{
 DnsName = "$($env:COMPUTERNAME).$($env:USERDNSDOMAIN)".ToLower()
 CertStoreLocation = "Cert:\LocalMachine\My"
}
New-SelfSignedCertificate @SelfSignedHT
$cert = Get-ChildItem -Path Cert:\LocalMachine\My -SSLServerAuthentication

# 2. Export its public key
Export-Certificate -Cert $cert -Type CERT -FilePath ~/documents/cert.cer

# 3. Import the public key in the Trusted Root Certificate Authorities store
Import-Certificate -FilePath ~/documents/cert.cer -CertStoreLocation Cert:\LocalMachine\Root

# 4. Select this certificate in the SSL bindings
$cert | New-Item IIS:\SslBindings\0.0.0.0!8531

# 5. Require SSL for the following virtual roots only:
'SimpleAuthWebService','DSSAuthWebService',
'ServerSyncWebService','APIRemoting30',
'ClientWebService' | ForEach-Object {
 Set-WebConfigurationProperty -Filter 'system.webserver/security/access' -Location "WSUS Administration/$($_)" -Name sslFlags -Value 8
}

# 6. Switch WSUS to SSL
& 'C:\Program Files\Update Services\Tools\WsusUtil.exe' configuressl $("$($env:COMPUTERNAME).$($env:USERDNSDOMAIN)".ToLower())

# 7. Change your GPO to point to the new URL
$key = 'HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate'
$uri = 'https://{0}:8531' -f $("$($env:COMPUTERNAME).$($env:USERDNSDOMAIN)".ToLower())
Get-GPO -All | Foreach-Object { 
 if ($_ | Get-GPRegistryValue -Key $key -ValueName WUServer -EA 0) {
  $_ | Set-GPRegistryValue -Key $key -ValueName WUServer       -Value $uri -Type String
  $_ | Set-GPRegistryValue -Key $key -ValueName WUStatusServer -Value $uri -Type String
 }
}

You’re almost done.
The last step consists in distributing the public key of your self-signed certificate to your clients so that they trust your self-signed certificate.
To achieve this, you’ll need to edit your GPO that targets clients and import your ~/documents/cert.cer file into ‘Computer Configuration / Policies / Windows Settings / Security Settings / Public Key Policies / Trusted Root Certificate Authrorities
Import-PK-into-Root

You’ve successfully mitigated the threat reported at BH2015 😎
Note that the certificate is valid for 1 year.

Install Internet Explorer 11 with WSUS

Internet Explorer support/lifecycle: better safe than sorry

You should proably know that your browser should stay up-to-date not only because of security issues being fixed or any security or non-security related improvements introduced. Now, it will have to be aligned with the the lastest supported major version of Internet Explorer. The end-of-life of Internet Explorer on a per-OS basis has changed. Microsoft announced in August 2014 that:
IE11-support-changes
Source: http://blogs.msdn.com/b/ie/archive/2014/08/07/stay-up-to-date-with-internet-explorer.aspx

Any guidance available?

Let’s have a look at the guidance on how to deploy Internet Explorer 11 on Windows 7 with WSUS.

I found the following technet page but it’s not exactly what I was looking for:
Install Internet Explorer 11 (IE11) – Windows Server Update Services (WSUS)

You may not know but it’s recommended to uninstalll previous IE9 before installing Internet Explorer 11
Source: https://support2.microsoft.com/kb/2872074/en-us

This page shows how to uninstall Internet Explorer from the commandline.
IE11-IE9-uninstall

That’s it for the official guidance 😦 If you’ve a better link – an official one pointing to Microsoft’s website – , please feel free to post it in the comments, I may update this article to share it πŸ™‚

Approve the Internet Explorer 11 on WSUS

Internet Explorer 11 is classified in the “Update Rollup” category. This category should be selected in the WSUS settings and the catalog should have been synchronised.

You cannot actually directly approve Internet Explorer 11 like any security update. If you try, you’ll get an error message saying:
“This Update has Microsoft Software License Terms that must be accepted before it can be deployed.”
W7-IE11-LicenseApprovalRequired

If I list all the properties of the Internet Explorer 11, we can that the license has not been approved yet:
W7-IE11-BeforeLicenseApproval

Fortunately, there’s a license approval method named ‘AcceptLicenseAgreement’ πŸ™‚
W7-IE11-LicenseApprovalMethod

Once the IE11 license has been approved, the properties are:
W7-IE11-AfterLicenseApproval

Here’s the piece of code I used to approve all required updates for Internet Explorer 11

(Get-WsusServer).SearchUpdates("Internet Explorer 11")| 
Where {
 -not($_.IsSuperseded) -and
 -not($_.isApproved)   -and 
 $_.Title -match "Windows\s7\sfor\sx64\-(based|Edition)" 
} | ForEach-Object {
 if($_.RequiresLicenseAgreementAcceptance) {
  $_.AcceptLicenseAgreement()
  Write-Verbose -Message "License accepted for $($_.Title)" -Verbose
 }
 $_.Approve(
  [Microsoft.UpdateServices.Administration.UpdateApprovalAction]::Install,
  $targetgroup            
 )
}

Any post-installation updates required?
If you deploy Internet Explorer 11, you’ll have to apply post-installation security updates
Currently (on August 14) this is what is approved updates on WSUS

(Get-WsusServer).SearchUpdates("Internet Explorer 11")| ? {
    ($_.isApproved)   -and 
    $_.Title -match "Windows\s7\sfor\sx64\-(based|Edition)" 
} |
Select Title,isApproved,isSuperseded,SecurityBulletins,
@{l='Revision';e={$_.Id.RevisionNumber}},CreationDate,UpdateClassificationTitle | 
ft -AutoSize

W7-IE11-ApprovedUpdates

What’s the client ‘experience’?
On the Windows 7 client, some prerequisites updates have been approved and installed along with Internet Explorer 11:
W7-IE11-WUA-install

To confirm that Internet Explorer 11 was installed on the client, you can watch for the event ID 19.

$HT= @{
 LogName = 'System' ;
 ProviderName = 'Microsoft-Windows-WindowsUpdateClient';
}
Get-WinEvent -FilterHashtable $HT -MaxEvents 10

IE11-installed-event
Once Internet Explorer 11 has been installed and Windows 7 restarted, a bunch of post-installation updates are still required to be installed on the Windows 7 client
W7-IE11-PostInstallAfterReboot

Conclusion: When you deploy Internet Explorer 11 through WSUS, it’s fairly easy but it requires unfortunately 2 scans/installs + reboot to finally get a fully secured and up-to-date version of Internet Explorer 11 πŸ™‚
If it’s manually deployed, you can achieve the same thing with a single reboot. Thanks to DISM, you can chain the uninstallation of IE9, the installation of the prerequisites, IE11 itself plus its post-installation updates and reboot.

Bonus: Here are two useful links if you manage IE11 in a corporate environment

Cleanup WSUS

I’ve never had to perform a WSUS cleanup for years, shame on me πŸ˜‰

Lawrence Garvin, who answers all the WSUS maintenance related questions on the patchmanagement.org mailing list made me change my mind recently.

His post explains what are the benefits of performing maintenance tasks on a regular basis:

Source: http://marc.info/?l=patchmanagement&m=142075193424332&w=2

Having WSUS built-in Windows 2012 R2 servers makes it very easy with PowerShell πŸ˜€

Here’s what I do a few days later, after performing my usual Patch Tuesday duties (~synchronize and approve required updates):

  • Step 1: Decline all updates that have been superseded and not approved
$UpdateScope = New-Object Microsoft.UpdateServices.Administration.UpdateScope
$allupdates = (Get-WsusServer).GetUpdates($UpdateScope)
$allupdates | Where {
 ($_.IsSuperseded) -and
 -not($_.isApproved) -and
 -not($_.isDeclined)
} | ForEach-Object -Process {            
    $_.Decline()
}
  • Step 2: Use the built-in cmdlet to perform the maintenance and display results
$cleanupResults = Get-WsusServer | 
Invoke-WsusServerCleanup -CleanupObsoleteUpdates `
-CleanupUnneededContentFiles -CompressUpdates `
-DeclineExpiredUpdates -DeclineSupersededUpdates:$false -Verbose

$cleanupResults
'Diskspace Freed: {0:N2} GB' -f (
(($cleanupResults | sls -Pattern "^DiskSpace").Line -split ":")[1] / 1GB 
)

To summarize, I’ve now:

  • Updates being displayed faster in the console, when I select ‘Any Except Declined’
  • Compressed updates (less to transport over the wire)
  • Made some free space on the server (~ 1,5 GB in my case, the first time)
  • A cleanup maintenance task performing faster next month

PowerShell and WSUS, that rocks! – no doubt 😎 and a huge thanks to Lawrence Garvin for his excellent input on this subject πŸ˜€