I was recently engaged with a customer who wanted to populate SharePoint user profile pictures from Active Directory. The customer was using Microsoft Office SharePoint Server 2007 and Exchange Server 2003. They had been using a solution written by Gary Lapointe, which was working fine and really wasn’t causing any problem. This solution is documented in one of Gary’s blog post titled ‘Set User Profile Picture Url Property Using Stsadm Revisited’. The goal of the engagement was simply to change the architecture of the solution such that we relied on values stored in Active Directory and leveraged profile import, instead of relying on scheduled tasks to update user profile information
Typically this is a relatively simple process. First we would populate all of the user profiles with the expected attribute and value, and then edit the user profile properties and map the ‘picture’ property to the AD attribute. This is documented very well in a blog by Henry Ong titled ‘Importing User pictures from Active Directory to MOSS 2007’.
This becomes a little easier in newer technologies. SharePoint 2010 offers a few ways to populate Active Directory properties For instance, SharePoint 2010 will sync user photos directly to the thumbnailPhoto attribute in Active Directory. Russ Maxwell actually has a good post titled ‘SharePoint 2010 Profile Picture Property 101‘ describing this process on his blog. SharePoint 2007 has a few hoops to jump through, and a quick search of the internet will provide you with virtually hundreds of solutions telling you how to do this.
The next challenge we ran into is that as we move towards PowerShell as SharePoint administrators, other scripting languages become harder to work with. Part of the process to update Active Directory with the required information will involve accessing extension attributes. Though these can be accessed using tools like ADSI edit, they’re not exposed to the AD PowerShell snap-ins. They are available with some third party tools, but we really don’t need to complicate this solution for what should be a one-time effort, or at most a very minimal-use solution.
What we ended up finally deciding on was a three-part process.
The first part was easy. It’s a matter of simply creating a picture library and populating it with pictures for users, and applying the appropriate naming convention. The third part is also simple, and is covered well up above in Henry Ong’s blog post. This is what we did for part 2 in order to link these two parts together. We wrote the following VB Script:
You can download the script from this location: Download UpdateExtensionAttribute1.vbs (Zipped)
‘Create the Variables that will be needed in the script
Dim s Dim PictureURL Const ADS_PROPERTY_CLEAR = 1 Dim PhotoLibrary = “http://my.contoso.com/employeephotos/” SET objParent = GETOBJECT(LDAP://OU=Users,,DC=Contoso,DC=Com) objparent.FILTER = ARRAY("user")
With CreateObject("MSXML2.XMLHTTP") ‘Loop through each user in the specified OU FOR EACH objUser in objParent
'Notify Administrators Which Object Is Being Evaluated Wscript.Echo "Evaluating " & objUser.Get("CN")
'Set the URL to the user photo location PictureURL = PhotoLibrary & objUser.GET("SAMAccountName") & ".jpg"
'Retrieve the header for the document .open "HEAD", PictureURL, false .send s = .status ‘If we retrieve a HTTP status of 200 (OK), the picture for the user exists. Update the Extension Attribute if(s = 200) then objUser.put "extensionAttribute1”, PictureURL objuser.Setinfo Wscript.Echo("Photo for user " &Objuser.GET("CN") & “ exists. ExtensionAttribute1 has been set to “ &PictureURL) elseif(s = 404) then Wscript.Echo("Photo For User " &Objuser.GET("CN") & " does not exist. ExtensionAttribute1 has been cleared.") objUser.putex ADS_PROPERTY_CLEAR, "extensionAttribute1", 0 objuser.Setinfo else Wscript.Echo(s) end if NEXT End With
To run this script, you will want to execute the following command from the command prompt: ‘cscript.exe UpdateExtensionAttribute1.vbs’. The default behavior for Wscript is to output messages to a message box with an OK button, which will require user action for each of the Wscript.Echo actions in the script. Cscript will output these messages to the console, which is much more user friendly.
As always, if you have any questions or feedback, let me know. If you have any ideas to optimize the script, I’d like to hear that too. Thanks for reading!