Exemple #1
0
        public string DetermineOrigAndNewAttributeValue(UpdateOpContext context, ConnectorObject origObject, ICollection <ConnectorAttribute> attributesForReplace, string attributeName, out string origAttributeValue)
        {
            ConnectorAttribute originalAttribute = origObject.GetAttributeByName(attributeName);

            if (originalAttribute != null)
            {
                origAttributeValue = ConnectorAttributeUtil.GetAsStringValue(originalAttribute);
            }
            else
            {
                origAttributeValue = null;
            }

            ConnectorAttribute newAttribute = ConnectorAttributeUtil.Find(attributeName, attributesForReplace);

            if (newAttribute != null)
            {
                return(ConnectorAttributeUtil.GetAsStringValue(newAttribute));
            }
            else
            {
                return(origAttributeValue);
            }

            /*
             * string deltaValue = ConnectorAttributeUtil.GetAsStringValue(attribute);
             * if (attribute == null) {
             *  return origAttributeValue;
             * }
             * switch (context.UpdateType) {
             *  case UpdateType.ADD:
             *      if (deltaValue == null) {
             *          return origAttributeValue;
             *      }
             *      if (origAttributeValue != null && !origAttributeValue.Equals(deltaValue)) {
             *          throw new ArgumentException("Multiple values for " + attribute.Name + " are not allowed: existing = " + origAttributeValue + ", one being added = " + deltaValue);
             *      } else {
             *          return deltaValue;
             *      }
             *  case UpdateType.REPLACE:
             *      return deltaValue;
             *  case UpdateType.DELETE:
             *      if (deltaValue == null) {
             *          return origAttributeValue;
             *      }
             *      if (origAttributeValue == null || !origAttributeValue.Equals(deltaValue)) {
             *          LOGGER.TraceEvent(TraceEventType.Warning, CAT_DEFAULT, "Trying to remove value from " + attribute.Name + " that is not there: " + deltaValue);
             *          return origAttributeValue;
             *      } else {
             *          return null;
             *      }
             *  default:
             *      throw new ArgumentException("Invalid update type: " + context.UpdateType);
             * } */
        }
Exemple #2
0
        /// <summary>
        /// Helper method: Gets attribute value from the attribute collection
        /// </summary>
        /// <param name="attName">attribute name</param>
        /// <param name="attributes">collection of attribute</param>
        /// <returns>Attribute value as object, null if not found</returns>
        /// <exception cref="ArgumentNullException">If some of the params is null</exception>
        internal static object GetAttValue(string attName, ICollection <ConnectorAttribute> attributes)
        {
            Assertions.NullCheck(attName, "attName");
            Assertions.NullCheck(attributes, "attributes");

            object             value     = null;
            ConnectorAttribute attribute = ConnectorAttributeUtil.Find(attName, attributes);

            if (attribute != null)
            {
                value = ConnectorAttributeUtil.GetSingleValue(attribute) ?? string.Empty;
            }

            return(value);
        }
Exemple #3
0
        /// <summary>
        /// Helper method: Sets attribute value in the attribute collection
        /// </summary>
        /// <param name="attName">attribute name</param>
        /// <param name="attValue">attribute value (if null, we will remove the attribute from the collection)</param>
        /// <param name="attributes">collection of attribute</param>
        /// <exception cref="ArgumentNullException">If some of the params is null</exception>
        internal static void SetAttValue(string attName, object attValue, ICollection <ConnectorAttribute> attributes)
        {
            Assertions.NullCheck(attName, "attName");
            Assertions.NullCheck(attributes, "attributes");

            ConnectorAttribute attribute = ConnectorAttributeUtil.Find(attName, attributes);

            if (attribute != null)
            {
                attributes.Remove(attribute);
            }
            if (attValue != null)
            {
                attributes.Add(ConnectorAttributeBuilder.Build(attName, new object[] { attValue }));
            }
        }
