In a large environment with many active directory domains and some servers which are not domain members, it is difficult to find all duplicate SusClientIds. Remote registry queries are not an option because there are many systems in protected networks behind firewalls.
So I decided to use the IIS Failed Request Log to detect duplicate SusClientIds.
Install IIS Tracing
Start the Server-Manager and install the following role service:
Tracing (under World Wide Web Services – Health and Diagnostics – Tracing)
Enable Failed-Request Tracing
- Open the Internet Information Services (IIS) Manager
- In the Connections pane, expand the machine name, expand Sites, and then click on the Site, where WSUS runs.
- In the Actions pane, under Configure, click Failed Request Tracing…
- Select the Enable check box.
- Set Maximum number of trace files to [number of WSUS clients x 5]
Configure Failed Request Tracing Rule
- Double-click Failed Request Tracing Rules.
- In the Actions pane, click Add…
- In the Add Failed Request Tracing Rule wizard, on the Specify Content to Trace page, select Custom and enter the value ReportingWebService.asmx. Click Next.
- On the Define Trace Conditions page, select the Status code(s) check box and enter 200 as the status code to trace. Click Next.
- On the Select Trace Providers page, under Providers, select the WWW Server check box. Under Areas, select the Compression check box and clear all other check boxes. Compression is not what we are looking for, but it is required to select at least one Area.
- Under Verbosity, select Verbose.
- Click Finish.
Analyze Logfiles
After some logging (minimum 24h) in the Path C:\inetpub\logs\FailedReqLogFiles\W3SVC[xxxxxxxxx] are many new xml-files are created. This is the work directory for the following steps.
To analyze this files, I wrote the script get-susclientids.ps1 to get a list of all IPs and SusClientIds.
$list = @() Foreach ($file in (Get-ChildItem *.xml)){ $entry = New-Object -TypeName PSObject $filecontent = Get-Content $file.name $SCIline = ($filecontent | ? { $_ -like "*;<Sid>*"}) $remoteaddrline = ($filecontent | ? { $_ -like "*<Data Name=""RemoteAddress"">*"}) $remoteaddr = $remoteaddrline.Substring($remoteaddrline.IndexOf("""RemoteAddress"">")+16,$remoteaddrline.Length-36) If($SCIline -and $SCIline.IndexOf(";<Sid>") -gt 0){ Add-Member -InputObject $entry -MemberType NoteProperty -Name RemoteAddr -Value $remoteaddr Add-Member -InputObject $entry -MemberType NoteProperty -Name SusClientId -Value $SCIline.substring($SCIline.IndexOf(";<Sid>")+12,36) If(@($list | ? { $_.remoteaddr -eq $remoteaddr }).count -lt 1){ $list += $entry } } } $list | export-csv -path susclientids.csv
The result can be queried with this command:
Import-Csv .\susclientids.csv
Example output:
RemoteAddr SusClientId ---------- ----------- 10.0.0.1 aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee 10.0.0.2 ffffffff-0000-1111-2222-333333333333 10.0.0.7 aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee
Finding Duplicates
To find duplicate SusClientIds I wrote the script get-duplicate.ps1:
$duplicates = Import-Csv .\susclientids.csv | sort susclientid | group susclientid | ? { $_.count -gt 1} $list = @() foreach ($duplicateSCI in $duplicates){ foreach ($system in $duplicateSCI.Group){ $entry = New-Object -TypeName PSObject Add-Member -InputObject $entry -MemberType NoteProperty -Name RemoteAddr -Value $system.remoteaddr try { $fqdn = ([System.Net.Dns]::GetHostEntry($system.remoteaddr).Hostname) } catch { $fqdn = "" } Add-Member -InputObject $entry -MemberType NoteProperty -Name FQDN -Value $fqdn Add-Member -InputObject $entry -MemberType NoteProperty -Name SusClientId -Value $system.SusClientId $list += $entry } } $list
Example output:
RemoteAddr FQDN SusClientId ---------- ---- ----------- 10.0.0.1 host1.domain.com aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee 10.0.0.7 host7.domain.com aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee
Now it’s time to reset the SusClientId on the listed systems.