Quick tip: test if Windows 10 opted-in the Windows Insider Preview program

If you haven’t blocked the ability for users to join the Windows Insider Preview program with the following GPO policy, Toggle-IPB-button you may need to quickly test if their Windows 10 opted-in the Windows Insider Preview program.

Here’s a simple and fast way of testing it:

# load the function
Function Test-isPreviewBuild {
    $HT = @{
        Path = 'HKLM:\SOFTWARE\Microsoft\WindowsSelfHost\Applicability' ;
        Name = 'EnablePreviewBuilds' ;
        ErrorAction = 'SilentlyContinue' ;
    }
    [bool](Get-ItemProperty @HT).EnablePreviewBuilds
}

# invoke the function
Test-isPreviewBuild

Note about the Convenience rollup update KB3125574 on Windows 7

If you don’t know yet what is the Convenience rollup update KB3125574 for Windows 7 that hit the headlines, I’d encourage you to read the following blog post:

https://blogs.technet.microsoft.com/windowsitpro/2016/05/17/simplifying-updates-for-windows-7-and-8-1/

If you plan to do anything with it, please also read its related KB page: https://support.microsoft.com/en-us/kb/3125574 . There are more info about known issues, the list of files changed (stored in a CSV file attached).

I’ve quickly tested it on some Windows 7 computers.
If you already have WMF 5.0, there’s no change to the $PSVersionTable.
But, if you’ve a vanilla Windows 7 installation and apply the “SP2”, you’ll shift from
PS2-W7-sp1
to
PS2-W7-sp2
Did you notice that both the BuildVersion and the CLRVersion increased respectively from 6.1.7601.17514 to 6.1.7601.23403 and from 2.0.50727.5485 to 2.0.50727.8669?

If you’ve some code testing the values in the $PSVersionTable, you should consider revising your code and verifying the way your code handles theses values.

Deploy WMF5.0 on Windows 7

When the WMF5.0 was republished, I’ve asked the following question in the comments

Can you please explain why WMF 4.0 is a prerequisite on Windows Server 2008 R2 and Windows 7 SP1? Is it related to the WMI repository and/or to DSC?

Krishna C Vutukuri from the Windows PowerShell Team replied

As you may know, WMF 5 uses CBS based technology for installation. Win 7 SP1/W2K8R2 systems contain PowerShell 2.0, WinRM, WMI by default. After Win7/W2K8 R2 released, we shipped WMF 3.0 and WMF 4.0 which contain updates to these features. Installing / Uninstalling these packages uncovered some issues in the upgrade options from inbox -> WMF4 and inbox->WMF3->WMF4. We fixed all those issues in WMF4. Hence we had to make WMF4 as requirement for installing WMF5 on Win7 SP1/W2K8 R2. Here are the specific issues you might face if you do not install WMF4 before upgrading to WMF5:

(a) Forwarded Events log is unavailable and EventCollector log is not displayed in Event Viewer after you uninstall in Windows 7 SP1 and in Windows Server 2008 R2 SP1
(b) Issues with PSModulePath environment when you upgrade directly from inbox to WMF5 or from WMF 3 to WMF5.

Again WMF4 addresses these issues and our internal testing environment uses this matrix for testing WMF5 on Win7 SP1/W2K8R2 SP1.

Thanks
Krishna
Windows PowerShell Team

The other person interested in the upgrade path to WMF 5.0 on Windows 7 asked about
WMF4-update

To summarize: Windows 7 SP1 is shipped with PowerShell 2.0 and .Net 3.5 SP1 and to upgrade it to PowerShell 5.0, you’ve to:

  1. fullfil the .Net 4.x requirement
  2. update to WMF 4.0
  3. reboot
  4. update to WMF 5.0
  5. reboot

Ok, .Net 4.5.2 or .Net 4.6.x and WMF 5.0 can deployed from Microsoft Update but how to deploy WMF 4.0?

I’m not the only one who noticed this shortcoming. Bjorn Houben says on his blog:

One of the disadvantages however is that for operating systems before Windows 8.1/2012, a prerequisite is that WMF4 is installed, which cannot easily be deployed using WSUS unfortunately.

Martin Schvartzman @MSFT discussed how to deploy WMF 4.0 on this page.

Although I’ve got ConfigMgr in my environment, I wanted to find a solution

  • that doesn’t have any dependency (except Internet connectivity),
  • that would deploy .Net 4.5.2 if missing but that wouldn’t fail if it has .Net 4.6 or 4.6.1,
  • that would minimize the number of restarts required,
  • that will install the required components silently and not force a restart

