MOSS MVP

I've moved my blog to http://blog.falchionconsulting.com!. Please update your links. This blog is no longer in use--you can find all posts and comments at my new blog; I will no longer be posting to this site and comments have been disabled.

Thursday, August 9, 2007

Set Picture URL Property

Within our SPS 2003 environment we stored employee pictures in a picture library. We then set the users Picture URL profile property to point to their picture in this library. The problem was that as soon as we upgraded the paths to these pictures no longer worked. Our pictures were previously found under the path "http://intranet/HumanResources/EmployeePictures/" but after the upgrade the path changed to http://intranet/Topics/Divisions/HumanResources/EmployeePictures/.

So we needed a way to reset the path for all the users in the profile database to reflect this new path (note that in the end we intend to move the photos to a different location as the Topics and Divisions sites that were created will be dumped). My solution was a fairly simple command, called gl-setpictureurlnewpath, which takes in the path to the new picture library and resets all profile users PictureUrl property to reflect this new path. I assume that all the filenames are not changing and that all the photos are in this single library (if your environment has users with photos in different libraries then you'll want to modify this code to take in another variable to help you determine which ones to change). The core code that does this is shown below:

   1: public int Run(string command, StringDictionary keyValues, out string output)
   2: {
   3:  ...
   4:  UserProfileManager profManager = new UserProfileManager(ServerContext.GetContext(sspname));
   5:  foreach (UserProfile profile in profManager)
   6:  {
   7:   if (SetPicture(profile["PictureURL"], librarypath))
   8:    profile.Commit();
   9:  }
  10:  ...
  11: }
  12: private static bool SetPicture(UserProfileValueCollection val, string libraryPath)
  13: {
  14:  string currentUrl;
  15:  if (val.Value == null)
  16:   return false;
  17:  else
  18:   currentUrl = val.Value.ToString();
  19:  
  20:  if (string.IsNullOrEmpty(currentUrl))
  21:   return false;
  22:  
  23:  string newUrl = libraryPath.TrimEnd('/') + "/";
  24:  if (currentUrl.IndexOf('/') < 0)
  25:   newUrl += currentUrl.Trim();
  26:  else
  27:  {
  28:   string file = currentUrl.Substring(currentUrl.LastIndexOf('/'), currentUrl.Length - currentUrl.LastIndexOf('/'));
  29:   newUrl += file.Trim('/');
  30:  }
  31:  val.Value = newUrl;
  32:  
  33:  return true;
  34: }

The syntax of the command I created to do this can be seen below.

C:\>stsadm -help gl-setpictureurlnewpath

stsadm -o gl-setpictureurlnewpath

Fixes the pathing for all user photos or a single user's photo as the result of moving a picture library (assumes file names have not changed).

Parameters:
        -sspname <name of the 2007 SSP>
        -librarypath <path to new photo library (i.e., "http://intranet/HumanResources/Employee%20Pictures/")>
        [-username <NT account name>]

Here’s an example of how to change the picture url path for all users:

stsadm –o gl-setpictureurlnewpath –sspname “SSP1” –librarypath "http://intranet/hr/EmployeePictures"

16 comments:

John said...

Gary, I have installed the extensions form yuor zip file, and while other commands (enumnavigation, etc.) return results, when I run this command stsadm.exe -o setpictureurlnewpath -sspname "SharedServices1" -librarypath "http://ourportal/employees/" , it returns "operation completed successfully", yet the PictureURL property for any user is not changed. Any ideas? I wouldn't think I would need to do a profile update from AD for this to take effect.

Gary Lapointe said...

It's hard to say exactly. Best I could recommend is that you should either step into the code or if you can't do that then add a bunch of Console.WriteLine statements to the code. The code itself is pretty simple - it only updates the profile if the current PictureURL property contains a non-empty/non-null value. If you're not sure how to add the debug info then send me an email (glapointe at edfinancial dot com) and I'll send you a version that will output any information I would need in order to troubleshoot your problem.

Gary Lapointe said...

I think I may have figured out your issue. When profile changes are made there is a timer job that runs that keeps the databases in sync with those changes. If you run the profsynch timer job (stsadm -o runtimerjob profsynch -url "http://ourportal") then you should see the field updates reflected. Note that your content databases need to be online to pick up the change (I had mine offline so this job wasn't actually running). Hopefully this addresses your issue. In general though if you can see the changes when viewing the profiles via your SSP admin site and as long as your content databases are online then you'll eventually see the change.

Wayne said...

Gary,

I'm running into the same problem that you just described the only difference is that I'm still using Sharepoint 2003 and you solution seems to be geared towards 2007. Is there a workaround that I can use to fix the path? Thanks for any help that you can give.

Gary Lapointe said...

You won't be able to do it using my code as is but you should be able to create a separate console application and use portions of what I've created. The API for 2003 isn't as good but I'm pretty sure most of the same capabilities exist (you'll probably have to do a bit more digging though to figure it all out). If you're not sure where to start then I'd recommend taking Reflector and disassembling the 2003 pages used to edit the profile data - you should be able to trace through that code to see what objects are required to edit the information. Sorry I can't be more helpful.

wayne said...

Gary, thanks for the help.

wayne said...

Gary, I have a simple question for you that I can't seem to find an answer for on the web. I've been using SharePoint 2K3 and I'm migrating to 2K7. Here's the question. When I create a list and then populate it how do I later go back and edit a field or a row. Is the Datasheet view the only way to do this. In 2K3 we had the drop down menu and you could edit it that way. I haven't really seen or heard of anything like this in 2K7 and I'm just concerned the end users may get confused. Thanks again for your help

Gary Lapointe said...

Wayne - in this regard 2007 is just like 2003. Most likely the view you are working with is simply configured in such a way so that it's not showing the edit option. If you customize the view you should see fields with things such as "link to item with edit menu" or "link to edit item" in parens next to the field name. Just make sure that one of these is visible. For most list at least of these is visible by default - not sure why the list you're working with is not showing one.

wayne said...

Gary,

Thanks for pointing me in the right direction. I went to the edit view and saw that I had unchecked the edit field which prevented me from seeing the edit icon. Just a case of good ole user error. Thanks again for helping with this.

AndyD said...

Gary, I have installed and deploy the extension but when running your stsadm extension, it always reported "Command line error." even though I can seen through stadm -help setpictureurlnewpath. Is there something that I missed? Please shine me some lights.

Gary Lapointe said...

What's the exact syntax you are using? If you're using the latest build I'm assuming that you are using "gl-setpictureurlnewpath"?

Stacey Arnold said...

Unable to determine lastname from existing profile data (53edb5ee-7b46-460b-8296-06af2b838a8e).

Anonymous said...

Hi, do you know how to retrieve a user's mysite Profile Picture URL using PowerShell?

Gary Lapointe said...

This should do it for you:

[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint")
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.Office.Server")
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.Office.Server.UserProfiles")
$context = [Microsoft.Office.Server.ServerContext]::Default
$profManager = New-Object Microsoft.Office.Server.UserProfiles.UserProfileManager($context)
$user = "spdev\spadmin"
if ($profManager.UserExists($user)) {
$profile = $profManager.GetUserProfile($user)
Write-Host $profile["PictureURL"].Value
}

Bhavesha said...

Hi Gary,

I am new to sharepoint.
i have this requirement.
Can u tell me how do i make command gl-setpictureurlnewpath available at my system ?

Regards.
Bhavi

Gary Lapointe said...

You have to download the appropriate WSP file from the downloads page and deploy it to your farm.