We have a customer with a number of custom target systems. These are kept in sync each with its own Synchronization Project. A few days ago, one of the CSV projects learned a new trick. For every new record it detects in the CSV, it produces the following error in the synchronization log…
[B10025] UNSAccountB: Write permission denied for value “UID_UNSContainerB”
If we delete a number of records from UNSAccountB, all these records are added to the list of errors on the next sync.
It’s possible that someone has edited UNSAccountB template code recently, but aside from this, absolutely nothing has changed on the system.
Anyone have any idea of what can be causing this?
We found the exact same error for version 7.0.1 with a message that it was a bug that was fixed by a hotfix. Our customer is on 8.0.2017.1104, is it possible that an old bug has returned?
---
The UID_UNSContainerB is set by the Sync-Project Mapping via a “Key resolution by reference” which is passed the Canonical-name of the container…
Here is the template code for UID_UNSContainerB… data-sync is not checked in the workflow so this code should get skipped entirely. As far as we are aware this is the only code that has been modified recently.
'$FK(UID_Person).UID_Department$
'$FK(UID_Person).UID_Locality$
'$FK(UID_Person).UID_ProfitCenter$
'#If ORG Then
'$FK(UID_Person).UID_Org$
'#End If
'If CBool(Connection.Variables.Get("FULLSYNC")) = False Then
If Not CBool(Variables("FULLSYNC")) Then
Select Case ($FK(UID_TSBBehavior).ITDataUsage:Int$)
Case 0:'do not get data from employee
Case -1:'fill property initially from the ITData of the employee
If Not $[IsLoaded]:Bool$ Then
Value = TSB_ITDataFromOrg($UID_Person$, $UID_TSBAccountDef$, Base.TableDef.Columns("UID_UNSContainerB"))
If $FK(UID_UNSRootB).Ident_UNSRoot$ = "TOPdesk" Then
If $AccountDisabled:Bool$ Then
Dim UID As String = CCC_getDataFromAnyTable("UNSContainerB", "CanonicalName", "TOPdesk/Operators/Archived", "UID_UNSContainerB")
If Not String.IsNullOrEmpty(UID) Then
Value = UID
End If
End If
End If
End If
Case 1:'update property depending on ITData of the employee
Value = TSB_ITDataFromOrg($UID_Person$, $UID_TSBAccountDef$, Base.TableDef.Columns("UID_UNSContainerB"))
If $FK(UID_UNSRootB).Ident_UNSRoot$ = "TOPdesk" Then
If $AccountDisabled:Bool$ Then
Dim UID As String = CCC_getDataFromAnyTable("UNSContainerB", "CanonicalName", "TOPdesk/Operators/Archived", "UID_UNSContainerB")
If Not String.IsNullOrEmpty(UID) Then
Value = UID
End If
End If
End If
End Select
End If
And here is the template code for “cn” which is triggered by a change to UID_UNSContainerB… $Ident_UNSRoot$ = "TOPdesk" for the system with the problem.
If $UID_UNSRootB$ <> "" Then
Dim cnFix, cnNew, DNold, DNnew, wherePart As String
Dim f As ISqlFormatter = Connection.SqlFormatter
'Dim p as IDnParser = VI_GetDnParser("LDAP")
Dim attributeName as String = "CN"
' If targetsystem is configured without containers
If Not $FK(UID_UNSRootB).UsesContainer:Bool$ Then
attributeName = "user"
End If
cnFix = $cn$
If $FK(UID_UNSRootB).Ident_UNSRoot$ = "TOPdesk" Then
If Entity.Columns.Item("Lastname").IsChanged _
OrElse Entity.Columns.Item("Firstname").IsChanged _
OrElse Entity.Columns.Item("AccountName").IsChanged _
OrElse (Not cnFix.EndsWith(")") And Not String.IsNullOrWhiteSpace($AccountName$)) Then
Dim cn = {$Firstname$, $Lastname$}
cnFix = String.Join(" ", cn.Where(Function(o) Not String.IsNullOrWhiteSpace(o)))
If Not String.IsNullOrWhiteSpace($AccountName$) Then
cnFix = String.Format("{0} ({1})", cnFix, $AccountName$)
End If
Else
cnFix = $cn$
End If
Else
If Entity.Columns.Item("Lastname").IsChanged _
OrElse Entity.Columns.Item("Firstname").IsChanged Then
Dim cn = {$Firstname$, $Lastname$}
cnFix = String.Join(" ", cn.Where(Function(o) Not String.IsNullOrWhiteSpace(o)))
Else
cnFix = $cn$
End If
End If
Dim cnLen as Integer = Entity.Columns.Item("cn").MaxLen
cnFix = VID_Left(cnFix, cnLen)
If $cn[o]$<>cnFix OrElse Entity.Columns.Item("UID_UNSContainerB").IsChanged Then
Dim i As Integer = 1
cnNew = cnFix
'to avoid triggering template on change DistinguishedName of parent object no objectwalker used
If $UID_UNSContainerB[o]$ <> "" Then
DNold = VI_GetValueOfObject ("UNSContainerB", "UID_UNSContainerB", $UID_UNSContainerB[o]$, "DistinguishedName")
Else
DNold = VI_GetValueOfObject ("UNSRootB", "UID_UNSRootB", $UID_UNSRootB[o]$, "DistinguishedName")
End If
If $UID_UNSContainerB$ <> "" Then
DNnew = VI_GetValueOfObject ("UNSContainerB", "UID_UNSContainerB", $UID_UNSContainerB$, "DistinguishedName")
Else
DNnew = VI_GetValueOfObject ("UNSRootB", "UID_UNSRootB", $UID_UNSRootB$, "DistinguishedName")
End If
wherePart = f.AndRelation( _
f.UidComparison("UID_UNSAccountB", $UID_UNSAccountB$, CompareOperator.NotEqual), _
f.UidComparison("UID_UNSRootB", $UID_UNSRootB$))
Do While Connection.Exists( "UNSAccountB", _
f.OrRelation( _
f.AndRelation( _
f.Comparison("DistinguishedName", TSB_CreateDN(attributeName, cnNew, DNnew), ValType.String), _
wherePart _
), _
f.AndRelation( _
f.Comparison("DistinguishedName",TSB_CreateDN(attributeName, cnNew, DNOld), ValType.String), _
wherePart _
) _
))
cnNew = VID_Left(cnFix, cnLen - (1 + CStr(i).Length)) & "_" & i
i=i+1
Loop
Value = cnNew
End If
End If
This is the custom function called by the template code..
Public Function CCC_getDataFromAnyTable(ByVal TableName As String, ByVal CompareAttribute As String, ByVal CompareValue As String, ByVal ReturnAttributeName As String) As String
Dim f As ISqlFormatter = connection.SqlFormatter
Dim ccc_objects As IColDbObject = Connection.CreateCol(TableName) 'Maak een collectie van objecten uit deze tabel
ccc_objects.prototype.whereclause = f.Comparison(CompareAttribute,CompareValue,Valtype.string,CompareOperator.Equal)
'Select ... from <table> where <Compareattribute> = '<comparevalue'>
ccc_objects.prototype.Columns(Returnattributename).isDisplayItem = True
'Select ... is translated to a return column here
ccc_objects.Load() 'Load all objects
If ccc_objects.Count > 0 Then
Dim ccc_object As IColElem = ccc_objects(0)
Return ccc_object.GetValue(ReturnAttributeName).String
End If
Return ""
End Function