Exemple #4
0
            private IList <object> GetValuesSorted(ConnectorObject resource, string field)
            {
                ConnectorAttribute value = ConnectorAttributeUtil.Find(field, resource.GetAttributes());

                if (value == null || value.Value == null || value.Value.Count == 0)
                {
                    return(CollectionUtil.NullAsEmpty <object>(null));
                }
                if (value.Value.Count > 1)
                {
                    var results = new List <object>(value.Value);
                    results.Sort(ValueComparator);
                    return(results);
                }
                return(value.Value);
            }
Exemple #5
0
        /// <summary>
        /// Helper method: Gets attribute values from the attribute collection
        /// </summary>
        /// <param name="attName">attribute name</param>
        /// <param name="attributes">collection of attribute</param>
        /// <returns>Attribute value as collection of objects, null if not found</returns>
        /// <exception cref="ArgumentNullException">If some of the params is null</exception>
        internal static IList <object> GetAttValues(string attName, ICollection <ConnectorAttribute> attributes)
        {
            Assertions.NullCheck(attName, "attName");

            if (attributes == null)
            {
                return(null);
            }

            ConnectorAttribute attribute = ConnectorAttributeUtil.Find(attName, attributes);

            if (attribute != null)
            {
                return(attribute.Value);
            }
            else
            {
                return(null);
            }
        }
Exemple #6
0
        public Uid Create(ObjectClass objClass, ICollection <ConnectorAttribute> attrs, OperationOptions options)
        {
            StringBuilder      sb            = new StringBuilder();
            ConnectorAttribute NameAttribute = ConnectorAttributeUtil.Find(Name.NAME, attrs);

            if (NameAttribute == null)
            {
                throw new ConnectorException("The name operational attribute cannot be null");
            }

            string parameter = ConnectorAttributeUtil.GetAsStringValue(NameAttribute);

            string[] login = parameter.Split('@');

            PowerShell PowerShellInstance = PowerShell.Create();

            PowerShellInstance.AddCommand(this.config.createScript + "create.ps1");
            PowerShellInstance.AddArgument(login[0]);

            Collection <PSObject>    results;
            Collection <ErrorRecord> errors;

            results = PowerShellInstance.Invoke();
            errors  = PowerShellInstance.Streams.Error.ReadAll();

            if (errors.Count > 0)
            {
                foreach (ErrorRecord error in errors)
                {
                    sb.AppendLine(error.ToString());
                }

                throw new ConnectorException(sb.ToString());
            }
            else
            {
                return(new Uid(ConnectorAttributeUtil.GetAsStringValue(NameAttribute)));
            }
        }
Exemple #7
0
        public Uid Update(ObjectClass objclass, Uid uid, ICollection <ConnectorAttribute> replaceAttributes, OperationOptions options)
        {
            StringBuilder sb = new StringBuilder();
            PowerShell    PowerShellInstance = PowerShell.Create();

            ConnectorAttribute StatusAttribute = ConnectorAttributeUtil.Find(OperationalAttributes.ENABLE_NAME, replaceAttributes);
            String             enable          = ConnectorAttributeUtil.GetAsStringValue(StatusAttribute).ToLower();

            string parameter = ConnectorAttributeUtil.GetAsStringValue(uid);

            string[] login = parameter.Split('@');

            if (enable.Equals("false"))
            {
                PowerShellInstance.AddCommand(this.config.createScript + "disable.ps1");
                PowerShellInstance.AddArgument(login[0]);

                Collection <PSObject>    results;
                Collection <ErrorRecord> errors;

                results = PowerShellInstance.Invoke();
                errors  = PowerShellInstance.Streams.Error.ReadAll();

                if (errors.Count > 0)
                {
                    foreach (ErrorRecord error in errors)
                    {
                        sb.AppendLine(error.ToString());
                    }

                    throw new ConnectorException(sb.ToString());
                }
                else
                {
                    return(uid);
                }
            }
            else if (enable.Equals("true"))
            {
                PowerShellInstance.AddCommand(this.config.createScript + "enable.ps1");
                PowerShellInstance.AddArgument(login[0]);

                Collection <PSObject>    results;
                Collection <ErrorRecord> errors;

                results = PowerShellInstance.Invoke();
                errors  = PowerShellInstance.Streams.Error.ReadAll();

                if (errors.Count > 0)
                {
                    foreach (ErrorRecord error in errors)
                    {
                        sb.AppendLine(error.ToString());
                    }

                    throw new ConnectorException(sb.ToString());
                }
                else
                {
                    return(uid);
                }
            }
            else
            {
                return(uid);
            }
        }
