Update User Profile photo using Workflow

Update: I’ve added a video walkthrough of this technique.

In my last post, I talked about using a Powershell script to import user profile photos from a SharePoint Picture Library in to the MySites users profile.

That works great to sync up the photos from the library as a batch.  But what happens when you add a new employee photo to the library?  We need something to automatically update the MySite user profile, and a custom workflow will do just that.

Here’s the general logic for our workflow:

When an item is added or updated,

  1. Check if a User Name has been set.  If so, 
  2. Retrieve the User’s Profile
  3. Set the ‘PictureUrl’ value to the Url of the item in the picture library.
  4. Save the Profile record.
  5. Regenerate the Thumbnail sizes used by MySites.

Unfortunately, out of the box, SharePoint Designer workflows will not allow you to manipulate the User Profile.  I made an attempt to use the Virto Software Workflow Activities add-on, but was not able to get it working as I expected.  (UPDATE: This may have been a permissions issue. YMMV)

So, we need to use a Visual Studio Sequential Workflow in order to get full access to the User Profile.  Here are the steps.

First, create a new Sequential Workflow project in Visual Studio and go through the wizard

01_NewProject

02_ProjectWiz-1

03_ProjectWiz-2

04_ProjectWiz-3

05_ProjectWiz-4

Next, with the Workflow Designer open, select a ‘Code’ element from the Toolbox and drag it on to the workflow after the onWorkflowActivated1 event.

06_WorkflowToolbox

View the Properties for the Code element, and set the ExecuteCode property to “UpdateUserProfilePhoto”.  This will stub out a new method for you in the code file.

07_SetExecuteCode

Now, add the following references to your project:

  • Microsoft.Office.Server (14.0.0.0)
  • Microsoft.Office.Server.UserProfiles (14.0.0.0)
  • System.Web (2.0.0.0)

08_AddReferences

In your workflow code file, add the following using statements

using Microsoft.Office.Server.UserProfiles;
using Microsoft.SharePoint.Administration;
using System.Web;

And then add this code to the UpdateUserProfilePhoto method to implement our workflow sequence.

private void UpdateUserProfilePhoto(object sender, EventArgs e)
{
  try
  {

    //get username
    Microsoft.SharePoint.SPFieldUser fieldUser =
     (Microsoft.SharePoint.SPFieldUser)workflowProperties.Item.Fields.GetField("User Name");

    Microsoft.SharePoint.SPFieldUserValue fieldUserValue =
      (Microsoft.SharePoint.SPFieldUserValue)fieldUser.GetFieldValue(workflowProperties.Item["User Name"].ToString());

    if (fieldUserValue != null)
    {
      string username = fieldUserValue.User.LoginName.ToString();

      if (!string.IsNullOrEmpty(username))
      {

        //get profile record
        using (SPSite site = new SPSite(workflowProperties.SiteId))
        {
          SPServiceContext context = SPServiceContext.GetContext(site);

          UserProfileManager profileManager = new UserProfileManager(context);

          UserProfile profile = profileManager.GetUserProfile(username);

          //Updates values
          profile[PropertyConstants.PictureUrl].Value = workflowProperties.Item["EncodedAbsUrl"].ToString();

          //commits changes
          profile.Commit();

        }
      }
    }
  }
  catch (Exception ex)
  {
    //write to ULS
    SPDiagnosticsService diagSvc = SPDiagnosticsService.Local;

    diagSvc.WriteTrace(0, new SPDiagnosticsCategory("Workflow", TraceSeverity.Monitorable, EventSeverity.Error), TraceSeverity.Monitorable,
      "Error in Save User Profile Photo workflow: {0}", new object[] { ex.Message.ToString() });
    diagSvc.WriteTrace(0, new SPDiagnosticsCategory("Workflow", TraceSeverity.Monitorable, EventSeverity.Error), TraceSeverity.Monitorable, 
      "Error in Save User Profile Photo workflow: {0}", new object[] { ex.StackTrace.ToString() });
  }
}

Note that there are some slight variations between this code and the Powershell script, namely in the Encoded Absolute Url property name, and the property used to get the username value.

The workflow is now ready to be deployed, so you can update the Feature and Package to your liking.

There is one more crucial task in order to make this work, and that is to grant permissions for modifying the User Profile to the Application Pool service account for the web application in which this workflow will run. If you do not do this, you will receive the following exception when the workflow attempts to modify the profile record.

Attempted to perform an unauthorized operation.
 at Microsoft.Office.Server.UserProfiles.UserProfileValueCollection.CheckUpdatePermissions()    
 at Microsoft.Office.Server.UserProfiles.ProfileValueCollectionBase.set_Value(Object value)    
 at SaveUserProfilePhoto.Workflow1.Workflow1.UpdateUserProfile(Object sender, EventArgs e)

To grant this permission, go to the Manage Service Applications page in the Central Administration site. Select the entry for the User Profile Service Application, and click the Administrators button shown in the Ribbon.

Add the application pool service account, then check ‘Full Control’, and save the changes.

Running the Workflow

To test the workflow out, we’ll add a new image to our Photo Library, being sure to select a person in the User Name field.  We also need to make sure we Check In the record, since workflow will not run on a checked out item.

09_AddNewPhoto

Clicking on the item and viewing its Workflow status will let us see if the Workflow ran successfully.

11_WorkflowStatus

Finally we can go to the user’s MySites profile page and confirm that the image is in place.

10_MySitesProfileWithPhoto

If the workflow code encounters any exceptions, they will be logged to the ULS file, so you can check there to see what happened.


Posted

in

, ,

by

Tags:

Comments

Leave a Reply