How to use a VBScript to update the ExtensionAttribute1 property in Active Directory and use that value to display user profile pictures in MySites.

 

Background

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

Approach

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’.

Challenges

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.

Solution

What we ended up finally deciding on was a three-part process.

  1. We would need to create a repository to store all user accounts.  In our case, all users were in the same domain so we named the pictures ‘UserName.jpg’.  We stored these photos in a picture library in SharePoint, in the ‘my site host’ site collection because it was convenient.
  2. We’d need to write something programmatic that would allow us to loop through all Active Directory users and perform some logical operations based on if a profile picture actually exists.  If the profile picture exists in the repository, we will set the chosen attribute’s value to the location of the photo.  If no photo exists, we empty out the value of the attribute.  This logic ensures that if the photo does not exist, the user gets the default SharePoint user image applied to their profile instead of a red ‘X’ from displaying a photo that does not exist
  3. We’d have to map the user profile property to the chosen Active Directory attribute.

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

 


Usage

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.

Feedback

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!