Exemple #8
0
        /// <summary>
        /// Updates an AD object (also called by create after object is created)
        /// </summary>
        /// <param name="oclass"></param>
        /// <param name="directoryEntry"></param>
        /// <param name="attributes"></param>
        /// <param name="type"></param>
        /// <param name="config"></param>
        internal void UpdateADObject(ObjectClass oclass,
                                     DirectoryEntry directoryEntry, ICollection <ConnectorAttribute> attributes,
                                     UpdateType type, ActiveDirectoryConfiguration config)
        {
            if (oclass.Equals(ObjectClass.ACCOUNT))
            {
                // translate attribute passed in
                foreach (ConnectorAttribute attribute in attributes)
                {
                    // encountered problems when processing change password at the same time
                    // as setting expired.  It would be set to expired, but the change would
                    // clear that.  So we must ensure that expired comes last.
                    if (OperationalAttributes.PASSWORD_EXPIRED_NAME.Equals(attribute.Name))
                    {
                        continue;
                    }

                    AddConnectorAttributeToADProperties(oclass,
                                                        directoryEntry, attribute, type);

                    //  Uncommenting the next line is very helpful in
                    //  finding mysterious errors.
                    // Trace.TraceInformation("Committing after setting attribute {0} to {1}", attribute.Name, attribute.Value);
                    // directoryEntry.CommitChanges();
                }

                directoryEntry.CommitChanges();

                // now do the password change.  This is handled separately, because
                // it might be a user changing his own password, or it might be an
                // administrative change.

                GuardedString gsNewPassword = ConnectorAttributeUtil.GetPasswordValue(attributes);
                if (gsNewPassword != null)
                {
                    GuardedString         gsCurrentPassword = ConnectorAttributeUtil.GetCurrentPasswordValue(attributes);
                    PasswordChangeHandler changeHandler     = new PasswordChangeHandler(_configuration);
                    if (gsCurrentPassword == null)
                    {
                        // just a normal password change
                        changeHandler.changePassword(directoryEntry, gsNewPassword);
                    }
                    else
                    {
                        changeHandler.changePassword(directoryEntry,
                                                     gsCurrentPassword, gsNewPassword);
                    }


                    UserAccountControl.Set(directoryEntry.Properties[ActiveDirectoryConnector.ATT_USER_ACOUNT_CONTROL],
                                           UserAccountControl.PASSWD_NOTREQD, false);
                    directoryEntry.CommitChanges();
                }

                // see note in loop above for explaination of this
                ConnectorAttribute expirePasswordAttribute = ConnectorAttributeUtil.Find(
                    OperationalAttributes.PASSWORD_EXPIRED_NAME, attributes);

                if (expirePasswordAttribute != null)
                {
                    AddConnectorAttributeToADProperties(oclass,
                                                        directoryEntry, expirePasswordAttribute, type);
                    directoryEntry.CommitChanges();
                }

                /*
                 * UserAccountControl.Set(directoryEntry.Properties[ActiveDirectoryConnector.ATT_USER_ACOUNT_CONTROL],
                 *  UserAccountControl.PASSWD_NOTREQD, false);
                 */
                directoryEntry.CommitChanges();

                HandleNameAndContainerChange(type, directoryEntry, attributes, config);
            }
            else if (oclass.Equals(ActiveDirectoryConnector.groupObjectClass))
            {
                // translate attribute passed in
                foreach (ConnectorAttribute attribute in attributes)
                {
                    // Temporary
                    // Trace.TraceInformation(String.Format("Setting attribute {0} to {1}",
                    //    attribute.Name, attribute.Value));
                    AddConnectorAttributeToADProperties(oclass,
                                                        directoryEntry, attribute, type);
                    //                  Uncommenting the next line is very helpful in
                    //                  finding mysterious errors.
                    //                 directoryEntry.CommitChanges();
                }

                directoryEntry.CommitChanges();
                HandleNameAndContainerChange(type, directoryEntry, attributes, config);
            }
            else if (oclass.Equals(ActiveDirectoryConnector.ouObjectClass))
            {
                // translate attribute passed in
                foreach (ConnectorAttribute attribute in attributes)
                {
                    // Temporary
                    // Trace.TraceInformation(String.Format("Setting attribute {0} to {1}",
                    //    attribute.Name, attribute.Value));
                    AddConnectorAttributeToADProperties(oclass,
                                                        directoryEntry, attribute, type);
                    //                  Uncommenting the next line is very helpful in
                    //                  finding mysterious errors.
                    // directoryEntry.CommitChanges();
                }

                directoryEntry.CommitChanges();
                HandleNameAndContainerChange(type, directoryEntry, attributes, config);
            }
            else
            {
                String objectClassName = GetADObjectClass(oclass);
                // translate attribute passed in
                foreach (ConnectorAttribute attribute in attributes)
                {
                    // Temporary
                    // Trace.TraceInformation(String.Format("Setting attribute {0} to {1}",
                    //    attribute.Name, attribute.Value));
                    AddConnectorAttributeToADProperties(oclass,
                                                        directoryEntry, attribute, type);
                    //                  Uncommenting the next line is very helpful in
                    //                  finding mysterious errors.
                    // directoryEntry.CommitChanges();
                }

                directoryEntry.CommitChanges();
                HandleNameAndContainerChange(type, directoryEntry, attributes, config);
            }
        }
