Synchronize Active Directory Information with Sharepoint Foundation 2013 User Profiles

By | March 27, 2014

You might be wondering why should I do this when Sharepoint can do this already though User Profile Synchronization, well that is partly true because in Sharepoint Foundation 2013 and even on 2010 it is not available.  Having said that there will always be a way and that’s what are trying to achieve on this article, to synchronize Active Directory Information with Sharepoint User Profile by doing some coding.  This can be achieved in multiple ways, you can do Powershell, you can create a Sharepoint feature or develop a standalone application, we will do the latter as for me its more flexible and manageable.

01 Ad and Sharepoint

Now lets start but before doing so lets lay out some ground work and give some explanation on how to we go about on this one.


Did you know that Sharpoint stores user profiles in a list as well?  It’s sort of hidden but in case you did not know you can locate it at:

http://{YourSharepointUrl}/_catalogs/users/simple.aspx

And it will look like this

02 User List


But something is different, unlike normal lists it does not give you the tabs to manipulate the list or its view but that does not stop us in doing so as it is just a web part in a page, having said that you can still edit the page.

03 Edit Page

and edit the web part

04 Edit The Web Part


then edit the current view

05 Edit the current view

and there you are

06 View Edit

free to change how your view looks like.


That does not end there, you can also edit the list by adding column of your choice.  It’s not straightforward though as you need to know your List Id by checking it in the URL while you in the view property page.

07 List Id

Now copy that and combine it with the URL below to view your List Properties

http://{YourSharepointURL}/_layouts/listedit.aspx?List={YourListIdHere}

And whoalla! you can now edit your list.

08 Manage List

So now lets say we add Description, Office and Company which is not there by default.

09 Update List

Once saved you can now see it on the view

10 It shows now on the view

Now that you know that the user profiles are saved on a list and you can modify the structure of it let’s do some coding and map our Active Directory with Sharepoint User Data.  For this example we will map the common and the most logical fields we usually use.

11 Mapping

Although it shows the proper name on the view the field names might not be the same, so if you run the codes below and investigate what the field names are it would look like this.

11a Mapping Sp

So make sure you map it to the correct Sharepoint and Active Directory fields/columns, for our example it will be like this.

View Labels
Sharepoint Name
Active Directory Name
NameTitledisplayName
E-MailEMailmail
Job TitleJobTitletitle
DepartmentDepartmentdepartment
Mobile NumberMobilePhonemobile
DDIDDItelephoneNumber
SIP AddressSIPAddressipPhone
DescriptionDescriptiondescription
OfficeOfficephysicalDeliveryOfficeName
CompanyCompanycompany

Now lets start coding.  What we will do first is a simple listing of all Site Users, to do that copy and paste the codes below.

private static void GetAllSiteUsers()
{
    // Starting with ClientContext, the constructor requires a URL to the server running SharePoint. 
    var sharepointContext = new ClientContext("http://yoursharepointurl/");
 
    //Get Web Context
    var sharepointList = sharepointContext.Web.SiteUserInfoList;
 
    var camlQuery = new CamlQuery();
 
    var userList = sharepointList.GetItems(camlQuery);
    sharepointContext.Load(userList);
    sharepointContext.ExecuteQuery();
 
    foreach (ListItem user in userList)
    {
               
    }
}

Run it and lets see your first data, the first user that will appear is the one who set up your Sharepoint Instance, which means you are safe to assume that it is a real user.

12 Filtering Users

Place a breakpoint and investigate your results.  If you notice when you run the code it will give you all the List Items and in our example we have 2399 items, we need to filter it further because the whole list contains Users, Active Directory Groups and Sharepoint Groups.  What we need to sync only are the Users so we need to identify which are the users somehow.

After looking at my example I have two Field values that I can use, first is the ContentTypeId which if you further investigate is common for all Users other entities have a different ContentTypeId.  Another is the Name where all users will have a Claims Authentication Code and Domain Prefix ie i:0#.w|YourDomainUserName other entities such as group is prefixed as c:0+.w|  followed by and SID.

Now we know how to filter lets apply that to the CAML Query and further filter our results.

