We have a large installation supporting 21,000 users with 260 Response groups and about 1200 agents. To enable response group managers to update the agent membership of their response groups, we use distribution lists.
The Synchronisation Task which updates the Agents table in the rgsconfig database from distribution lists crashes continuously under some circumstances which has the result that changes which the users make to the distribution lists may have no effect. If they are unlucky, their distribution list is not processed before the crash point.
The problem senario is this: A person who is an agent in one or more response groups changes their sip address. In our case, the sip address contains a representation of the user's name and so for example a woman marries and changes her name, then she may request a new sip address.
The synchronisation task which updates the Agents table does not find the new sip address and attempts to add it to the table together with other attributes such as the SID of the User object. However, the old row still exists in the Agents table for the users old sip address. But because the User Object SID has not changed and the Table is indexed on the SID Column, it throws an error. Because this error is not handled appropriately, the synchronisation task breaks at this point.
Here is an event log extract ...
======================
Data synchronization from Active Directory failed.
The following exception was thrown during the synchronization process:
Exception: System.Data.SqlClient.SqlException - Cannot insert duplicate key row in object 'dbo.Agents' with unique index 'IX_Agents_UserSid'.
The statement has been terminated.
Inner Exception: ~
The next synchronization attempt will be in 480 minutes.
Cause: Unhandled exception.
Resolution:
Verify the connectivity with the domain controller or if the Active Directory schema was properly applied and all user attributes are present.
======================
The work around (until Microsoft fixes this problem) is to delete the agent's old entry from the agents table. The problem is finding which agent 's entry is causing the problem. In OCS it was possible by setting up a trace using the logging tool on all the RGS components and by examing the trace at the point of the crash, it was possible to find which agent was being added and use the SQL Studio to delete the entry. Not so with Lync. There is a bug which prevents a user viewing the captured traces (etl files) for Response Group components. Microsoft Support have responded quickly in analysing thes files for us but we need to react very quickly when this happens because telephony is mission critical for us. I have developed a powershell procedure for finding entries in the agents table which will cause the synchronisation task to go on to crash. It works by going through the agents table (actually a modified csv dump of the agents table) and getting the matching entries from the AD using the user object's SID. It then reports if the SIP address in the agents table is different to the SIP Address in the AD for a given user object.
Here is the code in case it helps anyone ..
==================== # # Scan CSV file extract from RGS Agent Table # # To use this script, Prepare Agent Table Extract (Copy to Excel, # delete display name column, save to csv, replace all ';' with ',' ) # # # Get AD User object based on SID in Agent Table # Compare SIP Address in Agent Table with that in Userobject. # Report Mismatches # # Douglas Miles 10.06.2011 # # change this ... $agentFile = 'C:\Users\SCIS-TBEMIFR1\Desktop\agentTableDump.txt' Function Get-ADUser { # bits from http://www.wisesoft.co.uk/scripts/ Param($Container, $filter) $dom = [System.DirectoryServices.ActiveDirectory.Domain]::GetCurrentDomain() $root = [ADSI] "LDAP://$($dom.Name)" $objSearcher = New-Object System.DirectoryServices.DirectorySearcher $objSearcher.SearchRoot = $root $objSearcher.PageSize = 1000 $objSearcher.Filter = $Filter $objSearcher.FindAll() } Function Do-All ( $isDebug ) { begin { } process { $in = $_ #convert SID from format "0x01050000000000051500000085E77E2F2AD0375C43170A32E4030800" # to \01\05\00.... format for the LDAP Query... $sidSep = '' for( $i = 2; $i -lt $in.UserSID.Length ; $i = $i + 2 ) { $sidSep += '\' + $in.UserSID.substring($i, 2 ) } # $sidSep + ' - ' + $_.SIPAddress $uobj = Get-adUser -filter "(objectSid=$sidSep)" $uoSIP = [string] $uobj.getdirectoryentry().'msrtcsip-primaryuseraddress' if ( $uoSIP.tolower() -ne $in.SIPAddress.tolower() ) { "Unmatched SIPAddress AgentTable: " + [string] $in.SIPAddress + " ADUserObject:$uoSIP " } } end { } } Import-Csv $agentFile | Do-All( $false ) ====================
If anyone wants to modify this code to directly read from the Agent table instead of a local csv dump of it, please post your code.
Another interesting point about updating agents from distribution lists is that in OCS after a certain patch level, the xml file OcsAppServerHost.exe.config included a section where the user could set the update frequency (default 8 hours) see http://support.microsoft.com/kb/975893 . In Lync, the xml code fragment is missing from OcsAppServerHost.exe.config but you can cut and paste it (carefully because the target file now contains other code !!) from the Knowledge base article or here is the relevant part with an example of a 30 Minute refresh cycle ...
<appSettings>
<add key="AdUpdateInterval" value="30" />
</appSettings>
This works after the response group service is restarted.