My code somehow illustrates the concept of immutable infrastructure that Jeffrey Snover talked about in a recent video.

[…] All your infrastructure is the result of a base set of components and an algorithm to produce a result. If you don’t like the result or ever need to make a change, you never change the instance, you go back, change the recipe, re-run it to produce the instance. […]

My code is a recipe to ease the pain of getting Windows 7 from its built-in PowerShell 2.0 to WMF 5.0.
It’ll drive you through the following different stages:

    • Run it for the first time with all components missing, it will install .Net 4.5.2
    • wmf2towmf5-stage1

      Re-run it and it moves to the next step and installs WMF 4.0
      wmf2towmf5-stage2

    • Re-run it and it will kindly tell you that a reboot is pending
    • wmf2towmf5-reboot1

    • Re-run it after the 1st restart, it will move on and install WMF 5.0
    • wmf2towmf5-stage3

    • Re-run it after the 2nd restart and it will do nothing except telling you that WMF 5.0 is already installed
    • wmf2towmf5-final

Here’s the code (gone through the PSScriptAnalyzer module that only flagged it for using the Get-WmiObject cmdlet)

No doubt that PowerShell rocks and that it’s a key component to immutable infrastructureğŸ˜Ž

WSUS 2012 R2 KB3159706 manual steps

I’ve been monitoring what’s going on with WSUS updates and Microsoft WSUS team kept us posted on their official blog:

The TLDR version is KB3148812 was a disaster and now KB3159706 replaces it but still requires some manual steps afterward.
I’ve decided to share my recent experience with KB3159706. Please note that I didn’t installed KB3148812 and even if I had I’d have restored my WSUS to a previous state instead of trying to uninstall this KB.

  • Step1: Make a backup of your WSUS server and its Database and be prepared to restore it
  • Step 2: Before doing anything, read the above blog posts and the manual steps documented on the KB3159706 page under the “more info” section.
  • Step 3: install KB3159706, it’s available on Windows Update as a recommended update
  • Step 4: Reboot the WSUS server
  • Step 5: In a DOS command prompt running as local administrator, type:
    "C:\Program Files\Update Services\Tools\wsusutil.exe" postinstall /servicing
    

    NB1: All you should see is a line indicating where the log file is written and 2 lines ‘Post install is starting’ and ‘Post install has successfully completed’

  • NB2: I copied the log file somewhere else under a meaningful name and opened it to check that there isn’t any error mentioned

  • Step 6: Install the ‘HTTP Activation’ feature under .NET Framework 4.5 Features
    I first identified its Name and its state. It appeared mine was ‘Removed’. It means that I’ll have to provide a source to install it.

    Get-WindowsFeature -Name NET-WCF-HTTP-Activation45
    

    WSUS-Net45-HTTP-Activation-Removed

    My WSUS server has access to the Internet (it downloads updates from Microsoft), so I used ‘Windows Update’ as a source:

    Get-WindowsFeature -Name NET-WCF-HTTP-Activation45 | 
    Add-WindowsFeature -Restart:$false -Verbose -Source 'Windows Update'
    

    WSUS-Net45-HTTP-Activation

  • Step 7: Restart the WSUS service

    Get-Service -Name WsusService | Restart-Service -Verbose
    

My WSUS server is running under HTTPS, so I also performed the following steps:

  • Step 8: Copy the web.config file
    dir 'C:\Program Files\Update Services\WebServices\ClientWebService\Web.Config' | 
    Copy-Item -Destination D:\web.config
    
  • Step 9: Edit the copied web.config file and make the appropriate changes (see KB3159706)
    WSUS-3159706-webconfig-file
    NB1: Basically you need first to copy the 2 existing endpoints under the services node and change their bindingConfiguration to “SSL”. You’ve now 4 endpoints instead of 2.
    NB2: And you need to add multipleSiteBindingsEnabled=”true” almost at the end of the file.

  • Step 10: Replace the original web.config file with your modified version.
    To achieve that, there’s no need to modify the ACL of the original web.config.
    You can actually use the “restore mode” of robocopy.exe to overwrite a file where the Builtin\Administrators have only read and execute permissions.

    robocopy D:\ "C:\Program Files\Update Services\WebServices\ClientWebService" web.config /R:0 /B
    

