How to amend WSUS Scan Retry Error Codes list in ConfigMgr 2012 with PowerShell

In a situation where you’ve multiple Software Update Points in the same site spread across different domains where clients in a particular domain cannot access resources in another domain, you’d expect that the ConfigMgr clients would switch Software Update Point after it has tried to scan against the Software Update point it can’t access for 4 times. That behavior is default, and in that situation you might want it to switch Software Update Point, but depending on the error code returned from the scan, it might not switch in all situations. I recently ran into a an issue at one of my customers where they had a number of systems that reported Unknown State back when running a Software Update compliance report. The customer had two Software Update Points in the site where the clients were reporting back as Unknown in the compliance report. We started digging and began with running a simple PowerShell one-liner locally on one of the clients that Unknown:

(Get-WmiObject -Namespace "root\ccm\StateMsg" -Class CCM_StateMsg -Filter "TopicType = 500" | Measure-Object).Count

The reason for running this PowerShell command was to check if the client had sent any State Messages at all regarding Software Updates. It appeared that there were no State Messages on the client we investigated, so we started looking at the WUAHandler.log to see if the client was able to scan against, and there we saw the following:

137_1

Apparently the clients weren’t able to scan against one of the Software Update Points and reported the following error:

Scan failed with error = 0x80072ee2

Error 0x80072ee2 translates to “The operation timed out”. These communication restrictions in the customer network was a known fact for the customer and they’ve intentionally designed their hierarchy to support this by adding an addition Software Update Point so that the ConfigMgr client could switch to a reachable Software Update Point. The problem was that when we investigated the WUAHandler.log further, we saw that the switch wasn’t taking place. So how can we fix that? Easy, with some PowerShell magic and by knowing the error code returned by the ConfigMgr client in the WUAHandler.log file. But first, let’s try to understand what went wrong.

WSUS Scan Retry Error Codes list

On the Site server where you have the SMS Provider installed, normally on the Primary Site server (and on the CAS if you’re running a hierarchy) there’s a WMI Server Class called SMS_SCI_Component. In that class, all the instances references the configuration of each component in the site. By knowing that, we can assume that there will be an instance for the particular Software Update Points SMS_WSUS_CONFIGURATION_MANAGER component. This instance has a number of SMS_EmbeddedProperty properties and one of them are particular interesting in this case, the one with a PropertyName of WSUS Scan Retry Error Codes. This Embedded Property is a string containing a list of error codes presented in decimals. We can explore this list by running the following PowerShell command:

$Props = Get-WmiObject -Namespace "root\SMS\site_CAS" -Class SMS_SCI_Component -Filter "ComponentName like 'SMS_WSUS_CONFIGURATION_MANAGER'" | Where-Object { $_.SiteCode -like "CAS" } | Select-Object -Property Props
$Props.Props | Where-Object { $_.PropertyName -like "WSUS Scan Retry Error Codes" }

When the above code is executed (remember to change the site_CAS and “CAS” portions to the Site Code of your the Site where the Software Update Point resides), the output would be something like the following:

137_3

Since the error codes in the Value2 property above is presented in decimals, we need to convert out hexadecimal error code (0x80072ee2) to decimal. That can be done with the following PowerShell code:

$ErrorCode = "0x80072ee2"
[System.Convert]::ToUInt32($ErrorCode, 16) -as [string]

137_4

Now that we know the error code in decimal, it’s easy to see if it’s present in the Value2 property list of values. Since the 2147954402 is not one of the eleven default error codes that forces the ConfigMgr client to switch Software Update Point, the reason for all of those clients being reported as Unknown State is due to the fact that the error the scan returned was not in the WSUS Scan Retry Error Code list.

Using PowerShell to add the Error Code

You could of course just fire up wbemtest and use the tool to add 2147954402 to the Value2 property, but that’s not fun. Instead I’ve created a script that will take care of things for you. All you need to do is to copy the error shown in WUAHandler.log and use that as parameter input with the script. The script has two parameters, SiteServer and ErrorCode. Save the script below as Add-CMWSUSScanRetryErrorCodes.ps1 in e.g. C:\Scripts.

<#
.SYNOPSIS
    Add an error code to the WSUS Scan Retry Error Codes list that will instruct a ConfigMgr 2012 client to switch Software Update Point
.DESCRIPTION
    Use this script to add an error code to the WSUS Scan Retry Error Codes list that will instruct a ConfigMgr 2012 client to switch Software Update Point once the threshold of failed scans has been reached
.PARAMETER SiteServer
    Site server name with SMS Provider installed
.PARAMETER ErrorCode
    Specify the error code to add as hexadecimal, e.g. 0x80072ee2 
.EXAMPLE
    .\Add-CMWSUSScanRetryErrorCodes.ps1 -SiteServer CM01 -ErrorCode 0x80072ee2
    Add the error code '0x80072ee2' to the WSUS Scan Retry Error Codes list on a Primary Site server called 'CM01':
.NOTES
    Script name: Add-CMWSUSScanRetryErrorCodes.ps1
    Author:      Nickolaj Andersen
    Contact:     @NickolajA
    DateCreated: 2015-04-07 