private static void GetAllSiteUsersFilteredByType()
{
    // Starting with ClientContext, the constructor requires a URL to the server running SharePoint. 
    var sharepointContext = new ClientContext("http://yoursharepointurl/");
 
    //Get Web Context
    var sharepointList = sharepointContext.Web.SiteUserInfoList;
 
    //Prefix for all users
    string userType = "i:0#.w|";
 
    var camlQuery = new CamlQuery();
    camlQuery.ViewXml = @"<FieldRef Name='Name' />" + userType + "</Value></Contains></Where></Query></View>";
 
    var userList = sharepointList.GetItems(camlQuery);
    sharepointContext.Load(userList);
    sharepointContext.ExecuteQuery();
 
    foreach (ListItem user in userList)
    {
 
    }
}

13 Filtered

Now you will see we have lesser result count as we only get the real users.

Let’s do the synchronization Part!

By now you know how to get all that users now we need to search for the same user in Active Directory get its information and overwrite the ones in Sharepoint.  The codes below is complete but I just created them in one class as a console application, it’s up to you how you want to use them.

The codes also takes into consideration that service user you will be using have full rights on Active Directory and is in the Site Collection Administrators Group on Sharepoint.

using Microsoft.SharePoint.Client;
using System.DirectoryServices;
using System.DirectoryServices.AccountManagement;
 
namespace Sharepoint_User_and_Active_Directory_Sync
{
    static class Program
    {
        //If you're using claims authentication, this defines a user on a domain
        const string userType = "i:0#.w|";
        //If you're not using claims authentication, this defines a user on a domain
        //const string userType = @"YourDomain"; 
 
        const string domain = "your.sharepoint.com";
        const string rooOrganizationalUnit = "DC=your,DC=sharepoint,DC=com";
        const string adDomain = "YOURDOMAIN";
        const string adUserName = "YourServiceUser";
        const string adPassword ="YourServiceUserPassword";
 
        static void Main(string[] args)
        {
 
            // Starting with ClientContext, the constructor requires a URL to the server running SharePoint. 
            var sharepointContext = new ClientContext("http://yoursharepointurl/");
            sharepointContext.Credentials = new System.Net.NetworkCredential(adUserName, adPassword, adDomain);
 
            //Get Site Users Lists
            var sharepointList = sharepointContext.Web.SiteUserInfoList;
            
            //Filter User List by CAML Query
            var camlQuery = new CamlQuery();
            camlQuery.ViewXml = @"<FieldRef Name='Name' />" + userType + "</Value></Contains></Where></Query></View>";
            var userList = sharepointList.GetItems(camlQuery);
            sharepointContext.Load(userList);
            sharepointContext.ExecuteQuery();
 
            //Loop Through Each User
            foreach (ListItem user in userList)
            {
                //Lets remove the Claims Authentication Prefix
                var userName = user["Name"].ToString().Replace(userType, "");
 
                //Get the User Details from Active Directory
                UserPrincipal userPrincipal = GetUser(userName);
 
                //if User Principal Exists
                if (userPrincipal != null)
                {
                    user["Title"] = userPrincipal.DisplayName;
                    user["EMail"] = userPrincipal.EmailAddress;
                    user["Description"] = userPrincipal.Description;
                    user["DDI"] = userPrincipal.VoiceTelephoneNumber;
 
                    //Unrepresented AD Attributes in User Principal, we have to use 
                    //our own extension method called GetProperty to retrieve AD Value
                    user["JobTitle"] = userPrincipal.GetProperty("title");
                    user["Department"] = userPrincipal.GetProperty("department");
                    user["MobilePhone"] = userPrincipal.GetProperty("mobile");
                    user["SipAddress"] = userPrincipal.GetProperty("ipPhone");
                    user["Office"] = userPrincipal.GetProperty("physicalDeliveryOfficeName");
                    user["Company"] = userPrincipal.GetProperty("company");
 
                    //Update User
                    user.Update();
 
                    //Commit Changes
                    sharepointContext.ExecuteQuery();
                }
            }
        }
 
        /// <summary>
        /// Gets the base principal context
        /// </summary>
        /// <returns>Retruns the PrincipalContext object</returns>
        private static PrincipalContext GetPrincipalContext()
        {
            PrincipalContext principalContext;
 
            principalContext = new PrincipalContext(ContextType.Domain, domain, rooOrganizationalUnit, ContextOptions.Negotiate, adDomain + @"" + adUserName, adPassword);
 
            return principalContext;
        }
 