Side notes:
My first attempt wasn’t successful, I forgot to remove bindingConfiguration=”ClientWebServiceBinding” and had 2 bindingConfiguration lines. D’Oh!(My Bad).
When I restarted the WSUS server, I had an error message saying: The Client Web Service is not working.
I fixed the typos I made in my D:\web.config file and restored it again with the “backup mode” of robocopy.exe.
I then checked that my problem was solved by running:

Get-Service -Name WsusService | Restart-Service -Verbose
& "C:\Program Files\Update Services\Tools\wsusutil.exe" checkhealth

WSUS-check-health

Get-winevent -FilterHashtable @{ 
 LogName = 'Application' ; 
 ProviderName = 'Windows Server Update Services' 
} -MaxEvents 10

WSUS-fix-webclient-not-working

Windows Server 2016 TP5

Windows Server 2016 Technical Preview 5 has just been released. Check what’s new in TP5 on this TechNet page

Let’s quickly review the top 10 reasons why you’ll love Windows Server 2016:

There are also some fresh news related to Nano server:

Bonus 1: There’s a free e-book about Windows Server 2016.

Bonus 2:: I’ve updated the demo code I presented last year about How to use WDS to PXE Boot a Nano Server VHD with PowerShell published on PowerShell Magazine

If you use the updated version below, you end up with 2 virtual machines: a Windows Server 2016 TP5 (with Active Directory and WDS) and a Nano VM ready to be provisioned through PXE.

The updated code for TP5 is available as a gist on this page.

Let’s see quickly what’s new:

The Convert-WindowsImage.ps1 script and the NanoServerImageGenerator module are now located on the (ISO):\NanoServer\NanoServerImageGenerator folder.

The New-NanoServerImage function has some new parameters like DeploymentType, Edition,… You can see below a huge comment block that contains a comparison of packages differences between TP4 and TP5 as well as details about syntax differences between TP4 and TP5 version of the New-NanoServerImage function.

A small gotcha. I’ve had to specify the Active Directory module version in the DSC configuration because I had multiple versions installed locally. If you’ve got the most up-to-date version, you’ll have to adjust the version I’ve hardcoded (‘2.8.0.0’ in my case).

One last thing, the code below assumes that you’ve downloaded and stored the TP5 ISO file in a directory named TP5 under your current user’s ‘Downloads’ directory.

Be careful with PPKG files

While working on a Windows 10 lab, I discovered a weakness in the provisioning engine responsible for handling PPKG files.

Let’s say, you want you use PPKG files to provision a local admin account, you secure the PPKG file and install it to Window 10 (1507 version).

Imagine, your IT dept. gave you a brand new Windows 10 and used PPKG to install a local admin account.

If you’re logged in as a standard user, you can actually read the local admin password stored in clear text in configuration files. D’oh!

dir C:\ProgramData\Microsoft\Provisioning -inc *.xml -rec | 
sls 'password' -context 1,1

No need to find an Elevation of Privilege vulnerability or decrypt passwords stored in the group policy preferences (Remember MS14-025 and its CPassword vulnerability in GPP CVE-2014-1812 ?)

It appeared that the ACLs on “C:\ProgramData\Microsoft\Provisioning” allowed standard users to read the content.

I’ve contacted Microsoft about this issue, respected the coordinated vulnerability disclosure guidelines and waited for 90 days before reporting it publicly.

There’s also another kind of file that stores the password in clear text:

dir C:\ProgramData\Microsoft\Provisioning -inc *.provxml -rec | 
sls 'password'

ppkg-password-01

I’ve found that only Windows 10 RTM (1507 branch/Threshold1/10.0.10240) is at stake and that the issue has been addressed in the Threshold2 branch (1511 or 10.0.10586). The latest report I had from Microsoft about this issue also confirmed these findings.

I don’t know if the ACL on the Provisioning directory are corrected if you upgraded from the 1507 branch to the 1511 branch.
If you run 1507 LTSB version, I don’t know if you’re safe…

Using the SANS DShield REST API

The SANS announced the availability of the Microsoft Patch Data on the 5th of April.
They have actually added both a REST API and a new web interface.

I’ve written a tiny module that uses the 3 Dshield REST API methods and made sure you can bind the resulting functions together. The last piece of the puzzle is a function to get the 2nd Tuesday of a month.

The module is available in a github repository and in the PowerShell Gallery

To get a nice display of Microsoft security bulletins, you can do:

