A very important patch for Windows 8.1 and Server 2012 R2

It would appear that Microsoft Windows 8.1 and Server 2012 R2 are only thirty days away from not receiving security updates, or more precisely from the beginning of patch Tuesday in May 2014 .

Well that is not entirely true, but instances running these operating systems are required to have installed KB2919355 (http://support.microsoft.com/kb/2919355) before the above date to continue to receive security updates.

According to Microsoft, this update was released to simplify servicing across both Windows Server 2012 R2, Windows 8.1 RT and Windows 8.1 and that his update will be considered as a new servicing/support baseline.

The new baseline only exists for Windows 8.1 and Windows Server 2012 R2, so those currently with Windows 8 and Windows Server 2012 operating systems will be unaffected. 

For more information on the above:

http://blogs.technet.com/b/gladiatormsft/archive/2014/04/12/information-regarding-the-latest-update-for-windows-8-1.aspx.

Happy patching!

Monitor Windows Update Last Success Time with Nagios XI

I was recently asked to provide a monitoring service for the last success success time of Windows Update and to provide status information within Nagios XI. Basically, the last success time was compared to be run a time span period of a number of days in the past to provide a service state.

In the case of the time span this was dependent on the host being monitored and therefore this period would be specified as a mandatory parameter when invoking the powershell script which was to be used as the check plugin within Nagios.

Param ([parameter(Mandatory = $true)][string] $Days)

We can read the last success time reported from Windows Update by querying the registry to retrieve the date and then format the date string to be in the format  ‘dd/MM/yyyy’.

$LastRun = (Get-ItemProperty "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update\Results\Install").LastSuccessTime
$LastRun = Get-Date $LastRun -Format 'dd/MM/yyyy'

We will now to generate a date in the past based on the value specified by the mandatory Days parameter using the subtraction method from the current date.

In order to generate the service status, we will use conditional logic to compare the current date to that specified in the timespan and to provide a return code and status information message. If the date values cannot be compared this will return an unknown service status.

If ([datetime]::parse($LastRun) -ge [datetime]::parse($TimeSpan))
   {
   $returncode = 0
   "Windows Update last run successfully on " + $LastRun
   } 
   ElseIf ([datetime]::parse($LastRun) -lt [datetime]::parse($TimeSpan))
   {
   $returncode = 1
   "Windows Update last run successfully on " + $LastRun
   }
Else 
   { 
   $returncode = 3 
   }

Finally, we will exit the powershell session by providing the return code.

exit $returncode

Windows Server 2008 R2 Service Pack 1 fails with 800F0818

I was recently attempting to run Windows Server 2008 R2 Service Pack 1, which would fail with the error code 800F0818 due to Windows Update corruption.

In order to resolve the issue, run the System Update Readiness tool and then install the service pack.

The System Update Readiness tool is available from http://support.microsoft.com/kb/947821.

Patch Management with Windows Update Server and WuInstall

I was recently looking to schedule approved updates from Windows Update Server and schedule updates with finer granularity than those provided by the Windows Update Services client. I discovered a command line utility called WuInstall  (http://www.wuinstall.com/index.php/en) which allows for updates to be installed on demand.

As part of this solution, I still required updates to be approved by my Windows Update Server and to be automatically downloaded by the Windows Update Services client on a daily basis.

I created a group policy object and linked to the organisational unit containing the clients and set the following group policy object settings:

Setting State Options Description
Configure Automatic Updates Enabled 3 – Auto download and notify for install Specifies that the instance will download approved updates from the WSUS server, but will only notify for install.
Specify intranet Microsoft Update Service location Enabled http://<name of WSUS server> Specifies the WSUS server as the intranet server to host updates.
Allow non-administrators to receive update notifications Disabled N/A Specifies that only administrators receive update notifications.
Enable client-side targeting Enabled <name of target group> Specifies the target group for the instances to receive updates.

Once the approved updates have been downloaded, the command line utility WuInstall will manage the schedule and installation.

As previously mentioned, WuInstall is a command line tool that allows the installation of Windows Updates on demand and can use the internal WSUS server to discover approved updates.

In the case of a single server, the executable can be downloaded and run with a number of command line arguments, in my case the following are to be used:

WuInstall.exe /install /autoaccepteula /reboot_if_needed /logfile <path to log file>
Usage Description
/install Searches, downloads and installs available updates.
/autoaccepteula Automatically accepts EULA on every update.
/reboot_if_needed Only restarts the instance if needed.
/logfile Creates log file

However, I was required to run the following against a number of servers. The command utility WuInstall supports the use of PSExec to run agaisnt multiple servers (http://www.wuinstall.com/index.php/faq#psexec) and therefore this was the mechanism used to launch the executable from a central management server to invoke the command on each remote server, with the following command line arguments:

PSExec.exe -c -f -s \\Server\Share\WUInstall.exe /install /autoaccepteula /reboot_if_needed /logfile <path to log file>
Usage Description
-c Copies the specific program (WuInstall.exe) to the remote instance for execution.
-f On copying the specific program overwrite the file is this already exists on the remote system.
-s Run remote process in the System account.

Now a further requirement was introduced in that updates were required to be installed on all servers in a particular environment and prior to the updates being installed a snapshot of the root device performed (Amazon Web Services). Therefore all the above would be compiled into a Windows Powershell script and

Param ([string] $Environment)

As the script was to be run against a number of environments, , the script defined parameters for the Environment name, which were called with the Environment argument. The script would required importing the Powershell for Amazon Web Services ((http://aws.amazon.com/powershell/) snap-in to the current powershell session.

If (-not (Get-Module AWSPowershell -ErrorAction SilentlyContinue))
{ 
Import-Module "C:\Program Files(x86)\AWS Tools\Powershell\AWSPowershell\AWSPowershell.psd1" > $null
}

As previously mentioned I have a collection of AWS EC2 instances (not a particularly large environment) to which I want to install the updates agaisnt, therefore this was represented as a collection in a hashtable to contain the information I required the InstanceID, VolumeID of the root device (/dev/sda1) and server name, below is an example of what this would look like;

$Instances = New-Object System.Collection.Generic.List(System.Collections.Hashtable)
$Instances.Add(@{"instanceid"="i-xxxxxxx1";"volumeid"=vol-xxxxxxx1";"name"="xxxxxxxxDEMxxx"})
$Instances.Add(@{"instanceid"="i-xxxxxxx2";"volumeid"=vol-xxxxxxx2";"name"="xxxxxxxxPRExxx"})
$Instances.Add(@{"instanceid"="i-xxxxxxx1";"volumeid"=vol-xxxxxxx1";"name"="xxxxxxxxPRDxxx"})

Once the instances have been listed as a collection we are required to run a loop process to return each instance name and then filter the environment using the substring method as conditional logic, where the naming convention contains the environment name in the 8th, 9th and 10th character of the hostname.

ForEach ($Instance in $Instances)
{
$String = $Instance.Name.ToString().Substring(8,3)
If ($String -eq $Environment)

Once this instances have been returned for the environment, the following is performed against each instance returned in the filter:

  • Stop the EC2 Instance
  • Once stopped perform an EC2 snapshot of the VolumeID specified in the collection and add the description: <Host Name>: WIndows Update on ddMMyyyy_HHmm
  • Once the EC2 snapshot is complete, start the EC2 instance.
  • Once the EC2 instance is running Invoke WuInstall to install the approved updates.
{ 
Stop-EC2Instance $Instance.instanceid 
Do { 
$EC2Instance = Get-EC2Instance -Instance $instance.instanceid  
$State = $EC2Instance.RunningInstance| ForEach-Object {$_.InstanceState.Name}
{
Until ($State -eq "stopped")
New-EC2Snapshot -VolumeID $instance.volumeid -Description ($instance.name + ": Windows Update on " + $Date)
Do { 
$SnapshotStatus = (Get-EC2Snapshot | Where-Object {$_.Description -eq ($instance.name + ": Windows Update on " + $Date)}).status
}
Until ($SnapshotStatus -eq "completed")
Start-EC2Instance $instance.instanceid
Do { 
$EC2Instance = Get-EC2Instance -Instance $instance.instanceid  
$State = $EC2Instance.RunningInstance| ForEach-Object {$_.InstanceState.Name}
}
Until ($State -eq "running")
Start-Sleep -Seconds 300 
$Hostname = $instance.Name
$Command =  "& 'C:\Program Files\SysinternalSuite\PsExec.exe' \\$Hostname -c -f -s \\Server\Share\WUInstall.exe /install /autoaccepteula /reboot_if_needed /logfile \\Server\Share\Logs\logfile.log"
Invoke-Expression $Command
}
}

A couple of issues I experienced with the script, was that when the EC2 instance was reported as running the instance would not be contactable as the status checks had not been completed, so a the script is therefore suspended for a period of five minutes as a workaround.

There is currently a known issue with Powershell for Amazon Web Services snap-in (3.0.512.0) where the Get-EC2InstanceStatus cmdlet fails to return stopped instances. This requires a workaround to be performed where the instance state is returned using the Get-EC2Instance cmdlet and returning the value of the RunningInstance.InstanceState.Name object.

I plan to update this script to remove the dependency on a collection as a hashtable and return this information using the Powershell for Amazon Web Services Tools snap-in. Also, I will hopefully address the issue of reporting the EC2 instance as being in a running status where the status checks have not completed and remove the need to suspend the script.

The script will require AWS credentials to run the various cmdlets above, in this process I store the credentials on the local computer where the scheduled task is invoked.

The full Windows Powershell script can be downloaded from the below link:

https://app.box.com/s/7t2b5zqgbp4kus34rtwf

Windows Update fails with error 66A

On attempting to install updates the client was failing with the error code 66A, this is due to corrupted install files when attempting to update the Microsoft .NET Framework 4 Client Profile. In order to resolve this and install updates successfully perform the following:

1) Browse to Start > Control Panel > Programs > Uninstall a program.

2) Select ‘Microsoft .Net Client 4 Profile’ and Uninstall.

3) Choose to ‘Repair .NET Framework 4 Client Profile’ to its original state.

4) Once the repair is complete perform a restart.