Archive for March, 2013

Programmatically updating locked down user profile attributes from a web part

Wednesday, March 6th, 2013

Central Admin User Profile Service Profile PropertyIn our organization, we have a policy in place that only a peron’s organizational ID photo may be used in their SharePoint user profile.  We have it set to show by default.  However, we also allow them to “opt-out” of having it displayed.  We’ve created a simple web part that has two buttons to opt-in or opt-out of the photo being displayed in various systems in our organization.  To disable it in SharePoint and in Active Directory, we require that the “PictureUrl” user profile attribute be empty (not pointing to an image).  We have a reverse sync of that particular attribute back to Active Directory.  The Active Directory “thumbnailPhoto” is used in other various systems around the organization that integrate into Active Directory.  For the PictureUrl attribute, we have it set so that users cannot modify it.  Afterall, we don’t want them uploading in appropriate photos!

Central Admin User Profile Service PermissionsBut our opt-out web part needed to be able to modify that attribute.  Like most other web parts, it runs under the current user context.  Our non-admins do not have “Manage Profile” rights as that would be very dangerous since it would give a user access to other user’s profile data.  So the following code produced the error “Property Not Editable: This property can only be modified by an administrator”.

SPServiceContext serviceContext = SPServiceContext.GetContext(HttpContext.Current);
UserProfileManager upm = new UserProfileManager(serviceContext);
UserProfile up = upm.GetUserProfile(“DOMAIN\username”);
up["PictureURL"].Value = “http://www.someurl.com/image.jpg”;
up.Commit();

So the next logical step is to run the code using elevated privileges (RunWithElevatedPrivileges).

SPSecurity.RunWithElevatedPrivileges(delegate()
{
…code snippet from above…
});

But that still didn’t work, we continued to get the same error.

After some research, we found others who ran into the same problem and apparently user profile access has some problems using impersonation (as in it just doesn’t work!).  Somebody did find a workaround though, a hack of sorts, by removing the current context reference before calling the UPM.

SPSecurity.RunWithElevatedPrivileges(delegate()
{
HttpContext httpContext = HttpContext.Current;
SPServiceContext serviceContext = SPServiceContext.GetContext(httpContext);
HttpContext.Current = null; // Hack !!!
UserProfileManager upm = new UserProfileManager(serviceContext);
UserProfile up = upm.GetUserProfile(“DOMAIN\username”);
up["PictureURL"].Value = “http://www.someurl.com/image.jpg”;
up.Commit();
HttpContext.Current = httpContext; // Restore !!!
});

This technique has been working fine for me in SharePoint 2010.  However, I have seen some blog posts with the following technique which some say is more appropriate for SharePoint 2010 and doesn’t involve a hack.  I haven’t tried this method yet.

UserProfileConfigManager upcm = new UserProfileConfigManager(spServiceContext);
ProfilePropertyManager ppm = upcm.ProfilePropertyManager;
CorePropertyManager cpm = ppm.GetCoreProperties();
CoreProperty cp = cpm.Create(false);
ProfileTypePropertyManager ptpm = ppm.GetProfileTypeProperties(ProfileType.User);
ProfileTypeProperty ptp = ptpm.Create(cp);psp.IsUserEditable = true; // important in this case!
ProfileSubtypeManager psm = ProfileSubtypeManager.Get(spServerContext);
ProfileSubtype ps = psm.GetProfileSubtype(ProfileSubtypeManager.GetDefaultProfileName(ProfileType.User));
ProfileSubtypePropertyManager pspm = ps.Properties;
ProfileSubtypeProperty psp = pspm.Create(ptp);

Solutions fail to complete deploying or retracting

Tuesday, March 5th, 2013

I ran into a problem today that I’ve seen before, but have never been able to solve until now.  I saw the problem once in an old MOSS 2007 farm, and then recently in a SharePoint 2010 farm.  Whenever I attempted to deploy or retract a solution, the process would begin but never complete.  There would be a one-time timer job definition, which I could run, but it would not remove itself afterwards.  Regardless of how I tried to deploy/retract (PowerShell, Central Admin, STSADM, etc) the process would never complete.  I would have to delete the timer job definition in order for the “Deploying…” or “Retracting…” to go away from the solution screen in Central Admin.

So what’s the solution?  I found that the timer service on the web servers was stopped!  Once I restarted it on the web servers, solutions completed deploying and retracting properly!