(Get-SecondTuesday -Year 2016 -Month 04).ToString('yyyy-MM-dd') |
Get-SansMSPatchDay | Select @{l='Bulletin';e={$_.Id}},title,
 @{l='Components Affected';e={$_.affected}},
 @{l='kb';e={$_.kb -as [string]}},
 @{l='Known Exploits';e={
  switch($_.exploits) {
   'yes' { $true}
   'no'  {$false}
   default {}
  }
}},severity,clients,servers | Out-GridView -Title "April, 2016"

NB1: The long select properties list aims only to force the KB property to be displayed as a string by Out-GridView. There’s no problem in the console with the raw json format.
NB2: Next month, you can also omit the -Year and -Month parameters of the Get-SecondTuesday function. By default this function returns the second Tuesday of the current month as a datetime object.
SANS.Dshield.11

Now that we have seen how to use the functions each month.

Let’s say we want to do something more complicated and get an overview of what happened last year.

First store dates formatted the way the REST API expects them:

# Summary for 2015
$2015BTDates = 1..12 | ForEach-Object {
    (Get-SecondTuesday -Year 2015 -Month $_).ToString('yyyy-MM-dd')
}

SANS.Dshield.01

Pull all the bulletins from 2015 and store the info in a variable:

# Get Bulletins
$2015Bulletins = $2015BTDates | Get-SansMSPatchDay

SANS.Dshield.02
We also see above the first bulletin MS15-001 and the last one MS15-135.

Sure there were 135 bulletins in 2015? Actually No! The following tells us that there were only 133 bulletinsğŸ˜Ž

# Total bulletins in 2015
$2015Bulletins.Id | Measure

SANS.Dshield.03

How many bulletins have addressed one or more known vulnerabilities exploited in the wild?

# Only known exploits
$2015Bulletins | Where 'exploits' -eq 'yes' |
Select -Property Id | Measure

SANS.Dshield.04

19 known exploits over how many vulnerabilities fixed by these bulletins?

# Get CVEs
$2015CVEs  = $2015Bulletins | Get-SansMSPatchCVE

# Total CVEs
$2015CVEs | Select -expand cve | Sort -Unique | Measure

SANS.Dshield.05

"{0:P2}" -f $(19/220)

That makes 8.64%

What months got the most bulletins released?:

# Total bulletins per month in 2015
1..12 | ForEach-Object {
    [PSCustomObject]@{
        Month = $_ ;
        Bulletins = $(
            (Get-SecondTuesday -Year 2015 -Month $_).ToString('yyyy-MM-dd') | 
            Get-SansMSPatchDay | Select -Expand Id 
        );
    } 
} | Select Month,Bulletins,
@{l='Count';e={ $_.Bulletins | Measure-Object | Select -Expand Count}}

SANS.Dshield.06

How many vulnerabilities were addressed each month?

# Total CVEs per month in 2015
1..12 | ForEach-Object {
    [PSCustomObject]@{
        Month = $_ ;
        CVEs = $(
            (Get-SecondTuesday -Year 2015 -Month $_).ToString('yyyy-MM-dd') | 
            Get-SansMSPatchDay | Get-SansMSPatchCVE | Select -Expand cve
        );
    } 
} | Select Month,CVEs,
@{l='Count';e={ $_.CVEs |  Sort -Unique | Measure-Object | Select -Expand Count}}

SANS.Dshield.09

Let’s go crazy and retrieve from all the SANS data (almost 10 years) and filter out what bulletins were rated “PATCH NOW” by the SANS:

2006..2016 | ForEach-Object {
    $Y = $_
    1..12 | ForEach-Object {
        $M = $_
        Get-SecondTuesday -Year $Y -Month $M
    }
} | ForEach-Object {

    Write-Verbose -Message "Query MS Patch Day API of SANS for date: $($_.ToString('yyyy-MM-dd'))" -Verbose
    $_.ToString('yyyy-MM-dd') | Get-SansMSPatchDay
} | Where { $_.clients -eq 'patch now' -or $_.servers -eq 'patch now' } | 
Select Id,Title,affected,
    @{l='kb';e={$_.kb -as [string]}},
    @{l='Known Exploits';e={
        switch($_.exploits) {
            'yes' { $true}
            'no'  {$false}
            default {}
        }
    }},severity,clients,servers | ogv

SANS.Dshield.10
NB1: you’ll see inconsistencies when affected components get named. You’ve got for example: IE, MSIE or Internet Explorer.
NB2: the SANS bulletin id’s are not numbered the same way Microsoft did before 2010. You’ve got MS90-32 instead of MS09-032 for example.

Don’t blame the SANS, they did a nice job by providing these REST API methods.