Programmatically updating user profile properties (specifically Email) for inactive users may cause you grief.
In SharePoint a user’s email address (along with some other key properties including name, login etc. ) are stored in three distinct locations. There are:
- User Store (this could be AD, SQL for FBA etc.)
- User Profile Database (specifically the ‘
- SharePoint Content Database(s) (specifically the ‘
For the sake of this article I am making the presumption that User Profiles have been configured.
The data stored across these locations needs to be keep synchronised for obvious reasons and this done in different ways depending on the source being updated. For FBA updating the User Store will almost certainly only occur via User Profiles if it is allowed at all (depending on what properties you decide to store there), so sync’ing TO the User Profile Database will not be considered. In the case of an update occurring in AD, the User Profile Synchronisation timer job will periodically check for updates and persist them to the User Profile Database. You find more on this here.
A scheduled process will then sync’ the User Profile Database with the SharePoint content database.
It is this part of the process which has inspired me to write this post; there is an important caveat to previous sentence. It should be as such: A scheduled process will then sync’ the User Profile Database with the SharePoint content database for all active users (in this case an active user is one that has saved his/her user profile). The impact of this is that if you programmatically update the email user profile property for an inactive user (e.g. from
firstname.lastname@example.org) the property value will not be sync’ed and an action such as:
SPUser user = ...; Mailer.SendEmail(subject, body, user.Email)
will send an email to
email@example.com rather than
UserProfile profile = ...; Mailer.SendEmail(subject, body, profile["Email"])
would correctly send the email to
firstname.lastname@example.org (Note: Mailer is a fictitious class in these examples).
For FBA scenarios this follows on what may be a more significant issue. If you have your users login using their email address then most likely the FBA login name includes this email address (e.g. for user with email
email@example.com, their login name is
i:firstname.lastname@example.org). If your custom developed components include code that relies on this relationship, such as
web.EnsureUser(TOKEN + email), then this code may start failing for these inactive users. It’s unlikely that this will affect the inactive users themselves (as they aren’t using the system) but it may affect other users which are attempting to interact with these users that exist in the system before they have begun using the system.
I believe that the goal is to update the tp_Email column in the SharePoint content database UserInfo table. I have been unable to find an API which does this.
Set-SPUser does not achieve this, and nor does
SPFarm.MigrateUserAccount. I don’t dare break best-practice and update the table directly as in my case knowledge of this issue was enough. This is because the only time we attempt to update inactive user profiles is when obfuscating production email addresses upon restoring production database backups to our test environments. Having said that I would be very interested to hear of a good solution to this issue if anyone has found one.
I hope I saved you a headache.