#>
[CmdletBinding(SupportsShouldProcess=$true)]
param(
    [parameter(Mandatory=$true,HelpMessage="Site server where the SMS Provider is installed")]
    [ValidateNotNullOrEmpty()]
    [ValidateScript({Test-Connection -ComputerName $_ -Count 1 -Quiet})]
    [string]$SiteServer,
    [parameter(Mandatory=$true,HelpMessage="Specify the error code to add as hexadecimal, e.g. 0x80072ee2")]
    [ValidateNotNullOrEmpty()]
    [ValidateLength(1,10)]
    [ValidatePattern("^0{1}[xX]{1}[0-9a-fA-F]{8}$")]
    [string]$ErrorCode
)
Begin {
    # Determine SiteCode from WMI
    try {
        Write-Verbose "Determining SiteCode for Site Server: '$($SiteServer)'"
        $SiteCodeObjects = Get-WmiObject -Namespace "root\SMS" -Class SMS_ProviderLocation -ComputerName $SiteServer -ErrorAction Stop
        foreach ($SiteCodeObject in $SiteCodeObjects) {
            if ($SiteCodeObject.ProviderForLocalSite -eq $true) {
                $SiteCode = $SiteCodeObject.SiteCode
                Write-Debug "SiteCode: $($SiteCode)"
            }
        }
    }
    catch [System.UnauthorizedAccessException] {
        Write-Warning -Message "Access to WMI on target '$($SiteServer)' was denied" ; break
    }
    catch [Exception] {
        Write-Warning -Message "Unable to determine SiteCode" ; break
    }
    # Convert hexadecimal error code to decimal
    try {
        $RetryCodeUInt = [System.Convert]::ToUInt32($ErrorCode, 16) -as [string]
        Write-Verbose -Message "Converted error code '$($ErrorCode)' to '$($RetryCodeUInt)'"
    }
    catch [Exception] {
        Write-Warning -Message "Unable to convert error code '$($ErrorCode)' to decimal" ; break
    }
    # Define ErrorActionPreference
    $ErrorActionPreference = "Stop"
}
Process {
    # Get all WSUS Components
    $WSUSComponents = Get-WmiObject -Namespace "root\SMS\site_$($SiteCode)" -Class SMS_SCI_Component -ComputerName $SiteServer -Filter "ComponentName like 'SMS_WSUS_CONFIGURATION_MANAGER'"
    if ($WSUSComponents -ne $null) {
        foreach ($WSUSObject in $WSUSComponents) {
            $WSUSObjectProps = $WSUSObject.Props
            foreach ($WSUSObjectProp in $WSUSObjectProps) {
                # Get the WSUS Scan Retry Error Codes object
                if ($WSUSObjectProp.PropertyName -like "WSUS Scan Retry Error Codes") {
                    if ($WSUSObjectProp.Value2 -notmatch $RetryCodeUInt) {
                        $UpdatedRetryCodes = $WSUSObjectProp.Value2.Replace("}","") + ", $($RetryCodeUInt)"
                        $UpdatedRetryCodes = $UpdatedRetryCodes.Insert($UpdatedRetryCodes.Length, "}")
                        $WSUSObjectProp.Value2 = $UpdatedRetryCodes
                        # Update WMI object with new Props object
                        if ($PSCmdlet.ShouldProcess($WSUSObject.ItemName, "Update Scan Retry Codes")) {
                            try {
                                $WSUSObject.Props = $WSUSObjectProps
                                $WSUSObject.Put() | Out-Null
                            }
                            catch [Exception] {
                                Write-Warning -Message "An error occured while attempting to update WMI object" ; break
                            }
                        }
                    }
                    else {
                        Write-Warning -Message "Specified error code is already present on object '$($WSUSObject.ItemName)'"
                    }
                }
            }
        }
    }
    else {
        Write-Warning -Message "No WSUS Components was found"
    }
}

In my lab environment I have 3 Software Update Points. One on my CAS and one for each of my Primary Sites. When executing this script, that would add the error code for each of the SMS_WSUS_CONFIGURATION_MANAGER components in all sites.

Here’s an example of how the script could be executed:

1. Open an elevated PowerShell console and browse to C:\Scripts (or wherever you chose to save the above script).
2. Run the following command:

.\Add-CMWSUSScanRetryErrorCodes.ps1 -SiteServer CAS01 -ErrorCode 0x80072ee2 -Verbose

137_5

As shown in the verbose output from the script, all of the components has been updated with the error code 2147954402. Once the clients pick up this change, the WUAHandler.log should start to show that the switching is taking place:

137_2

I hope this helps and if you have any questions, feel free to comment below.

4 Comments

  1. Pingback: Installing SCCM site systems in a DMZ environment | microsoftramblings

  2. Chandru

    Thank you very much.. I followed the steps and I dont see the error anymore on our clients.
    I just need to wait now and see whether it will download the patches and install

    Reply
  3. bdam

    Have you tried this in Current Branch (currently 1602)? I’ve set this on our single primary server but the clients don’t seem to be getting the new list even after refreshing the various policies on them.

    Reply
    1. bdam

      Never mind, I’m dumb. The client I was working on was pointed at the wrong site.

      That being said, here’s a PowerShell one-liner to list the error codes on the client:
      (Get-WmiObject -Namespace “ROOT\ccm\policy\Machine\ActualConfig” -Class CCM_UpdateSource).ScanFailureRetryErrorCodes

      Reply

Leave a Comment

Your email address will not be published. Required fields are marked *