Sunday, June 5, 2016

Update User Profile properties in SharePoint online

I had a requirement from our client that we need to update some of the user AD properties with the SharePoint user profile properties regularly.

So, for that i have build a console application to update the properties and i have scheduled it as a Windows scheduler.

I have kept all the settings (LDAP connection string, AD admin username, password etc.. ) in the app.config file so that i don't have to specify them in the code.

Below is the App.Config file code.

<appSettings>
    <add key="tenantAdministrationUrl" value=""/>
    <add key="tenantAdminLoginName" value=""/>
    <add key="tenantAdminPassword" value=""/>
    <add key="UserProfileProperties" value="WorkPhone|CellPhone"/>   
    <add key="UserProfilePrimeProperty" value="WorkEmail"/>
    <add key="LDAP" value="LDAP://OU="/>
    <add key="ADAdminUserName" value="" />
    <add key="ADAdminPassword" value="" />
    <add key="Properties" value="telephoneNumber|mobile"/>
    <add key="PrimeProperty" value="mail"/>
  </appSettings>
 


Below is the code to retrieve the settings from the app.config file.
Consts._UserProfilePrimeProperty = ConfigurationManager.AppSettings["UserProfilePrimeProperty"];
Consts.ADAdminUserName = ConfigurationManager.AppSettings["ADAdminUserName"];
Consts.ADAdminPassWord = ConfigurationManager.AppSettings["ADAdminPassWord"];
Consts._ProfileProperties = ConfigurationManager.AppSettings["Properties"];
Consts._PrimeProperty = ConfigurationManager.AppSettings["PrimeProperty"];
Consts._tenantAdministrationUrl = ConfigurationManager.AppSettings["tenantAdministrationUrl"];
Consts._tenantAdminLoginName = ConfigurationManager.AppSettings["tenantAdminLoginName"];
Consts._tenantAdminPassword = ConfigurationManager.AppSettings["tenantAdminPassword"];
Consts._UserProfileProfileProperties = ConfigurationManager.AppSettings["UserProfileProperties"];

Below method will retrieve the AD information.

 
public static void getADInformation()
        {
            string ldap = ConfigurationManager.AppSettings["LDAP"];
            Console.WriteLine(ldap);
            if (!string.IsNullOrEmpty(ldap))
            {
                try
                {
                    using (DirectoryEntry ou = new DirectoryEntry(ldap))
                    {
                        DirectorySearcher searcher = new DirectorySearcher(ou);
                        searcher.Filter = "(&(objectClass=user)(objectCategory=person))";
                        searcher.SearchScope = SearchScope.Subtree;
                        searcher.PageSize = 1000;//This has to be set to return all the results from AD, if not set then it will limit the results to 1000 only

                        string[] tempProp = Consts._ProfileProperties.Split('|');
                        string[] properties = new string[tempProp.Count() + 1];
                        properties[0] = Consts._PrimeProperty;
                        for (int i = 1; i <= tempProp.Count(); i++)
                        {
                            properties[i] = tempProp[i - 1];
                        }

                        foreach (var property in properties)
                        {
                            searcher.PropertiesToLoad.Add(property);
                        }

                        SearchResult result;
                        List<string[]> columnValues = new List<string[]>();

                        searcher.PropertiesToLoad.Add("userPrincipalName");
                        searcher.PropertiesToLoad.Add("samAccountName");

                        SearchResultCollection resultCol = searcher.FindAll();
                        Console.WriteLine("Find all");
                        if (resultCol != null)
                        {
                            Console.WriteLine(resultCol.Count + " Results found in AD");
                            for (int i = 0; i < resultCol.Count; i++)
                            {
                                result = resultCol[i];
                                Console.WriteLine(result.Properties["samAccountName"][0] + "-" + result.Properties["userPrincipalName"][0]);

                                string[] tempPropVal = new string[properties.Count()];
                                int propCnt = 0;
                                //get each property value to array
                                foreach (var property in properties)
                                {
                                    if (result.Properties.Contains(property))
                                    {
                                        tempPropVal[propCnt] = Convert.ToString(result.Properties[property][0]);
                                    }
                                    else
                                    {
                                        tempPropVal[propCnt] = "";
                                    }
                                    propCnt++;
                                }
                                columnValues.Add(tempPropVal);
                            }
                        }

                        string[] tempUserProfileProp = Consts._UserProfileProfileProperties.Split('|');
                        string[] userProfileProperties = new string[tempUserProfileProp.Count() + 1];
                        userProfileProperties[0] = Consts._UserProfilePrimeProperty;
                        for (int i = 1; i <= tempUserProfileProp.Count(); i++)
                        {
                            userProfileProperties[i] = tempUserProfileProp[i - 1];
                        }

                        Consts.UserProdDataCol = new List<Dictionary<string, ExpandoObject>>();

                        foreach (string[] columnValue in columnValues)
                        {
                            dynamic data = new ExpandoObject();
                            //get the first object which is the account
                            string account = columnValue[0];
                            Dictionary<string, ExpandoObject> userProfData = new Dictionary<string, ExpandoObject>();
                            if (!string.IsNullOrEmpty(account))
                            {
                                for (int j = 1; j < userProfileProperties.Count(); j++)
                                {
                                    ((IDictionary<String, Object>)data).Add(userProfileProperties[j], columnValue[j]);
                                }
                                userProfData.Add(account, data);
                                Consts.UserProdDataCol.Add(userProfData);
                            }
                            else
                            {
                                Console.WriteLine(account + " is empty");
                            }
                        }
                    }
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.StackTrace);
                }
            }
        }

