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 :-D

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\!8531

# 5. Require SSL for the following virtual roots only:
'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

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

Tips: Make Get-WinEvent cmdlet perform quicker

Although September was a busy month, I’d like to share a nice tips that makes Get-WinEvent cmdlet perform quicker.

First, start with the FilterHashTable parameter. It’s easier to write.

$HT = @{
 LogName = 'System';
 ProviderName = 'Service Control Manager' ;
 Id = 7040 ;
 Data = 'Windows Modules Installer' ;
 StartTime = (Get-Date).AddDays(-365) ;
Get-WinEvent -FilterHashtable $HT -MaxEvents 1

Now, capture the XML query from the Verbose stream.
To achieve that, I just add the Verbose switch to the previous command

Get-WinEvent -FilterHashtable $HT -Verbose -MaxEvents 1


I copy/paste the XML query into a here-string and use it as input for the FilterXml parameter like this:

Get-WinEvent -FilterXml @'
 <Query Id="0" Path="system">
  <Select Path="system">*
  [System/Provider[@Name='service control manager'] and
  (System/TimeCreated[@SystemTime&gt;='2014-09-06T10:20:22.000Z']) and 
  (EventData/Data='Windows Modules Installer') and
'@ -Verbose -MaxEvents 1

As you can see, when you use the FilterXml parameter, there isn’t any overhead where the hashtable is first converted to a XML query.

The result is that the FilterXml will perform faster than the FilterHashTable parameter


… and you don’t have to figure out how to write the XML query :-D

Max memory for remote shell

The other day I was investigating a “locked” workflow .

The network tab of procexp.exe revealed what remote computer was locking it.
It was actually a Windows 7 computer that had the following 2 events in its log.



To “unlock” the workflow, I just stopped the WinRM service on the remote computer, waited for the workflow to end correctly and finally restart the WinRM service on that remote machine.

c:\windows\system32\sc.exe \\RemoteComputerName stop WinRM

What happened on this remote computer that caused the workflow to stop and wait for it?

It appeared that the code running on the remote computer was the culprit.
The code was supposed to get the total count of a specific event. What makes this computer so special was that it had 45469 of these events and the remote shell on this Windows 7 computer just hit the default maximum memory assigned.

After fixing winrm.cmd to work in my environment, I was able to do:

C:\winrm.cmd get winrm/config/winrs -machine:RemoteComputerName -format:#text
c:\winrm.cmd set winrm/config/winrs @{MaxMemoryPerShellMB="512"} -machine:RemoteComputerName

I’ve increased the default Maximum Memory for a remote shell from 150MB to 512MB


BPUG / August 28, 2015 / meeting summary and presentation materials

I went to the Basel PowerShell User Group that my fellow PowerShell MVP, Stéphane Van Gulick (@Stephanevg) organised.

I gave a presentation about Nano Server :-D

The presentation was a quick introduction directly inspired by this 20 minutes talk from Jeffrey Snover with Jeremy Chapman at Ignite early May 2015:



I gave also a quick demo about installing a Nano Server into a virtual machine through WDS (Windows Deployment Services). It’s directly inspired from the following article published in PowerShell Magazine, except that the code was “adapted” to work with the recently published Windows Server 2016 TP3.

Amanda Debler (@texmandie) who gave a preview of her presentation about Skype for Business for the 2nd Powershell.org Summit in Europe, took a nice picture during my demo :-D


And when you provide the correct credentials and authenticate on the Nano box, you’ll see

Bonus: here are 4 essentials links about NanoServer you should bookmark:

And… here is the code on github:

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:
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.

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.”

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

Fortunately, there’s a license approval method named ‘AcceptLicenseAgreement’ :-)

Once the IE11 license has been approved, the properties are:

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) {
  Write-Verbose -Message "License accepted for $($_.Title)" -Verbose

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


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

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

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

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

Windows Assessment and Deployment Kit (Windows ADK) 10 RTM available


I’ve updated the script on github that downloads ADK files for Windows 10

I’ve also added a new file that contains the checksums of files.
If you’ve downloaded the files into C:\ADK\v10, you can use the following code to check the integrity of these files:

$uri = 'https://raw.githubusercontent.com/p0w3rsh3ll/ADK/master/v10.0.26624/SHA256SUMS.csv'
Invoke-WebRequest -URI $uri -OutFile ~/documents\SHA256SUMS.csv
Import-Csv  ~/documents\SHA256SUMS.csv -Delimiter ";" | Foreach-Object {
 if ( (Get-FileHash -Path (Join-Path -Path C:\ADK\v10 -ChildPath $($_.File))).Hash -eq $_.Hash) {
  Write-Verbose -Message "OK: $($_.File)" -Verbose
 } else {
  Write-Warning -Message "NOK: $($_.File)"

NB: the installation log of the ADK says it’s verifying packages before installing themADK.setup.log.verified.packages

Enjoy :-D