Tuesday 23 September 2014

Monitor SharePoint User Profile Changes



SharePoint Server 2010 is a great platform for storing information about the users in an organization. Using the User Profile Service application and its related components, you can configure SharePoint to store a variety of information about users and synchronize that information with external storage, such as Active Directory (AD) or any other data source to which you can connect using Business Connectivity Services (BCS).
Users can then edit their information using the user profile pages. The external storage sources will then be updated automatically with this new information, thereby making the information more relevant and timely throughout the organization.
However, allowing users to update their own information introduces new problems when it comes to governance, particularly in terms of security of information, privacy, and ethical conduct. Fortunately, one component of the User Profile Service application is the User Profile Change Service.
The User Profile Change Service isn’t a true service but rather a series of tables within the User Profile Service’s profile database and a timer job (i.e., User Profile Change Cleanup Job) that’s used to clear stored changes older than 14 days.
By default, the User Profile Change Cleanup Job runs once a day. You can adjust this frequency by editing the schedule for this timer job.
You can use the User Profile Change Service to view and report on changes. Unfortunately, however, there isn’t a UI to view these changes, so you must use the SharePoint API to query the system to view changes.
But what kind of changes can you query the system for? The answer is simple: all user profile properties.
You can see the properties that are available by navigating to the Manage Service Applications page in the Central Administration site, selecting a User Profile Service application, and clicking Manage to view the User Profile Management page. (If a User Profile Service application doesn’t exist, you must create one in order to store and manage user details.)
Click the Manage User Properties link to see all the available properties. From here you can create, delete, or edit any properties that you want your users to populate with data. When a user edits any of the values for one of these properties, a change record will be created.
However, it’s important to remember that changes will persist for only 14 days, assuming the User Profile Change Cleanup Job is running. If you need to keep these changes longer, you can change the retention period by running a simple STSADM command. (There’s no Windows PowerShell equivalent way to do this.) The following example changes the retention period to 28 days:
stsadm -o profilechangelog

  -userprofileapplication "My User Profile Service App"

  -daysofhistory 28