Below is the method which will import AD data to user profile.

public static void ImportDatatoCloud(TextWriter writer)
        {
            List<Dictionary<string, ExpandoObject>> dataCollection = Consts.UserProdDataCol;
            int count = 1;
            int totalUsers = dataCollection.Count;
            foreach (var dataCol in dataCollection)
            {
                Generic.LogMessage(string.Format("processing user '{0}' of {1}...", count, totalUsers), Consts.LogLevel.Information);
                var userName = dataCol.Keys.FirstOrDefault();
                dynamic propertySet = dataCol.Values.FirstOrDefault();

                string UserAccountName = Consts._sPOProfilePrefix + userName;

                try
                {
                    using (ClientContext clientContext = new ClientContext(Consts._tenantAdministrationUrl))
                    {
                        SecureString passWord = new SecureString();

                        foreach (char c in Consts._tenantAdminPassword.ToCharArray()) passWord.AppendChar(c);

                        clientContext.Credentials = new SharePointOnlineCredentials(Consts._tenantAdminLoginName, passWord);

                        // Get the people manager instance for tenant context
                        PeopleManager peopleManager = new PeopleManager(clientContext);

                        foreach (var property in propertySet)
                        {
                            string propName = property.Key;
                            string propVal = property.Value;
                            Console.WriteLine(userName + " - " + propName + "->" + propVal);

                            if (propVal.Contains('|'))
                            {
                                // List Multiple values
                                List<string> propValues = propVal.Split('|').ToList<string>();

                                // Update the SPS-Skills property for the user using account name from profile.
                                peopleManager.SetMultiValuedProfileProperty(UserAccountName, propName, propValues);
                            }
                            else
                            {
                                // Update the AboutMe property for the user using account name.
                                peopleManager.SetSingleValueProfileProperty(UserAccountName, propName, propVal);
                            }
                        }

                        clientContext.ExecuteQueryRetry();
                    }
                }
                catch (Exception ex)
                {
                    Console.WriteLine("Issue in updating the profile properties for :" + UserAccountName);
                    writer.WriteLine("Issue in updating the profile properties for :" + UserAccountName);
                    writer.WriteLine(ex.ToString());
                }

                count++;
            }
            Generic.LogMessage("Processing finished for " + totalUsers + " user profiles. Import Complete!", Consts.LogLevel.Warning);
        }

Points to remember: 
Remember to add the sharepoint online client dll's - Microsoft.SharePoint.Client.dll, Microsoft.SharePoint.Client.Runtime.dll, Microsoft.SharePoint.Client.UserProfiles.dll

Hope this code helps you.

Happy Coding :)



No comments:

Post a Comment