        /// <summary>
        /// Gets a certain user on Active Directory
        /// </summary>
        /// <param name="userName">The username to get</param>
        /// <returns>Returns the UserPrincipal Object</returns>
        private static UserPrincipal GetUser(string userName)
        {
            try
            {
                var principalContext = GetPrincipalContext();
 
                var userPrincipal = UserPrincipal.FindByIdentity(principalContext, userName);
                return userPrincipal;
            }
            catch
            {
                return null;
            }
        }
 
        /// <summary>
        /// Gets the AD Attributes not represented in UserPrincipal
        /// </summary>
        /// <param name="principal">The User Principal Object</param>
        /// <param name="property">The property name you want to retrieve</param>
        /// <returns></returns>
        private static string GetProperty(this UserPrincipal principal, string property)
        {
            var directoryEntry = principal.GetUnderlyingObject() as DirectoryEntry;
 
            if (directoryEntry.Properties.Contains(property))
            {
                return directoryEntry.Properties[property].Value.ToString();
            }
            else
            {
                //Property not exisiting return empty strung
                return string.Empty;
            }
        }
    }
}

That’s it, now you can sync your Active Directory User Information to your Sharepoint Foundation 2013 regularly.

Recommended

22 thoughts on “Synchronize Active Directory Information with Sharepoint Foundation 2013 User Profiles

  1. Atiq

    Hi please suggest do i need below line if i create a timer service?

    sharepointContext.Credentials = new System.Net.NetworkCredential(adUserName, adPassword, adDomain);

    And anything else i need to change to work it in a timer service?

    Kind regards

    Atiq zia

    Reply
      1. Atiq

        Thank you so much for the reply and its solve my issue. Now i need your suggestion does your Getuser code will work if there are multiple OU and also an OU further can have sub level OU. I actually need code which should work in finding user regardless how much OU and sub level OU are created in AD.

        Best regards
        Atiq zia

        Reply
  2. Sampath

    Can you send me source files please, if possible.
    I’m new to SharePoint, and not understanding how to write the code and where?

    Reply
    1. Raymund Macaalay Post author

      You can choose whatever you want depending on how you would run it, for me I just created a console application that is called by Task Scheduler on predefined schedule.

      Reply
  3. David

    Nice tutorial hovewer I am not sure where and how to code. What application are you using?. What programing language and program are you using?

    Other that that it is very good and simple to follow article.

    Reply
  4. Adriano da Silveira

    Hi man, nice post about this. I was trying to search some informations about the sync using Sharepoint 2013 at a server stand alone.
    Would you tell me if as possible, sync the AD to the Sharepoint Foundations 2013 in this kind of server? Or using your post methods looks more safety?

    Thanks in advance,
    Best regards,

    Reply
      1. Adriano da Silveira

        All right, thanks for you reply. So can I import all my Farm to the AD, to do this sync?

        Thanks again,
        Best regards,

        Reply
  5. Alik

    Hi, i’m new in SP.
    It’s not clear for me, how you connected VS(Console C#) with SP2013, can you explain your steps with VS? advance thanks!

    Reply
  6. Michael Moynihan

    Thanks you for posting this article. I am going to work on it today and I am sure it will prove very useful.

    I have a quick question about one of the screen captures though. I don’t know where to go to generate the screen of Attribute-Syntax-Count that listed the active directory properties. It’s the right portion of the screen shot under the caption:

    “Now that you know that the user profiles are saved on a list and you can modify the structure of it let’s do some coding and map our Active Directory with Sharepoint User Data. For this example we will map the common and the most logical fields we usually use.”

    [Path: CN=Raymund Macaaaly]

    I have dug around in Microsoft’s “Active Directory Users and Computers” and can’t find this sort of attribute breakdown.

    Reply
  7. Thiago Sestini

    Hi, Raymund. I see that this will allow me to sync profile data on sharepoint foundation from AD, which is one of the things I wanted to do, so thanks a lot. One thing I don’t know how to do is to display the user profile to the user. If I click “my settings”, nothing happnes. Is it possible to call the data from sharepoint foundation’s user profile for the specific logged user?

    Reply
  8. Lee Davila

    I’m completely new to coding, but I slogged through to running the first code (as a .cs file) I’d substituted our sharepoint foundation 2013 URL. The error I got was: SiteUsers.cs(1,21): error CS0116: A namespace cannot directly contain members such as fields or methods. The build failed.
    Obviously, the .cs doesn’t contain namespaces. I’m confused!

    Reply

Leave a Reply to MaheshCancel reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.