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,
- Check if a User Name has been set. If so,
- Retrieve the User’s Profile
- Set the ‘PictureUrl’ value to the Url of the item in the picture library.
- Save the Profile record.
- 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
Next, with the Workflow Designer open, select a ‘Code’ element from the Toolbox and drag it on to the workflow after the onWorkflowActivated1 event.
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.
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)
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.
Clicking on the item and viewing its Workflow status will let us see if the Workflow ran successfully.
Finally we can go to the user’s MySites profile page and confirm that the image is in place.
If the workflow code encounters any exceptions, they will be logged to the ULS file, so you can check there to see what happened.
Leave a Reply