/// <summary> /// Add or Update user in Destination AD /// return: 0 - succesfully updated /// 1 - succesfully updated and changedImportantProps /// -1 - error /// </summary> public static int AddUser(ADServer server, UserProperties newProps, string cprContent, ADServer[] serversToWait) { // props["userPrincipalName"], props["displayName"], props["givenName"], props["sn"], props["mail"], props["initials"], props["objectSID"] string samAccountName = newProps["samAccountName"][0]; string oldSamAccountName = null; bool isNewUser = false; //bool isChangedOU = false; using (DirectoryEntry searchOU = new DirectoryEntry(server.path, server.ServerUserName, server.ServerPassword, server.authTypes)) { DirectoryEntry oldUser = LoadUserByObjectSID(searchOU, newProps["objectSID"][0], samAccountName); UserProperties oldProps = null; if (oldUser != null) { oldProps = GetUserProperties(oldUser); oldSamAccountName = (string)oldUser.Properties["samAccountName"].Value; } isNewUser = oldUser == null; string transResult; var adHint = ADHintsConfigurationSection.GetOUByAttributes(newProps, oldProps, out transResult); if (adHint == null) { var messageHint = "ADHint is not found for user " + quote(samAccountName) + ". Attributes:" + PrintAttributes(newProps); messageHint += ADHintsConfigurationSection.PrintMemberOfAttributes(newProps.GetPropValue("memberOf")); if (Settings.Default.DataMismatchLogging) { log.LogWarn(messageHint); } else { log.LogDebug(messageHint); } return(0); } var qualityCheck = adHint.QualityCheck(newProps); if (qualityCheck.Count > 0) { log.LogError("QualityCheck validation fails for user '" + samAccountName + "' with attributes:" + Environment.NewLine + string.Join(Environment.NewLine, qualityCheck.ToArray())); return(15); } // Process ... if (adHint.Type == ADHintElement.AdHintType.Terminate) { return(CCMApi.Terminate(oldSamAccountName)); // return 0 if success } string destPath = server.path + "/" + adHint.DestOU; // ="LDAP://myServ.local:636/OU=Office21,OU=Office2,OU=Domain Controllers,DC=myServ,DC=local" using (var destOU = new DirectoryEntry(destPath, server.ServerUserName, server.ServerPassword, server.authTypes)) { string changedImportantProps = transResult; string changedAllProps = ""; string msg = " '" + samAccountName + "' . HintNum=" + adHint.Num + ". " + adHint.Type + ". "; if (isNewUser) // new user { //log.LogInfo(" '" + samAccountName + "' . HintNum=" + adHint.Num + ". New user in '" + destOU.Path + "'" + (server.SSL ? "(SSL)" : "(not SSL)") + " ..."); msg += "Add user into '" + destOU.Path + "'" + (server.SSL ? "(SSL)" : "(not SSL)"); oldUser = destOU.Children.Add("CN=" + samAccountName, "user"); } else { // check if OU is changed for user if (!oldUser.Parent.Path.Equals(destOU.Path, StringComparison.OrdinalIgnoreCase)) { //log.LogInfo(" '" + samAccountName + "' move from '" + oldUser.Parent.Path + "' -> '" + destOU.Path + "' " + (server.SSL ? "(SSL)" : "(not SSL)") + ". HintNum=" + adHint.Num + " ..."); msg += "Move from '" + oldUser.Parent.Path + "' -> '" + destOU.Path + "' " + (server.SSL ? "(SSL)" : "(not SSL)"); oldUser.MoveTo(destOU); changedAllProps += "OU;"; } else { //log.LogInfo(" '" + samAccountName + "' update in OU '" + destOU.Path + "' " + (server.SSL ? "(SSL)" : "(not SSL)") + ". HintNum=" + adHint.Num + " ..."); msg += "Update in OU '" + destOU.Path + "' " + (server.SSL ? "(SSL)" : "(not SSL)"); } } changedImportantProps += CheckAndSetProperty(oldUser.Properties, "samAccountName", new string[] { samAccountName }); // AD key changedAllProps += SetPropertiesToUser(oldUser, newProps); changedAllProps += CheckAndSetProperty(oldUser.Properties, "Pager", newProps["objectSID"]); // the surrogate key bool terminate = !isNewUser && changedImportantProps.Length > 0; if (terminate) { log.LogInfo(msg + ". Terminating. Changed attributes: " + Environment.NewLine + changedAllProps + Environment.NewLine + changedImportantProps); CCMApi.Terminate(oldSamAccountName); } else if (!isNewUser && string.IsNullOrEmpty(changedAllProps) && string.IsNullOrEmpty(changedImportantProps)) { log.LogDebug("No attributes changed. Skip updating."); return(0); // skip to commit } else { log.LogInfo(msg + "Changed attributes: " + Environment.NewLine + changedAllProps + Environment.NewLine + changedImportantProps); } if (!terminate && CCMApi.IsActive(samAccountName) != 0) { return(-1); // card is already active } oldUser.Properties["userAccountControl"].Value = Utils.UserAccountControl.NORMAL_ACCOUNT | Utils.UserAccountControl.ACCOUNTDISABLE | Utils.UserAccountControl.PWD_NOTREQD; //Console.WriteLine(" CommitChanges '" + samAccountName + "' ..."); oldUser.CommitChanges(); if (isNewUser) { WaitDestinationADReplication(samAccountName, newProps["objectSID"][0], serversToWait); } // Dest AD is commited. // Process CCM .... if (Settings.Default.CCMHost.Trim().Length == 0) { log.LogWarn("CCMHost is not set. Skip CCM processing"); return(0); } int ccmResult; try { ccmResult = CCMApi.CreateCPR(samAccountName, cprContent, adHint.CardPolicy); // return 0 if success } catch (Exception ex) { log.LogError(ex, "update user '" + samAccountName + "' in CCM: " + ex.Message); return(-1); } if (ccmResult != 0) { // Rollback AD ... if (oldProps == null) // if created then delete { destOU.Children.Remove(oldUser); destOU.CommitChanges(); } else { SetPropertiesToUser(oldUser, oldProps); // return to oldProps oldUser.CommitChanges(); } log.LogWarn2("Rollback processed in AD for account '" + samAccountName + "' due to CCM error " + ccmResult + ". " + (oldProps == null ? "Account deleted in DestinationAD" : "Account attributes restored in DestinationAD")); return(-1); } return(ccmResult); } } }