Wednesday, November 30, 2011

Using Powershell to Update SharePoint 2010 User Profile

In previous post a small piece of code demos a simple way to update the user profile picture by object model. The same task can also be achieved easily using Powershell:
$userAccount = "SP2010\test"
$newPictureURL = "http://SP2010Site/Photos/test.jpg"
$site = Get-SPSite("http://SP2010Site")
$context = Get-SPServiceContext $site
$profileManager = New-Object Microsoft.Office.Server.UserProfiles.UserProfileManager($context)
$userProfile = $profileManager.GetUserProfile($userAccount)
$userPicture["PictureURL"].Value = $newPictureURL
$userProfile.Commit()
Actually there's some improvement in SharePoint 2010 user photo management. Instead of one picture being used everywhere in SharePoint 2007, SharePoint 2010 maintains three different profile pictures to be used in different contexts. Three images will be created when a user uploaded a picture which are stored in a library folder inside MySite's root site: http://mysite/User Photos/Profile Picture. You can get more detailed SharePoint 2010 photo management from this MSDN blog.

What about a SharePoint 2010 environment upgraded from SharePoint 2007? All the user pictures are still pointing to the old location. However, you can use following Powershell script to migrate all those pictures:
Update-SPProfilePhotoStore -MySiteHostLocation http://SPMySite/
What it does is rebuild all user pictures from previous verion. For example, a user with AD account of SP2010\test has the picture location of http://sp2010site/Profile Pictures/test.jpg. Then three images will be created after above Powershell command execution:
1. http://mysite/User Photos/Profile Pictures/SP2010_test_LThumb.jpg
-- size: 148x148 pixel
-- exmaple of usage: mysite title image
2. http://mysite/User Photos/Profile Pictures/SP2010_test_MThumb.jpg
-- size: 96x96
-- exmaple of usage: people search result image
3. http://mysite/User Photos/Profile Pictures/SP2010_test_SThumb.jpg
-- size: 36x36 small image
-- exmaple of usage: mysite colleague photo

One common scenario is to update test accounts' email address so testers/developers can get the email notification in the test environment. User's email address used by SharePoint to send the email notification is not directly from the user profile, instead it's from a user record in the User Information List tied to top site collection (the user info list data could be overridden by user profile service). In order to change a user's email address you have to modify the list item value in the user information list for a given site:
$web = Get-SPWeb http://sp2010site
$userInfoList = $web.Lists | where { $_.Title -eq "User Information List" }
$userAccount = $userInfoList.Items | where { $_["Account"] -eq "sp2010\test" }
$userAccount["Work e-mail"] = "whatevername@whatever.com"
$userAccount.Update()
Be aware that the modification could be overridden by user profile service's scheduled synchronization if you have user profile service enabled.

This is not related to user profile, but it's also common issue in a migrated SharePoint environment. A SharePoint 2010 farm migrated from SharePoint 2007 without visual upgrade will keep the old UI. But you will notice a new site created after migration (root site or subsite) would always use the new SharePoint 2010 UI. In case you just want to keep the old UI and don't have a short-term plan for UI upgrade, how to revert the new created site back to previous version? Simply a few lines of script:
$web = Get-SPWeb http://sp2010site/newsite
$web.UIVersion = 3
$web.MasterUrl = "/newsite/_catelogs/masterpage/homepagev3.master"
$web.AlternateCssUrl = "newsite/style library/customlayout.css"
$web.Update()

For more hands-on Powershell scripts used in SharePoint environment, refer to this codeplex project complied by a few SharePoint gurus.

Tuesday, November 29, 2011

SharePoint Server 2010 User Profile

There's no big change between SharePoint Server 2010 and MOSS 2007 in terms of User Profile management. The MOSS 2007 user profile database attached to SSP (Shared Service Provider) can be mounted directly to SharePoint Server 2010 User Profile Service Application. The mount process actually upgrades the MOSS 2007 user profile database. You will notice some new tables and columns are added in the backend database. Following image shows the scheme change made on the UserProfile_Full table in user profile database.

The User Information List is still there in each top site collection where SharePoint foundation manitains the basic user data. A record will be added to the User Information List when a user or a group is first referenced by the SharePoint environment. The initial User Information data, like title, user login, email address, etc., are imported from the authentication provider such as Active Directory. In SharePoint Foundation 2010 the User Information List is updated when you modify user info through "My Settings". All User Information List data are stored in the UserInfo table in content database:

Once the User Profile Service is enabled in SharePoint Server 2010, the User Information List became read-only for end user except the "Mobile Number" property, and user profile database is updated when the user modifying "My Settings", instead of the User Information List (UserInfo table). A timer job is responsible for replicating the user profile data to User Information data for each top site collection, and User Information List data will be overridden unless the corresponding property is not set to "Replicable" in User Profile Service:

Sometime it would cause some confusion when the User Information data are not synced to the User Profile data. Remember regular SharePoint sites always get user info from the User Information List but the User Profile content are the original data source when User Profile Service is enabled.

There's slight difference in SharePoint 2010 when accessing or updating the user profile data comparing with SharePoint 2007. In MOSS 2007, Microsoft.Office.Server.ServiceContext is available and you can create a UserProfileManager object from a ServiceContext. In SharePoint 2010 ServiceContext is replaced by the new Microsoft.SharePoint.SPServiceContext:

void UpdateUserProfiles(string siteUrl)
{
string userName = null;
using (SPSite spSite = new SPSite(siteUrl))
{
//ServiceContext is obsolete in SharePoint 2010
//UserProfileManager userProfileManager = new UserProfileManager(ServerContext.GetContext(spSite));

UserProfileManager userProfileManager = new UserProfileManager(SPServiceContext.GetContext(spSite));

foreach (UserProfile profile in userProfileManager)
{
string account = Convert.ToString(profile[PropertyConstants.AccountName].Value);
if (string.IsNullOrEmpty(account) || account.IndexOf("\\") <= 0)
continue;
userName = account.Substring(account.IndexOf("
\\"));
profile[PropertyConstants.PictureUrl].Value = GetUserPhotoLocation(userName);
profile.Commit();
}
}
}
The method simply goes through each user profile, and updates the user photo by some custom logic (GetUserPhotoLocation method). Notice Microsoft.Office.Server.UserProfiles has become a separate dll in SharePoint 2010, so in order to get above code compiled you need to add Microsoft.Office.Server and Microsoft.Office.Server.UserProfiles to the references.