Exemple #9
0
        /// <summary>
        /// Creates command based on the commanf info, reading the calues from attributes
        /// </summary>
        /// <param name="cmdInfo">Command defition</param>
        /// <param name="attributes">Attribute values - UID in these is ignored! It should be passed as a separate parameter</param>
        /// <param name="config">Configuration object</param>
        /// <returns>
        /// Ready to execute Command
        /// </returns>
        /// <exception cref="ArgumentNullException">if some of the param is null</exception>
        internal static Command GetCommand(PSExchangeConnector.CommandInfo cmdInfo, ICollection <ConnectorAttribute> attributes, Uid uidAttribute, Name nameAttribute, ExchangeConfiguration config)
        {
            Assertions.NullCheck(cmdInfo, "cmdInfo");

            LOG.Trace("GetCommand: cmdInfo name = {0}", cmdInfo.Name);

            ISet <string> parametersSet = new HashSet <string>();

            // create command
            Command cmd = new Command(cmdInfo.Name);

            if (!string.IsNullOrEmpty(cmdInfo.UidParameter) && !parametersSet.Contains(cmdInfo.UidParameter))
            {
                Uid    uidAttr = uidAttribute != null ? uidAttribute : ConnectorAttributeUtil.GetUidAttribute(attributes);
                string uid     = uidAttr != null?uidAttr.GetUidValue() : null;

                if (uid != null)
                {
                    cmd.Parameters.Add(cmdInfo.UidParameter, ActiveDirectoryUtils.ConvertADGUIDtoObjectGUID(uid));
                    parametersSet.Add(cmdInfo.UidParameter);
                }
            }

            // map name attribute, if mapping specified
            if (!string.IsNullOrEmpty(cmdInfo.NameParameter) && !parametersSet.Contains(cmdInfo.NameParameter))
            {
                Name   nameAttr = nameAttribute != null ? nameAttribute : ConnectorAttributeUtil.GetNameFromAttributes(attributes);
                string name     = nameAttr != null?nameAttr.GetNameValue() : null;;
                if (name != null)
                {
                    cmd.Parameters.Add(cmdInfo.NameParameter, name);
                    parametersSet.Add(cmdInfo.NameParameter);
                }
            }

            if (cmdInfo.UsesConfirm)
            {
                cmd.Parameters.Add("confirm", false);
                parametersSet.Add("confirm");
            }

            if (cmdInfo.UsesDomainController)
            {
                cmd.Parameters.Add("DomainController", ActiveDirectoryUtils.GetDomainControllerName(config));
                parametersSet.Add("DomainController");
            }

            // TODO check this only for user-related operations
            bool emailAddressesPresent     = GetAttValues(ExchangeConnectorAttributes.AttEmailAddresses, attributes) != null;
            bool primarySmtpAddressPresent = GetAttValues(ExchangeConnectorAttributes.AttPrimarySmtpAddress, attributes) != null;

            if (emailAddressesPresent && primarySmtpAddressPresent)
            {
                throw new ArgumentException(ExchangeConnectorAttributes.AttEmailAddresses + " and " + ExchangeConnectorAttributes.AttPrimarySmtpAddress + " cannot be both set.");
            }

            if (attributes != null)
            {
                foreach (string attName in cmdInfo.Parameters)
                {
                    object valueToSet = null;

                    ConnectorAttribute attribute = ConnectorAttributeUtil.Find(attName, attributes);
                    if (attribute != null)
                    {
                        if (attribute.Value != null && attribute.Value.Count > 1)
                        {
                            List <string> stringValues = new List <string>();
                            foreach (object val in attribute.Value)
                            {
                                stringValues.Add(val.ToString());
                            }
                            valueToSet = stringValues.ToArray();
                        }
                        else
                        {
                            valueToSet = ConnectorAttributeUtil.GetSingleValue(attribute);
                        }
                        if (parametersSet.Contains(attName))
                        {
                            throw new InvalidOperationException("Parameter " + attName + " is already defined for command " + cmdInfo.Name);
                        }
                        cmd.Parameters.Add(attName, valueToSet);
                        parametersSet.Add(attName);
                    }
                }
            }

            LOG.Trace("GetCommand exit: cmdInfo name = {0}", cmdInfo.Name);
            return(cmd);
        }
        /// <summary>
        /// DeduplicatesEmailAddresses.
        ///  - on REPLACE (i.e. update/replace or create) the situation is easy: we just remove duplicate entries (SMTP:x & smtp:x result in SMTP:x)
        ///  - on DELETE we currently do nothing
        ///  - on ADD we have one additional rule:
        ///     "If we are adding SMTP:x, we first convert all SMTP:y in existing records to smtp:y because we see the intent of having x to be a new primary"
        ///
        /// </summary>
        /// <param name="context"></param>
        /// <param name="attributes">these are attributes to be set (already resolved if we have update of type ADD or DELETE)</param>
        /// <returns></returns>
        private ICollection <ConnectorAttribute> DeduplicateEmailAddresses(CreateUpdateOpContext context, ICollection <ConnectorAttribute> attributes)
        {
            // trivial cases

            if (context is UpdateOpContext && ((UpdateOpContext)context).UpdateType == UpdateType.DELETE)
            {
                return(attributes);
            }

            ConnectorAttribute attribute = ConnectorAttributeUtil.Find(ExchangeConnectorAttributes.AttEmailAddresses, attributes);

            if (attribute == null || attribute.Value == null)
            {
                return(attributes);      // missing or empty EmailAddresses - nothing to deduplicate
            }
            ConnectorAttribute attributeDelta = ConnectorAttributeUtil.Find(ExchangeConnectorAttributes.AttEmailAddresses, context.Attributes);

            if (attributeDelta == null || attributeDelta.Value == null)
            {
                return(attributes);      // missing or empty changed EmailAddresses - nothing to deduplicate
            }

            // now the main part

            IList <string> valuesToDeduplicate = new List <string>();

            foreach (object o in attribute.Value)
            {
                if (o != null)
                {
                    valuesToDeduplicate.Add(o.ToString());
                }
            }
            bool changed = false;

            // special rule: if ADD with SMTP:, let us change all other "SMTP:x" to "smtp:x"
            Boolean isUpdateAdd = context is UpdateOpContext && ((UpdateOpContext)context).UpdateType == UpdateType.ADD;

            if (isUpdateAdd)
            {
                string newPrimary = null;
                foreach (object o in attributeDelta.Value)
                {
                    if (((string)o).StartsWith("SMTP:"))
                    {
                        newPrimary = (string)o;
                        break;
                    }
                }
                if (newPrimary != null)
                {
                    foreach (string address in new List <string>(valuesToDeduplicate))      // to eliminate concurrent access
                    {
                        if (address.StartsWith("SMTP:") && !address.Equals(newPrimary))
                        {
                            string replacement = "smtp:" + address.Substring(5);
                            LOGGER.TraceEvent(TraceEventType.Information, CAT_DEFAULT, "Changing duplicate primary-candidate address {0} to {1}", address, replacement);
                            valuesToDeduplicate.Remove(address);
                            valuesToDeduplicate.Add(replacement);
                            changed = true;
                        }
                    }
                }
            }

            IDictionary <string, string> values = new Dictionary <string, string>();       // normalized->most-recent-original e.g. SMTP:[email protected] -> SMTP:[email protected] (if primary is present)

            foreach (object v in valuesToDeduplicate)
            {
                string address    = (string)v;
                string normalized = address.ToUpper();
                if (values.ContainsKey(normalized))
                {
                    changed = true;
                    string existing = values[normalized];
                    if (address.StartsWith("SMTP:") && existing.StartsWith("smtp:"))
                    {
                        LOGGER.TraceEvent(TraceEventType.Information, CAT_DEFAULT, "Removing redundant address {0}, keeping {1}", existing, address);
                        values[normalized] = address;
                    }
                    else
                    {
                        LOGGER.TraceEvent(TraceEventType.Information, CAT_DEFAULT, "Removing redundant address {0}, keeping {1}", address, existing);
                    }
                }
                else
                {
                    values.Add(normalized, address);
                }
            }
            if (changed)
            {
                ConnectorAttributeBuilder cab = new ConnectorAttributeBuilder();
                cab.Name = ExchangeConnectorAttributes.AttEmailAddresses;
                foreach (string value in values.Values)
                {
                    cab.AddValue(value);
                }
                ICollection <ConnectorAttribute> rv = new List <ConnectorAttribute>(attributes);          // the original is (sometimes) a read-only collection
                rv.Remove(attribute);
                rv.Add(cab.Build());
                return(rv);
            }
            else
            {
                return(attributes);
            }
        }
        public void Create(CreateOpContext context)
        {
            context.Attributes = DeduplicateEmailAddresses(context, context.Attributes);

            // get recipient type
            string rcptType = ExchangeUtility.GetAttValue(ExchangeConnectorAttributes.AttRecipientType, context.Attributes) as string;

            if (rcptType == null || rcptType.Equals(""))
            {
                rcptType = ExchangeConnectorAttributes.RcptTypeUser;
            }

            ExchangeConnector        exconn = (ExchangeConnector)context.Connector;
            ActiveDirectoryConnector adconn = exconn.ActiveDirectoryConnector;

            PSExchangeConnector.CommandInfo cmdInfoEnable = null;
            PSExchangeConnector.CommandInfo cmdInfoSet    = null;
            switch (rcptType)
            {
            case ExchangeConnectorAttributes.RcptTypeMailBox:
                cmdInfoEnable = PSExchangeConnector.CommandInfo.EnableMailbox;
                cmdInfoSet    = PSExchangeConnector.CommandInfo.SetMailbox;
                break;

            case ExchangeConnectorAttributes.RcptTypeMailUser:
                cmdInfoEnable = PSExchangeConnector.CommandInfo.EnableMailUser;
                cmdInfoSet    = PSExchangeConnector.CommandInfo.SetMailUser;
                break;

            case ExchangeConnectorAttributes.RcptTypeUser:
                break;

            default:
                throw new ArgumentException(
                          context.ConnectorConfiguration.ConnectorMessages.Format(
                              "ex_bad_rcpt", "Recipient type [{0}] is not supported", rcptType));
            }

            // first create the object in AD
            ICollection <ConnectorAttribute> adAttributes = ExchangeUtility.FilterOut(context.Attributes,
                                                                                      PSExchangeConnector.CommandInfo.EnableMailbox,
                                                                                      PSExchangeConnector.CommandInfo.SetMailbox,
                                                                                      PSExchangeConnector.CommandInfo.EnableMailUser,
                                                                                      PSExchangeConnector.CommandInfo.SetMailUser);
            Uid uid = adconn.Create(context.ObjectClass, adAttributes, context.Options);

            if (rcptType == ExchangeConnectorAttributes.RcptTypeUser)
            {
                // AD account only, we do nothing
                context.Uid = uid;
                return;
            }

            // add a empty "EmailAddresses" attribute if needed (address policy is disabled and no addresses are provided)
            ICollection <ConnectorAttribute> enhancedAttributes;
            ConnectorAttribute policyEnabledAttribute = ConnectorAttributeUtil.Find(ExchangeConnectorAttributes.AttEmailAddressPolicyEnabled, context.Attributes);

            if (policyEnabledAttribute != null &&
                ConnectorAttributeUtil.GetBooleanValue(policyEnabledAttribute).HasValue&&
                ConnectorAttributeUtil.GetBooleanValue(policyEnabledAttribute).Value == false &&
                ConnectorAttributeUtil.Find(ExchangeConnectorAttributes.AttPrimarySmtpAddress, context.Attributes) == null &&
                ConnectorAttributeUtil.Find(ExchangeConnectorAttributes.AttEmailAddresses, context.Attributes) == null)
            {
                enhancedAttributes = new HashSet <ConnectorAttribute>(context.Attributes);
                enhancedAttributes.Add(ConnectorAttributeBuilder.Build(ExchangeConnectorAttributes.AttEmailAddresses));
                LOGGER.TraceEvent(TraceEventType.Verbose, CAT_DEFAULT, "Added empty EmailAddresses attribute because address policy use is disabled and no addresses were provided");
            }
            else
            {
                enhancedAttributes = context.Attributes;        // no change
            }

            // prepare the command
            Command cmdEnable = ExchangeUtility.GetCommand(cmdInfoEnable, enhancedAttributes, uid, (ExchangeConfiguration)context.ConnectorConfiguration);
            Command cmdSet    = ExchangeUtility.GetCommand(cmdInfoSet, enhancedAttributes, uid, (ExchangeConfiguration)context.ConnectorConfiguration);

            try {
                _helper.InvokePipeline(exconn, cmdEnable);
                _helper.InvokePipeline(exconn, cmdSet);
            }
            catch {
                LOGGER.TraceEvent(TraceEventType.Information, CAT_DEFAULT, "Rolling back AD create for UID: " + uid.GetUidValue());

                // rollback AD create
                try {
                    adconn.Delete(context.ObjectClass, uid, context.Options);
                } catch {
                    LOGGER.TraceEvent(TraceEventType.Warning, CAT_DEFAULT, "Not able to rollback AD create for UID: " + uid.GetUidValue());
                    // note: this is not perfect, we hide the original exception
                    throw;
                }

                // rethrow original exception
                throw;
            }

            context.Uid = uid;
        }