(Although the command wraps here, you'd enter it all on one line. The same holds true for the other commands that wrap.)
You can gain access to these change records using the objects in the Microsoft.Office.Server.UserProfiles namespace, which is part of the Microsoft.Office.Server.UserProfiles.dll assembly.
Specifically, you use the UserProfileManager, UserProfileChangeQuery, and UserProfileChangeToken classes.

Retrieving User Profile Changes

To retrieve user profile changes, you must first create an instance of the UserProfileManager class. This class is the gateway for all programmatic manipulations of the user profile properties and their properties.
To create an instance of this class, you must provide it with a Microsoft.SharePoint.SPServiceContext object. This context object makes sure that you’re working with the correct User Profile Service application.
There are two ways to retrieve the SPServiceContext object:
  1. You can provide a specific service application proxy object and a site subscription identifier. (Site subscriptions are only relevant in multi-tenancy scenarios. Most users can use the default site subscription, which is essentially just an empty globally unique identifier—GUID.)
  2. You can provide a site collection that’s associated with the service application.
Listing 1 at the end of this article demonstrates the first approach using PowerShell. Alternatively, you could use code in which the URL to the site collection is passed to the GetContext method. Either approach is perfectly acceptable.
Now that you have the SPServiceContext object, you can create the UserProfileManager object:
$manager = New-Object Microsoft.Office.Server.

UserProfiles.UserProfileManager $context

The UserProfileManager class contains the GetChanges method. This method has three overloads:
  • GetChanges(), which retrieves all changes
  • GetChanges(UserProfileChangeToken), which retrieves all changes from a given date or event
  • GetChanges(ProfileBaseChangeQuery), which retrieves specific changes given a query object
All the GetChanges overloads return a UserProfileChangeCollection object. This object contains all the changes stored as either a UserProfileChange object or one of its derivative types:
  • UserProfileColleagueChange
  • UserProfileCustomChange
  • UserProfileLinkItemChange
  • UserProfileMembershipChange
  • UserProfileOrganizationMembershipChange
  • UserProfilePropertyValueChange
  • UserProfileWebLogChange
Each object type stores the resultant change in a manner most appropriate for the given type. It’s important to note that a separate object will be returned for every change.
So, if a user edits two profile properties, you’ll have at least two objects (one for each property). As the phrase “at least” implies, you could have more than two objects.
For example, if the user edits the Skills property by adding several skills, a separate change object will be returned for each skill added (i.e., one object for each value entered).

Using the GetChanges Method

Let’s look at examples of how to use each overload for the GetChanges method. Figure 1 shows an example of running the GetChanges() method without any parameters.
Running the method in this manner will return all changes in the log, which can be quite numerous.

Figure 1: Example of the GetChanges() method

Figure 1: Example of the GetChanges() method
You can reduce the number of changes returned by passing in a UserProfileChangeToken object to the GetChanges method. This object lets you retrieve changes starting from a specific date.
To do so, you simply specify that date in the change token.
You can also retrieve all the changes created after a certain change event. In this case, you need to specify an arbitrary date and the change event’s ID because there’s no constructor available that accepts only an event ID. Only the event ID will be used; the date will be ignored.
Figure 2 shows an example of running the GetChanges method when you pass in a UserProfileChangeToken object with both the event ID (value of 32) and date ($date, whose value is 1/31/2011) set.
Alternatively, you could provide a value of [System.DateTime]::Now for the $date variable, as the value itself is irrelevant when the event ID is provided. (Note that the UserProfileChangeToken object values can only be set by initializing the object through its constructors.)

Figure 2: Example of the GetChanges(UserProfileChangeToken) method

Figure 2: Example of the GetChanges(UserProfileChangeToken) method
Filtering in this manner, however, can still result in a large number of records returned, particularly if you’re only interested in a specific type of change. To address this concern, you can use the third GetChanges overload and pass in a UserProfileChangeQuery object.
This object gives you the ability to specify exactly what type of changes you want returned. For example, perhaps you only want to know when single-valued properties (such as the AboutMe property) are added or updated. Using the UserProfileChangeQuery object, you can specify what property types and change types you care about.
The UserProfileChangeQuery object’s constructor lets you quickly set all the filtering properties to false. You can then enable just the properties of interest by setting them to true.
For example, the code in Figure 3 sets all the properties to false when it initializes the UserProfileChangeQuery object, then sets the SingleValueProperty, Add, and Update properties to True.

Figure 3: Example of the GetChanges(ProfileBaseChangeQuery) method

Figure 3: Example of the GetChanges(ProfileBaseChangeQuery) method
As you can see, retrieving user profile changes is fairly simple, requiring knowledge of only a few classes and their various members. With PowerShell, you can easily format the returned data a variety of ways. For example, Figure 4 shows Figure 3’s query results formatted into tables and grouped by account.

Figure 4: Example of formatted query results

Figure 4: Example of formatted query results

Empowering Privileged Users to Monitor Changes

Using PowerShell to retrieve information about user changes can be extraordinarily powerful and useful to administrators. But to enforce governance policies, you must bring the ability to monitor changes to privileged users (e.g., HR staff members) and give them the responsibility and authority to properly act on this data.
Let’s examine a real-world example that accomplishes the goal of empowering privileged users.
Suppose that an organization’s HR department has employee policies set in place that govern the communications of employees for email and other types of communication. These policies are extended to the communications in employees’ personal sites and their user profile information.
The HR department wants to monitor updates to visible fields like About me to ensure that the employees are complying with the policies. Further, it wants to have the freedom to review the changes from a central location and receive an alert when a new change has been posted to the change log.
The HR department’s requirements are easy to achieve if you consider that once you’ve gathered the changes and stored them in a list that HR staff members have access to, they can manage the information and set alerts using the list’s functionality. The only customizations you need to write are:
  • A SharePoint timer job that queries the log on a regular basis and adds the query results to the list
  • An administrative UI to manage the timer job
In this example, the list resides at the root of the My Site host, but the list could reside anywhere in a real implementation.

Creating the Timer Job

Let’s walk through the code that creates the SharePoint timer job to see how it works. This example is based on the Microsoft article “Creating Custom Timer Jobs in Windows SharePoint Services 3.0”.
The timer job begins by creating an instance of the UserProfileWatcherTimerJob class, which inherits from the SPJobDefinition class.
The SPJobDefinition class has a property bag that lets you provide properties to the Execute method for processing. In this case, the SubmitJob method is used to pass the userProfileFields and mySiteHost properties to the timer job instance and store them in the property bag, as you can see in the code that Listing 2 at the end of this article shows.
The Execute method is called when the timer job runs. As seen in Listing 3 at the end of this article, the Execute method begins by reading the values of the timer job’s properties. Next, it creates an instance of the worker class, UserProfileWatcherWorker, passing in those values.
UserProfileWatcherWorker then provides two methods, which the Execute method uses to query the user profile change log and update the target list when changes matching the query are found.
UserProfileWatcherWorker is the workhorse of the timer job, so let’s take a close look it. This worker class first declares several private fields to keep track of the user profile fields and the age of the changes. It also declares a list to store UserProfilePropertyValueChange objects:
public class UserProfileWatcherWorker

{

  private string _mySitesHost;

  private int _changeAge = 30;

  private string _profileFields;

  private List<UserProfilePropertyValueChange> _changes =

    new List<UserProfilePropertyValueChange>(); }
Next, it initializes the values that will be used to get the UserProfileManager object and construct the change query:
public UserProfileWatcherWorker(string profileFields, int queryInterval, string mySitesHost)

{

  _mySitesHost = mySitesHost;

  _changeAge = queryInterval;

  _profileFields = profileFields;

}
Finally, the UserProfileWatcherWorker worker class provides two methods:
  • RetrieveUserProfileChanges. When called by the Execute method, RetrieveUserProfileChanges queries the user profile change log. As shown in Listing 4 at the end of this article, the RetrieveUserProfileChanges method begins by getting a reference to the My Site host and SPServiceContext object, after which it constructs a change token and change query. Like the PowerShell code in Figure 3, it uses the change token and change query to call the GetChanges(ProfileBaseChangeQuery) overload, which performs the actual query. Finally, RetrieveUserProfileChanges evaluates the changes collection for the field stored in the _profileFields variable. If the field name is found, the UserProfilePropertyValueChange object (propertyChange) is stored in the list of changes.
  • LogProfileChange. When called by the Execute method, LogProfileChange writes the list of changes to the list configured in the timer job properties. As shown in Listing 5 at the end of this article, the LogProfileChange method begins by getting a reference to the target list through a utility function that ensures that the list exists. For each item in the list, the user profile is evaluated. If it’s not null, the method writes a list item for each change in the list of changes. Finally, the list web and site references are disposed.

 

Creating the Administrative UI

Administration of the timer job is achieved through the use of a custom administration page that Figure 5 shows. The administration page, which inherits from the OperationsPage class, is added to the solution in an ADMIN mapped folder.

Figure 5: Administration page
Figure 5: Administration page
Navigation to the new administration page is achieved by adding an elements.xml file that contains the CustomAction element code in Listing 6 at the end of this article. The CustomAction element adds a new menu item—Manage Aptillon SharePoint User Profile Watcher—to the Timer Jobs section of the Monitoring page, as seen in Figure 6.

Figure 6: New link to the administration page
Figure 6: New link to the administration page
When the new menu item is clicked, the administration page loads. During the loading process, the code shown in Listing 7 at the end of this article looks for a previous instance of the timer job and initializes the values of the page controls if a timer job is found.
In the administration page, the privileged user or administrator can choose to disable or enable the timer job. When a person selects Disabled and clicks OK, the OnClick method gets a reference to the SharePoint Timer Service and deletes all previous versions of the timer job. This prevents multiple instances of the timer job.
When the privileged user or administrator selects Enabled, enters the necessary information, and clicks OK, the administration page runs code that tests for the existence of the specified site and creates a schedule object based on the specified settings.
A new instance of the UserProfileWatcherTimerJob is created and the SubmitJob method is called to update the properties, which the code in Listing 8 at the end of this article shows. The privileged user or administrator is then redirected to the Monitoring page in Central Administration.

Testing the Sample

Testing the sample code requires you to have administrative access to your SharePoint farm.
After deploying the code, select the new Manage Aptillon SharePoint User Profile Watcher menu item in the Timer Jobs section of the Monitoring page in Central Administration.
On the administration page, enable the timer job, make sure the Profile Fields value is AboutMe, and set the time value to 1 minute for testing purposes. Supply the address of your farm’s My Site host and click OK. You’ll be returned to the Monitoring page in Central Administration.

Figure 7: Edit the user profile’s About me field
Figure 7: Edit the user profile’s About me field
Open your profile page and choose Edit My Profile. Edit the About me field, which Figure 7 shows, choose Save, then click Close.
After the time set on the administration page has passed, navigate to the My Site host and click View All Site Content. There will be a new list named User Profile Changes. When you view that list, you’ll see a copy of your change, as Figure 8 shows.

Figure 8: Review the change made to the About me field
Figure 8: Review the change made to the About me field

A Powerful Tool

The user profile change log is a powerful tool for monitoring change in your environment and can be used to help enforce governance policies for your My Site deployment.
Although SharePoint doesn’t provide a UI for the user profile change log, the SharePoint API provides great functions for accessing and using it to monitor user activity. You can also use PowerShell to access and monitor the change log.

Listing 1: Code to retrieve the SPServiceContext object
$app = Get-SPServiceApplication | ? {
$_.Name -eq "My User Profile Service App"
}
$siteSub = [Microsoft.SharePoint. ?
   SPSiteSubscriptionIdentifier]::Default
$context = [Microsoft.SharePoint. ?
  SPServiceContext]::GetContext( ?
    $app.ServiceApplicationProxyGroup, $siteSub)
Listing 2: SPJobDefinition code with properties added
public class UserProfileWatcherTimerJob : SPJobDefinition{
  public UserProfileWatcherTimerJob() {}
  /// <summary>
  /// Initializes a new instance of the <see
    cref="UserProfileWatcherTimerJob"/> class.
  /// </summary>
  public UserProfileWatcherTimerJob(SPService service)
: base(Constants.UserProfileWatcherJobName, service, null,
SPJobLockType.Job)
  {
    Title = Constants.UserProfileWatcherJobName;
  }

  /// <summary>
  /// Submits the job.
  /// </summary>
  public void SubmitJob(string userProfileFields, string mySitesHost,
SPSchedule schedule)
  {
    Properties[Constants.PropertyKeyProfileFields] =
userProfileFields;
    Properties[Constants.PropertyKeyMySitesHost] = mySitesHost;
    Schedule = schedule;
    Update();
  }
Listing 3: Execute method
public override void Execute(Guid targetInstanceId){
    string profileFields = Constants.ProfileFields;
    int queryInterval = 30;
    string mySitesHost = String.Empty;

    Debug.WriteLine("[Aptillon] User Profile Watcher Job: Begin
Execute.");

    try
    {
      //Get the properties from the Timer Job
      profileFields =
this.Properties[Constants.PropertyKeyProfileFields]
.ToString();
      queryInterval = (this.Schedule as SPMinuteSchedule).Interval;
      mySitesHost =
this.Properties[Constants.PropertyKeyMySitesHost]
.ToString();
      Debug.WriteLine(String.Format("[Aptillon] User Profile Watcher
Job: Fields={0}, Interval={1}, MySites Host={2}",
profileFields, queryInterval, mySitesHost));

    }
    catch (Exception ex)
    {
      Debug.WriteLine("[Aptillon] User Profile Watcher Job:
Error gettting Job Properties");
      Debug.WriteLine("[Aptillon] User Profile Watcher Job: " +
 ex.Message);
    }

    //Create an instance of the watcher class
    UserProfileWatcherWorker changes =
new UserProfileWatcherWorker(profileFields,
queryInterval, mySitesHost);

    //Get the changes from the log
    changes.RetrieveUserProfileChanges();
    //Process the changes and add them to the list
    changes.LogProfileChange();
  }
}

 Listing 4: RetrieveUserProfileChanges method
internal void RetrieveUserProfileChanges(){
  Debug.WriteLine("[Aptillon] User Profile Watcher Job: Starting Retrieve");
           
  using (SPSite site = new SPSite(_mySitesHost))
  {
    SPServiceContext context = SPServiceContext.GetContext(site);
    UserProfileManager profileManager = new UserProfileManager(context);

    DateTime tokenStart = DateTime.UtcNow.Subtract(TimeSpan.FromMinutes(_changeAge));
    UserProfileChangeToken changeToken = new UserProfileChangeToken(tokenStart);

    UserProfileChangeQuery changeQuery = new UserProfileChangeQuery(false, true);
    changeQuery.ChangeTokenStart = changeToken;
    changeQuery.UserProfile = true;
    changeQuery.SingleValueProperty = true;
    changeQuery.MultiValueProperty = true;
               
    UserProfileChangeCollection changes = profileManager.GetChanges(changeQuery);

    Debug.WriteLine(String.Format("[Aptillon] User Profile Watcher Job: found {0}
changes.", changes.Count));


    foreach (UserProfileChange change in changes)
    {
      if (change is UserProfilePropertyValueChange)
      {
        UserProfilePropertyValueChange propertyChange =
(UserProfilePropertyValueChange)change;
        if (_profileFields.Split(',').Contains(propertyChange.ProfileProperty.Name))
        {
          _changes.Add(propertyChange);
        }
      }
    }
    Debug.WriteLine("[Aptillon] User Profile Watcher Job: Done with Retrieve");
  }
}
Listing 5: LogProfileChange method
internal void LogProfileChange(){
  if (_changes.Count == 0) return;

  SPList list = Utilities.FetchOrCreateList(_mySitesHost);
  if (list == null)
    return;
  try
  {
    foreach (UserProfilePropertyValueChange change in _changes)
    {
      UserProfile profile = change.ChangedProfile as UserProfile;
      if (profile == null) continue;
     
      try
      {
        Debug.WriteLine(string.Format("[Aptillon] User Profile
Watcher Job: Adding change details - Account={0},
Property={1}", change.AccountName,
change.ProfileProperty.Name));

        SPListItem item = list.AddItem();

        item["Title"] = String.Format("\"{0}\" changed \"{1}\"",
profile[PropertyConstants.PreferredName].Value,
change.ProfileProperty.Name);
        item["PropertyName"] = change.ProfileProperty.Name;
        item["PropertyValue"] =
           profile[change.ProfileProperty.Name].Value;

        //Log the user too
        SPUser user = list.ParentWeb.EnsureUser(change.AccountName);
        item["User"] = user;

        item.Update();
        Debug.WriteLine("[Aptillon] User Profile Watcher Job:
Add Complete");
      }
      catch (Exception ex)
      {
        Debug.WriteLine("[Aptillon] User Profile Watcher Job:
Error gettting Job Properties");
        Debug.WriteLine("[Aptillon] User Profile Watcher Job: " +
 ex.Message);
      }
    }
  }
  finally
  {
    list.ParentWeb.Dispose();
    list.ParentWeb.Site.Dispose();
  }
}

Listing 6: CustomAction element
<?xml version="1.0" encoding="utf-8"?>
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
  <CustomAction Id="Aptillon.SharePoint.UserProfileWatcher"
  GroupId="TimerJobs"
  Location="Microsoft.SharePoint.Administration.Monitoring"
  Sequence="100"
  Title="Manage Aptillon SharePoint User Profile Watcher"
  Description="Manage the Aptillon SharePoint User Profile Watcher Timer Job.">
    <UrlAction Url="_admin/Aptillon/UserProfileWatchSettings.aspx" />
  </CustomAction>
</Elements>
Listing 7: Code to look for previous timer job instances
public partial class UserProfileWatchSettings : OperationsPage{
  protected void Page_Load(object sender, EventArgs e)
  {
  if (!IsPostBack)
  {
    jobStatusList.SelectedValue = "False";
    userProfileFieldsTextBox.Text = Constants.ProfileFields;
    intervalMinutesDropDownList.SelectedValue = "30";
    mySitesHostTextBox.Text = String.Empty;

    SPTimerService timerService = SPFarm.Local.TimerService;
    if (null == timerService)
    {
      throw new SPException("The Farm's timer service cannot
be found.");
    }
    foreach (SPJobDefinition oldJob in timerService.JobDefinitions)
    {
      if (oldJob.Title == Constants.UserProfileWatcherJobName)
      {
        jobStatusList.SelectedValue = "True";
        userProfileFieldsTextBox.Text =
oldJob.Properties[Constants.PropertyKeyProfileFields]
.ToString();
        intervalMinutesDropDownList.SelectedValue =
(oldJob.Schedule as SPMinuteSchedule).Interval.ToString();
        mySitesHostTextBox.Text =
oldJob.Properties[Constants.PropertyKeyMySitesHost]
.ToString();
        break;
      }
    }
  }
}
Listing 8: Code to update properties
protected void SetTimerJobsButton_OnClick(object sender, EventArgs e){
  SPTimerService timerService = SPFarm.Local.TimerService;
  if (null == timerService)
  {
    throw new SPException("The Farm's timer service cannot
be found.");
  }

  // delete the job for the current web application
  foreach (SPJobDefinition oldJob in timerService.JobDefinitions)
  {
    if (oldJob.Title == Constants.UserProfileWatcherJobName)
    oldJob.Delete();
  }

  // Enable the Timer Job if the enabled button is chosen
  if (jobStatusList.SelectedValue == "True")
  {
    string mySitesHost = mySitesHostTextBox.Text;

    if (!SPSite.Exists(new Uri(mySitesHost)))
    {
      ErrorMessageLiteral.Text = "The specified my site
host does not exist.";
      return;
    }

    // create a new instance of the job and schedule it
    SPMinuteSchedule schedule = new SPMinuteSchedule();
    schedule.BeginSecond = 0;
    schedule.EndSecond = 59;
    schedule.Interval =
    Convert.ToInt32(intervalMinutesDropDownList.SelectedValue);

    UserProfileWatcherTimerJob job =
new UserProfileWatcherTimerJob(timerService);
    job.SubmitJob(userProfileFieldsTextBox.Text,
mySitesHost, schedule);

  }
  this.RedirectToOperationsPage();
}
 


Reference

http://sharepointpromag.com/sharepoint-2010/monitor-sharepoint-user-profile-changes


Reading Change Log for a User Profile in Sharepoint


Nice Article by Sandeep

http://snahta.blogspot.in/2008/09/reading-change-log-for-user-profile.html


using System;
using System.Collections.Generic;
using Microsoft.SharePoint;
using Microsoft.Office.Server;
using Microsoft.Office.Server.UserProfiles;

namespace ChangeLog
{
    class Program
    {
        static void Main(string[] args)
        {
            try
            {
                using (SPSite spSite = new SPSite(@"http://localhost"))
                {
                    ServerContext siteContext = ServerContext.GetContext(spSite);
                    UserProfileManager pmManager = new UserProfileManager(siteContext);

                    // This gets some subset of changes to a user profile

                    // Display the changes that have occurred in the last month
                    DateTime dtNumberDays =
                             DateTime.UtcNow.Subtract(TimeSpan.FromDays(30));
                    // Create a change token to compare the number of days
                    UserProfileChangeToken upChangeToken = 
                                new UserProfileChangeToken(dtNumberDays);

                    // Create a query object to determine which changes are displayed
                     UserProfileChangeQuery QueryAnniversayAndColleagues = 
                               new UserProfileChangeQuery(false, true);
                    QueryAnniversayAndColleagues.ChangeTokenStart = upChangeToken;
                    QueryAnniversayAndColleagues.Anniversary = true;
                    QueryAnniversayAndColleagues.Colleague = true;

                    string strUserName = "domain\\sandeep";

                    if (pmManager.UserExists(strUserName))
                    {
                        UserProfile spMyUser = pmManager.GetUserProfile(strUserName);

                        UserProfileChangeCollection MyUserProfileChanges =                                     spMyUser.GetChanges(QueryAnniversayAndColleagues);

                        foreach (UserProfileChange MyUserChange in MyUserProfileChanges)
                        {
                            Console.WriteLine(MyUserChange.EventTime.ToString());
                            if (MyUserChange is UserProfileAnniversaryChange)
                            {
                                UserProfileAnniversaryChange AnniversryEvent =
                                      (UserProfileAnniversaryChange)MyUserChange;
                                Console.WriteLine(AnniversryEvent.Anniversary);
                                Console.WriteLine(AnniversryEvent.ProfileProperty);
                            }
                            else if (MyUserChange is UserProfileColleagueChange)
                            {
                                UserProfileColleagueChange ColleagueEvent = (UserProfileColleagueChange)MyUserChange;
                            }
                        }
                    }
                }
            }
            catch (Exception exp)
            {
                Console.WriteLine(exp.Message);
            }
        }
    }
}


Reference

http://snahta.blogspot.in/2008/09/reading-change-log-for-user-profile.html

Scheduling a Job in SQL Server

Explained step by step in this blog
 
 
 
Scheduling Data Imports in SQL Server
Part three of a three-part series of blogs
If you frequently import data into a SQL Server database from the same source you'll probably be sick of going through the import wizard again and again. So why not learn how to schedule an automatic import of your data using SSIS packages and the SQL Server Agent? This blog explains how to do exactly that!
  1. Scheduling Data Imports in SQL Server
  2. Using the Import Wizard in SQL Server
  3. Scheduling a Job in SQL Server (this blog)

Scheduling a Job in SQL Server

The final stage of this blog series is to create a scheduled job to execute the SSIS package on a regular basis.

The SQL Server Agent

You can schedule jobs using the SQL Server Agent.  You should find this at the bottom of the list of objects in any database server that you've connected to in SQL Server Management Studio:
SQL Server AgentThe SQL Server Agent appears at the bottom of the list of objects in a database server.
 

Creating a Job

To create a new job using SQL Server Agent:
Creating a new jobRight-click the Jobs folder and choose New Job...
 
You can then use the dialog box to set up the job you want to create.  The steps we need to follow in order to schedule our SSIS package execution are described below.

Step 1 - Enter a Name for the Job

The first step is to give the new job a sensible name, as shown below:
Naming a jobIn the General category, enter a descriptive name for the job.

Step 2 - Create the Job Steps

Next, you can create the steps that will make up the job.  Our job should have only one step and here's how to create it:
  1. Select the Steps page of the dialog box.
Create job stepsBuild a list of steps for the job using this page of the dialog box.
  1. Click the New... button to add a new step to the job.
Specify the job stepUse this dialog box to specify the settings for this job step.
  1. Enter a sensible name for this step of the job.
  2. Choose the type of action to perform.  Here we want to execute an SSIS package.
  3. Choose where the SSIS package is stored.  Here we've selected the package that we saved earlier on our SQL Server.
  4. Click the ellipsis (...) to choose the package you want to execute.
  5. Click OK to return to the New Job dialog box.
The job should now consist of a single step:
Step in jobOur entire job consists of a single step, but we could always add more to this by clicking the New... button at the bottom of the dialog box.

Step 3 - Creating the Job Schedule

To ensure that the job runs at a specific time you need to specify the schedule for the job.  To do this:
  1. Select the Schedules page of the dialog box.
Scheduling a jobUse this page to set up the job schedule.
  1. Click New... to create a new schedule.
  2. Complete the dialog box as shown below:
Schedule setupThe options in this page of the dialog box are self-explanatory. The options we have selected here ensures the job will be carried out each week at 9am on a Monday morning.
  1. Click OK to return to the New Job dialog box.

Step 5 - Creating the Job

When you have finished applying all of the settings listed above, you can create the job by simply clicking OK on the New Job dialog box.
Job createdYour new job will appear in the Jobs folder within SQL Server Agent.
 
And that's it!  As long as your database server is running and SQL Server Agent has been started your data import will occur on a scheduled basis from now on.


Reference

http://www.wiseowl.co.uk/blog/s231/schedule_data_import_in_sql_server_pt3.htm


Import CSV File Into SQL Server Using Bulk Insert – Load Comma Delimited File Into SQL Server

This is a very common request recently – How to import CSV file into SQL Server? How to load CSV file into SQL Server Database Table? How to load comma delimited file into SQL Server? Let us see the solution in quick steps.
CSV stands for Comma Separated Values, sometimes also called Comma Delimited Values.
Create TestTable
USE TestData
GO
CREATE TABLE CSVTest
(ID INT,
FirstName VARCHAR(40),
LastName VARCHAR(40),
BirthDate SMALLDATETIME)
GO

Create CSV file in drive C: with name sweetest. text with the following content. The location of the file is C:\csvtest.txt
1,James,Smith,19750101
2,Meggie,Smith,19790122
3,Robert,Smith,20071101
4,Alex,Smith,20040202

Now run following script to load all the data from CSV to database table. If there is any error in any row it will be not inserted but other rows will be inserted.
BULK
INSERT
CSVTest
FROM 'c:\csvtest.txt'
WITH
(
FIELDTERMINATOR = ',',
ROWTERMINATOR = '\n'
)
GO
--Check the content of the table.
SELECT *
FROM CSVTest
GO
--Drop the table to clean up database.
DROP TABLE CSVTest
GO




Reference : Pinal Dave (http://blog.SQLAuthority.com)
 


Import User Pictures from Active Directory to SharePoint 2010 My Site

My Organization decided to use Active Directory as a central repository for user profile photos to share with Lync 2010, Outlook and of course SharePoint!

Lets keep other products aside and talk about How to Import User Pictures from Active Directory to SharePoint 2010 My Site. Here is the default My site Profile page without Profile photo imported from AD:

import user pictures from active directory to sharepoint 2010

Well, this article addresses import user pictures from active directory to SharePoint 2010 step by step:
  1. Import user photo into Active Directory user profile's "thumbnailPhoto" attribute.
  2. Configure Property mapping between SharePoint and Active Directory and Run FULL Profile Import.
  3. Run Update-SPProfilePhotoStore cmdlet to generate thumbnails for SharePoint user profile picture.
Assuming UPS is in place, My Site is up and running, SharePoint 2010 SP1 is installed (or October 2010 Cumulative Update), Lets get into details.

Step 1: Import user photo into Active Directory user profile's "thumbnailPhoto" attribute.
If profile pictures are not already in Active Directory user profile's "thumbnailPhoto" attribute, We can import pictures into it. For SharePoint 2010 to import user photo from ad, it must have this attribute populated.
import photo from ad sharepoint 2010

Yes, there are 3rd party tools like AD Photo Edit to import user profile thumbnail photos in bulk,  PowerShell can do it well with just three lines!
?
1
2
3
4
5
Import-Module ActiveDirectory
 
$photo=[byte[]](Get-Content .\salaudeen_photo.jpg -Encoding byte)
 
Set-ADUser "Salaudeen" -Replace @{thumbnailPhoto=$photo}

PowerShell Script to Bulk Import User Profile Photos into AD:
Lets say, we've lot of users in AD and their user name, Profile Photo file names are stored in a CSV file with columns "UserName", "PhotoFileName". We can utilize PowerShell to import photo to AD in bulk.

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#Read the CSV file - Map the Columns to Named Header (CSV File doesn't has Column Header)
$CSVData = Import-CSV -path "C:\Scripts\UpdateProfilePhoto\UserPhotos.csv" -Header("UserName", "PhotoFileName")
 
 #Iterate through each Row in the CSV
 foreach ($row in $CSVData)
   {
        #Get the User Name & Photos from CSV file
        $userName= $row.UserName
        $PhotoFile = Join-path "C:\Scripts\UpdateProfilePhoto" $row.PhotoFileName
         
        #Get the User from AD
        $domain = [System.DirectoryServices.ActiveDirectory.Domain]::GetCurrentDomain()
        $root = $domain.GetDirectoryEntry()
        $search = [System.DirectoryServices.DirectorySearcher]$root
        $search.Filter = "(&(objectCategory=User)(samAccountName=$userName))"
        $result = $search.FindOne()
          
        if ($result -ne $null)
        {
            #Get the User Object
            $user = $result.GetDirectoryEntry()
             
            #Get the Photo from Disk
            $photo=[byte[]](Get-Content $PhotoFile -Encoding byte)
            
            #Update User Profile Photo
            $user.put("thumbnailPhoto"$photo )
            $user.setinfo()
             
            Write-Host $user.displayname " Photo has been updated."
        }
         
    }
Once imported, You can find the "thumbnailPhoto" property updated in AD User's properties.
import pictures from active directory to sharepoint 2010
BTW, User profile picture can be from any where! Not just AD, but any File Server, SharePoint Library, etc. So you can proceed by setting up a ProfileURL mapping and execute below steps.

Step 2: Configure Property mapping between SharePoint and Active Directory and Run FULL Profile Import.
Once user profile pictures are imported to Active directory, the next step is to make SharePoint aware of the Property by creating a Property Mapping. Go to:
  • Central Administration >> Manager Service Application
  • Click on "Manage" on User Profile Service Application
  • Click on "Manage User Properties"
  • Edit the "Picture" property
    import user profile photos from active directory into sharepoint 2010
  • We don't want users to override the photo from AD. So select "Do not allow users to edit value for this property" option
    import ad photos into sharepoint 2010
  • Specify the User Profile Connection, Attribute as "thumbnailPhoto" and direction as "Import"
    sharepoint 2010 import picture from active directory
  • click "Add" button and then "OK".
So, we've done mapping the AD property thumbnailPhoto with SharePoint via “PictureURL” User Profile property.

Trigger FULL User Profile Synchronization 
Since UPS didn’t know about this field previously, We've to Run FULL user profile sync. From User Profile Service Application, click on "Start Profile Synchronization" >> Select "Start Full" >> Click "OK" button.
 import pictures from active directory to sharepoint
wait for the user profile Synchronization to complete, and then proceed to next step. So now, we've import user profile photos from active directory into SharePoint 2010.

Step 3: Run Update-SPProfilePhotoStore cmdlet to generate thumbnails for SharePoint user profile picture.
SharePoint 2010 requires the thumbnails to be within 10kb size of 32x32, 96x96, 144x144 px resolutions. So, We've to instruct SharePoint to generate the image thumbnails and re-configure user profiles to reference the thumbnail.

PowerShell Script to create thumbnails in the right sizes and maps the images to the user profiles:
?
1
2
3
Add-PSSnapin Microsoft.SharePoint.PowerShell -ErrorAction SilentlyContinue
 
Update-SPProfilePhotoStore -CreateThumbnailsForImportedPhotos 1 -MySiteHostLocation  http://<My Site Host Web App URL>
Make sure You have Administrator access and "FULL" control Permissions on User Profile Service Application.  Otherwise, You will get "Update-SPProfilePhotoStore: Object reference not set to an instance of an object." Error!
sharepoint 2010 import photo from active directory
In some cases, It’s also important to note that you must be a site collection administrator of the ‘My Site Host’, and also have administrative access to the SQL Databases. On successful execution, SharePoint 2010 Stores user profile pictures under My site Host's, "User Photos" library. E.g. http://mysite.crescent.com/User%20Photos

Verify the Result: Navigate to My site Personal profile (person.aspx) page and verify the new photo. Same Procedure applies to SharePoint 2013 also.
sharepoint 2010 import user photo from ad
Remember, SharePoint search will still show you the old photo until the next incremental search crawl takes place on the content source with your sps3:// provider mapped!

On Going Maintenance: Once AD Profile photo is updated down the line, SharePoint 2010 user profile synchronization will pick the photo. But still we've to make the photo ready for SharePoint by executing Update-SPProfilePhotoStore cmdlet on schedule basis.

So, Its a good idea to schedule a script in Windows Task scheduler to run Update-spprofilephotostore cmdlet after completing FULL profile import. Say, You have the script in a file "SPProfilePhotoStore.ps1" under "D:\Scripts".  Schedule a PowerShell script in Windows task Scheduler and enter "c:\windows\system32\WindowsPowerShell\v1.0\powershell.exe "& 'D:\Scripts\Update-SPProfilePhotoStore.ps1'" in Program to execute.

 or in arguments box, you can directly enter: -NonInteractive -NoProfile -Command "& {Add-PSSnapin Microsoft.SharePoint.PowerShell;Update-SPProfilePhotoStore -MySiteHostLocation https://<My site Host URL> -CreateThumbnailsForImportedPhotos 1}"



Reference:


Synchronizing user image between Active Directory and SharePoint profile

As you may know Exchange 2010 and Outlook 2010 use the Picture attribute (better known as thumbnailPhoto based on its LDAP name) to store user and contact photos in Active Directory. You can learn more about that from this post in the Microsoft Exchange Team Blog.
Since I found no way in Outlook 2010 to set the photo, and found only (for an end user) cumbersome admin tools, like PowerShell and VBScript to upload the image. On the other side, SharePoint makes it possible for a user to upload her / his photo to the profile from the web UI easily.
Before trying to reinvent the wheel, I looked around on the web for similar solutions, but found only implementations (like this one) where an extension attribute of AD (like extensionAttribute3) was mapped to the ProfileURL SharePoint profile property.
My goal was a bit more: to synchronize the image binary as well, not only URLs. As I’ve already created tools to upload user photos from file system to SharePoint profile programmatically I thought it would be nice to reuse that knowledge on this task.
Although an ideal solution might be some kind of server process (for example a timer job), for the sake of simplicity and visibility I chose a Visual Web Part-based “self-service” implementation.
Let’s see the results first. You can find the code and the binaries as a single file download here.
When deploy the solution, you have to add the Profile Photo Sync WebPart to a page…
image
…and set its Root application partition property to the root of your AD.
image
Assuming there is no user photo in the profile nor in the AD, you should see something similar first:
image
Let’s upload our photo quickly to our SharePoint profile. It is done, the image is shown on the profile page. Let’s back to the web part. But wait a minute! The photo is still not visible there! What happened? I told you: wait a minute. SharePoint requires about one minute to push the profile property changes to the site. After it is done, the image is visible in the web part as expected:
image
If you press the >> button, the image is transferred to AD.
image
Now delete the image from the profile and refresh the page. The image can be found in the AD, but not in the SharePoint profile.
image
Try to load it back to SharePoint by pressing the << button. It seems to have no effect, but again you should wait a minute to see the result:
image
If you delete the image from the SharePoint profile again, refresh the page and now click on the >> button, you find that the photo is deleted from the AD as well and we are back to our starting point. Synchronizing an empty thumbnailPhoto property from AD to SharePoint profile deletes the image from the profile as well.
After this short demo let’s see some code blocks.
Since our control has to know where to look for AD properties we have to provide this iannformation for it. The web part has a property called DefaultPartition. The value of this property is forwarded to the user control in the CreateChildControls method.
  1. [Personalizable(),
  2. WebBrowsable(),
  3. WebDisplayName("Root application partition")]
  4. public string DefaultPartition
  5. {
  6.     get;
  7.     set;
  8. }
  9. #endregion
  10.  
  11. protected override void CreateChildControls()
  12. {
  13.     ProfilePhotoSyncWebPartUserControl control = (ProfilePhotoSyncWebPartUserControl)Page.LoadControl(_ascxPath);
  14.     control.DefaultPartition = DefaultPartition;
  15.     Controls.Add(control);
  16. }
The RefreshControls method is responsible for rendering the content of the UI. Since there is no built-in way to refer the thumbnailPhoto property in the AD via a URL, I made a quick and dirty hack there. If the request URL contains the UserName query string parameter, we clears the response, get the binary content from the thumbnailPhoto property and push that content to the response.
If the UserName query string parameter is not found in the request URL and the thumbnailPhoto property is not empty, I set the image URL of the AD image to the URL of the current page appending the current user name in the UserName query string parameter.
Similarly, if the PictureUrl user profile property is not empty in SharePoint I set the image URL for the SharePoint image to the value stored in the PictureUrl property.
If one or both of the properties would be empty then the corresponding image is hidden and a No photo label is shown as you can see on the images above.
  1. private void RefreshControls()
  2.         {
  3.             String userName = Request.QueryString["UserName"];
  4.  
  5.             // hack: render response as image for AD "thumbnailPhoto" image
  6.             if (!String.IsNullOrEmpty(userName))
  7.             {
  8.                 Response.Clear();
  9.                 ADUtils adUtils = new ADUtils(DefaultPartition);
  10.                 using (DirectoryEntry root = adUtils.GetDefaultPartition())
  11.                 using (DirectoryEntry user = adUtils.FindUserByAccountName(userName))
  12.                 {
  13.                     byte[] thumbnailPhotoBytes = (byte[])user.Properties["thumbnailPhoto"].Value;
  14.                     if (thumbnailPhotoBytes != null)
  15.                     {
  16.                         Response.BinaryWrite(thumbnailPhotoBytes);
  17.                     }
  18.  
  19.                 }
  20.                 Response.End();
  21.             }
  22.             else
  23.             {
  24.                 try
  25.                 {
  26.                     ADUtils adUtils = new ADUtils(DefaultPartition);
  27.                     using (DirectoryEntry root = adUtils.GetDefaultPartition())
  28.                     using (DirectoryEntry user = adUtils.FindUserByAccountName(_shortName))
  29.                     {
  30.                         byte[] thumbnailPhotoBytes = (byte[])user.Properties["thumbnailPhoto"].Value;
  31.                         bool hasThumbnailPhoto = (thumbnailPhotoBytes != null);
  32.                         ADImage.Visible = hasThumbnailPhoto;
  33.                         ADImageLabel.Visible = !hasThumbnailPhoto;
  34.  
  35.                         if (hasThumbnailPhoto)
  36.                         {
  37.                             ADImage.ImageUrl = String.Format("{0}?UserName={1}", Request.Url.GetLeftPart(UriPartial.Path), _shortName);
  38.                         }
  39.  
  40.                     }
  41.                 }
  42.                 catch (Exception ex)
  43.                 {
  44.                     Warning.Visible = true;
  45.                 }
  46.  
  47.                 UserProfileManager userProfileManager = new UserProfileManager(SPServiceContext.Current);
  48.                 UserProfile userProfile = userProfileManager.GetUserProfile(_accountName);
  49.  
  50.                 String pictureUrl = (String)userProfile["PictureUrl"].Value;
  51.  
  52.                 bool hasProfilelPhoto = (!String.IsNullOrEmpty(pictureUrl));
  53.  
  54.                 // double check to be sure the file is there to avoid "missing" images on the page
  55.                 // when removing the profile image on the UI it takes some time the change get reflected
  56.                 // in the profile property, but image is deleted immediately
  57.                 if (hasProfilelPhoto)
  58.                 {
  59.                     using (SPSite site = new SPSite(pictureUrl))
  60.                     {
  61.                         using (SPWeb web = site.OpenWeb())
  62.                         {
  63.                             SPFile file = web.GetFile(pictureUrl);
  64.                             hasProfilelPhoto = file.Exists;
  65.                         }
  66.                     }
  67.                 }
  68.  
  69.                 SPImage.Visible = hasProfilelPhoto;
  70.                 SPImageLabel.Visible = !hasProfilelPhoto;
  71.  
  72.                 if (hasProfilelPhoto != null)
  73.                 {
  74.                     SPImage.ImageUrl = pictureUrl;
  75.                 }
  76.  
  77.             }
  78.         }
When you click on the >> button to copy SharePoint profile image to AD the following code is called:
  1. protected void SP2AD_Click(object sender, EventArgs e)
  2.         {
  3.  
  4.             UserProfileManager userProfileManager = new UserProfileManager(SPServiceContext.Current);
  5.             UserProfile userProfile = userProfileManager.GetUserProfile(_accountName);
  6.  
  7.             String pictureUrl = (String)userProfile["PictureUrl"].Value;
  8.  
  9.             bool hasProfilelPhoto = (!String.IsNullOrEmpty(pictureUrl));
  10.  
  11.             byte[] imageContent = null;
  12.  
  13.             // double check to be sure the file is there to avoid "missing" images on the page
  14.             // when removing the profile image on the UI it takes some time the change get reflected
  15.             // in the profile property, but image is deleted immediately
  16.             if (hasProfilelPhoto)
  17.             {
  18.                 using (SPSite site = new SPSite(pictureUrl))
  19.                 {
  20.                     using (SPWeb web = site.OpenWeb())
  21.                     {
  22.                         SPFile file = web.GetFile(pictureUrl);
  23.                         if (file.Exists)
  24.                         {
  25.                             imageContent = file.OpenBinary();
  26.                         }
  27.                     }
  28.                 }
  29.             }
  30.  
  31.             ADUtils adUtils = new ADUtils(DefaultPartition);
  32.             using (DirectoryEntry root = adUtils.GetDefaultPartition())
  33.             using (DirectoryEntry user = adUtils.FindUserByAccountName(_shortName))
  34.             {
  35.                 user.Properties["thumbnailPhoto"].Clear();
  36.                 if (imageContent != null)
  37.                 {
  38.                     user.Properties["thumbnailPhoto"].Add(imageContent);
  39.                 }
  40.                 user.CommitChanges();
  41.  
  42.             }
  43.  
  44.             RefreshControls();
  45.  
  46.         }
Similarly, when you click << to copy image from AD to the SharePoint profile, the following code gets executed:
  1. protected void AD2SP_Click(object sender, EventArgs e)
  2.       {
  3.           try
  4.           {
  5.               ADUtils adUtils = new ADUtils(DefaultPartition);
  6.               using (DirectoryEntry root = adUtils.GetDefaultPartition())
  7.               using (DirectoryEntry user = adUtils.FindUserByAccountName(_shortName))
  8.               {
  9.                   byte[] thumbnailPhotoBytes = (byte[])user.Properties["thumbnailPhoto"].Value;
  10.                   bool hasThumbnailPhoto = (thumbnailPhotoBytes != null);
  11.                   ADImage.Visible = hasThumbnailPhoto;
  12.                   ADImageLabel.Visible = !hasThumbnailPhoto;
  13.  
  14.                   if (hasThumbnailPhoto)
  15.                   {
  16.                       using (SPSite site = new SPSite(GetMySiteHostUrl(SPContext.Current.Site)))
  17.                       {
  18.                           site.AllowUnsafeUpdates = true;
  19.                           using (SPWeb web = site.OpenWeb())
  20.                           {
  21.                               web.AllowUnsafeUpdates = true;
  22.                               ProfileImagePicker profileImagePicker = new ProfileImagePicker();
  23.                               InitializeProfileImagePicker(profileImagePicker, web);
  24.                               SPFolder subfolderForPictures = GetSubfolderForPictures(profileImagePicker);
  25.  
  26.                               UploadPhoto(_accountName, thumbnailPhotoBytes, subfolderForPictures);
  27.                               SetPictureUrl(_accountName, subfolderForPictures);
  28.                           }
  29.                       }
  30.                   }
  31.               }
  32.           }
  33.           catch (Exception ex)
  34.           {
  35.               Warning.Visible = true;
  36.           }
  37.  
  38.           RefreshControls();
  39.  
  40.       }
Helper methods in the AD2SP_Click method (UploadPhoto, SetPictureUrl, GetMySiteHostUrl etc.) are similar to the ones used in my former solutions here and here.
Active Directory related code is included in the ADUtils class (see credits later):
  1. public class ADUtils
  2.     {
  3.  
  4.         public ADUtils(String defaultPartition)
  5.         {
  6.             DefaultPartition = defaultPartition;
  7.         }
  8.  
  9.         private String DefaultPartition
  10.         {
  11.             get;
  12.             set;
  13.         }
  14.  
  15.         /// <summary>
  16.         /// Retrieves a DirectoryEntry using configuration data
  17.         /// </summary>
  18.         /// <param name="path"></param>
  19.         /// <returns></returns>
  20.         public DirectoryEntry CreateDirectoryEntry(string path)
  21.         {
  22.             return new DirectoryEntry(String.Format("LDAP://{0}", path));
  23.         }
  24.  
  25.         /// <summary>
  26.         /// Creates a DirectoryEntry from the DefaultPartition defined in config
  27.         /// </summary>
  28.         /// <returns></returns>
  29.         public DirectoryEntry GetDefaultPartition()
  30.         {
  31.             return CreateDirectoryEntry(DefaultPartition);
  32.         }
  33.  
  34.         /// <summary>
  35.         /// Simple method to find and return a user using the CN name and searching the
  36.         /// defaultNamingContext defined in config.
  37.         /// </summary>
  38.         /// <param name="userRDN"></param>
  39.         /// <returns></returns>
  40.         public DirectoryEntry FindUserByCN(string userRDN)
  41.         {
  42.             using (DirectoryEntry searchRoot = GetDefaultPartition())
  43.             {
  44.                 DirectorySearcher ds = new DirectorySearcher(
  45.                     searchRoot,
  46.                     String.Format("(cn={0})", userRDN),
  47.                     new string[] { "cn" },
  48.                     SearchScope.Subtree
  49.                     );
  50.  
  51.                 SearchResult sr = ds.FindOne();
  52.  
  53.                 return (sr != null) ? sr.GetDirectoryEntry() : null;
  54.             }
  55.         }
  56.  
  57.         /// <summary>
  58.         /// Simple method to find and return a user using the sAMAccountName name and searching the
  59.         /// defaultNamingContext defined in config.
  60.         /// </summary>
  61.         /// <param name="userRDN"></param>
  62.         /// <returns></returns>
  63.         public  DirectoryEntry FindUserByAccountName(string accountName)
  64.         {
  65.             Trace.TraceInformation("FindUserByAccountName method called. Account name: '{0}'", accountName);
  66.             using (DirectoryEntry searchRoot = GetDefaultPartition())
  67.             {
  68.                 DirectorySearcher ds = new DirectorySearcher(
  69.                     searchRoot,
  70.                     String.Format("(sAMAccountName={0})", accountName),
  71.                     new string[] { "sAMAccountName" },
  72.                     SearchScope.Subtree
  73.                     );
  74.  
  75.                 SearchResult sr = ds.FindOne();
  76.                 Trace.TraceInformation("FindUserByAccountName user found. Path: '{0}'", sr.Path);
  77.                 return (sr != null) ? sr.GetDirectoryEntry() : null;
  78.             }
  79.         }
  80.  
  81.     }
Note: The sample web part provided “as is”, and is intended to be used only as a proof of concept.
Important point on security: The sample should work only when at least two of the followings are located on the same computer: browser, SharePoint 2010 front end, Active Directory domain controller. If all of these three are located on a different computer and there is no Kerberos implemented then you should be prepared for the so-called double hops issue.
My general recommendation for that problem is accessing the resource (in this case the AD) using a service user account that has access to all the requested information. One can store the service account credentials for example in SSO or in an encrypted configuration parameter.
Implementing this features require some modifications in the current code. For example, you have to use a DirectoryEntry constructor in the CreateDirectoryEntry method of ADUtils class that has user name and password parameters.
You will not have such issues if you alter the solution to a server process, like timer job that runs as a dedicated user account.
Credits: I would like to say thanks to Joe Kaplan and Ryan Dunn for their book The .NET Developer’s Guide to Directory Services Programming. The book and the code samples are definitely a must for every .NET programmer who wants (or has) to dive into the beauty of Active Directory programming. The ADUtils class in my sample is based on a solution found in the book.


Reference
http://pholpar.wordpress.com/2010/08/10/synchronizing-user-image-between-active-directory-and-sharepoint-profile/