Active Directory, for reasons best known to itself, stores many boolean attributes (such as userAccountControl or msExchELCMailboxFlags) together in an aggregate integer rather than separating them into individual attributes.
This presents a problem when manipulating only part of that data while preserving the rest.
For example, to disable a user’s account, you must set the userAccountControl attribute to 0x0202 (0x002 + 0x0200). Which, in decimal, is 514 (2 + 512).
Doing this sort of arithmetic is fine if you know what all the flags should be. If, however, you only want to flip one of them (for example to activate an Archive Mailbox on a user while preserving the Litigation Hold flag), you need to be a bit more subtle.
I’m going to start with a little helper function which we use in FIM to manage the msExchELCMailboxFlags attribute:
Private Function BitwiseSet(flagset As Integer, pos As Integer, value As Boolean) As Integer
pos = 2 ^ (pos - 1)
If value Then
Return flagset Or pos
Else
Return flagset And Not pos
End If
End Function
This function takes an existing integer to work on, an offset for the flag (least significant bit is 1 rather than 0) and a boolean (true/false) of what that bit should be set to. For example, to set ElcV2 (2) and ValidArchiveDatabase and (32) both to true, enabling the archive mailbox) we’d call:
BitwiseSet(msExchELCMailboxFlags, 2, True)
BitwiseSet(msExchELCMailboxFlags, 6, True)
Tying that in to FIM’s export attribute flow API (MapAttributesForExport), this ends up looking like:
Public Sub MapAttributesForExport _
(ByVal FlowRuleName As String, ByVal mventry As MVEntry, ByVal csentry As CSEntry) _
Implements IMASynchronization.MapAttributesForExport
Select Case FlowRuleName
Case "export:msExchELCMailboxFlags"
'Const ExpirationSuspended As Integer = 1
Const ElcV2 As Integer = 2
'Const DisableCalendarLogging As Integer = 3
'Const LitigationHold As Integer = 4
'Const SingleItemRecovert As Integer = 5
Const ValidArchiveDatabase As Integer = 6
Dim msExchELCMailboxFlags As Integer
If csentry("msExchELCMailboxFlags").IsPresent Then
msExchELCMailboxFlags = csObject._msExchELCMailboxFlags.Value
Else
msExchELCMailboxFlags = 0 ' Nothing
End If
If isMailboxUser(mvObject) Then
msExchELCMailboxFlags = _
BitwiseSet(msExchELCMailboxFlags, ElcV2, True)
msExchELCMailboxFlags = _
BitwiseSet(msExchELCMailboxFlags, ValidArchiveDatabase, True)
Else
msExchELCMailboxFlags = _
BitwiseSet(msExchELCMailboxFlags, ElcV2, False)
msExchELCMailboxFlags = _
BitwiseSet(msExchELCMailboxFlags, ValidArchiveDatabase, False)
End If
If msExchELCMailboxFlags = 0 Then
If csentry("msExchELCMailboxFlags").IsPresent Then
csentry("msExchELCMailboxFlags").Delete()
End If
Else
csentry("msExchELCMailboxFlags").Value = msExchELCMailboxFlags
End If
Case Else
Throw New UnexpectedDataException(String.Format("MapAttributesForExport: Unknown flow rule '{0}'", FlowRuleName))
End Select
End Sub