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