Photos in Active Directory

Posted by on November 9, 2006

The number one reason people come to this page is they want pictures in Outlook from the Global Address List.
It appears this is now possible using Outlook 2010 against Exchange 2010 as outlined by Ilse Van Criekinge in her Technet blog.

Oh my blog, how I’ve neglected you.

Here’s a couple of things I managed to cook up at work this week, again after spending an inordinate amount of time on Google looking for the answer and having to piece it together bit by bit.

The problem: how to store (and retrieve) staff photos in Active Directory. After the first twenty or so webpages I’d decided on using the jpegPhoto attribute. The secondary problem of getting the staff to submit to getting their pictures taken has already been solved by the new photopasses we’re all getting.

Warning: There are some technical considerations to batch importing a large number of pictures into your AD regarding your replication topology. If you had a domain controller at the end of a very slow/poor connection then this could tie up that connection for a prolonged period of time, and as such the pictures could best be stored in ADAM or some other structured content store.

Ok thats the warning out of the way, now on the cool stuff:

1) Resize the images down to an appropriate size, I used Irfanview to batch resize the massive digital camera pics down to about 200×200 pixels resulting in ~25kb files.
2) Save all the pics in a directory named “Firstname Lastname.jpg”
3) Run this vbscript with sufficient (Domain Admin?) rights.

Const ForReading = 1

InDir = "C:\Temp\Staff Photos"
Set fso = CreateObject("Scripting.FileSystemObject")

set oIADS = GetObject("LDAP://RootDSE")
strDefaultNC = oIADS.Get("defaultnamingcontext")

Set theConn = CreateObject("ADODB.Connection")
theConn.Provider = "ADsDSOObject"
theConn.Open "ADs Provider"

Set theCmd = CreateObject("ADODB.Command")
theCmd.ActiveConnection = theConn
Set objRecordSet = CreateObject("ADODB.Recordset")

For Each tFile In fso.GetFolder(InDir).Files
tName = tFile.Name
'Gets the persons Name from the file by stripping the extention.
tName = Left(tName, InStrRev(tName,".")-1)

'You may need to tweak this bit depending on your naming conventions.
strQuery = ";" & _
"(&(objectClass=person)(name=" & tName & "));name,adspath;subtree"
theCmd.CommandText = strQuery
Set objRS = theCmd.Execute

If objRS.RecordCount = 0 Then
MsgBox "Can't find account for " & tName
Set objUser = GetObject(objRS("adspath"))

ObjUser.Put "jpegPhoto", ReadByteArray(tFile.Path)
End If

'Stolen from
Function ReadByteArray(strFileName)
Const adTypeBinary = 1
Dim bin
Set bin = CreateObject("ADODB.Stream")
bin.Type = adTypeBinary
bin.LoadFromFile strFileName
ReadByteArray = bin.Read
End Function

Download: UserPhoto.vb

Ok, thats the import done. I’m not entirely sure that that is the most appropriate format to store the pictures in, but they can be retrieved with the code below.

As part of a project I’m working on I’m looking at the implementation of Sharepoint across various parts of our company, so lets create a SharePoint Webpart to display the pics!

My first problem was how to create a webpart to output an image, not link to an image. In the end, thanks mainly to Simon Tocker I managed to get it working.

Imports System
Imports System.ComponentModel
Imports System.Web.UI
Imports System.Web.UI.WebControls
Imports System.Xml.Serialization
Imports Microsoft.SharePoint
Imports Microsoft.SharePoint.Utilities
Imports Microsoft.SharePoint.WebPartPages
Imports System.DirectoryServices
Imports System.Drawing

'Description for UserPhoto.
"), XmlRoot(Namespace:="WebParts")> _
Public Class UserPhoto
Inherits Microsoft.SharePoint.WebPartPages.WebPart
Implements System.Web.IHttpHandler

Private Const _defaultText As String = ""

Dim _name As String = _defaultText

' Dim imgCtrl As Image

Property [UName]() As String
Return _name
End Get

Set(ByVal Value As String)
_name = Value
End Set
End Property

'Render this Web Part to the output parameter specified.
Protected Overrides Sub RenderWebPart(ByVal output As System.Web.UI.HtmlTextWriter)

End Sub

Protected Overrides Sub EnsureChildControls()

End Sub

Public ReadOnly Property IsReusable() As Boolean Implements System.Web.IHttpHandler.IsReusable
Return True
End Get
End Property

Public Sub ProcessRequest(ByVal context As System.Web.HttpContext) Implements System.Web.IHttpHandler.ProcessRequest

Dim response As System.Web.HttpResponse = context.Response
Dim request As System.Web.HttpRequest = context.Request
Dim who As String
Dim outImg As System.Drawing.Image
Dim AuthUser As String = Right(request.ServerVariables("AUTH_USER"), Len(request.ServerVariables("AUTH_USER")) - InStr(request.ServerVariables("AUTH_USER"), "\"))
Dim ds As New DirectorySearcher("ldap://dc=example,dc=net")

If Not (request.QueryString("user") Is Nothing) Then
who = request.QueryString("user").ToString
End If
ds.Filter = "(&"
If who <> "" Then
ds.Filter &= "(name=" & who & ")"
ds.Filter &= "(sAMAccountname=" & AuthUser & ")"
End If
ds.Filter &= "(jpegPhoto=*))"
Dim res As SearchResult
res = ds.FindOne
If Not (res Is Nothing) Then
'Dim imgStr As String = res.Properties("jpegPhoto").Item(0)
Dim imgByte() As Byte = res.Properties("jpegPhoto").Item(0)
Dim ms As System.IO.MemoryStream
ms = New System.IO.MemoryStream(imgByte)
Dim newImage As System.Drawing.Image
newImage = System.Drawing.Image.FromStream(ms, True)
response.ContentType = "image/jpeg"
newImage.Save(response.OutputStream, System.Drawing.Imaging.ImageFormat.Jpeg)
Dim msg As String = "No image for "

If who = "" Then
msg &= "you"
msg &= who
End If
outImg = DoImage(msg)
response.ContentType = "image/jpeg"
outImg.Save(response.OutputStream, System.Drawing.Imaging.ImageFormat.Jpeg)

End If

Catch ex As Exception
outImg = DoImage(who & " : " & ex.Message)
response.ContentType = "image/jpeg"
outImg.Save(response.OutputStream, System.Drawing.Imaging.ImageFormat.Jpeg)
End Try
Catch es As Exception
outImg = DoImage(who & " : " & es.Message)
response.ContentType = "image/jpeg"
outImg.Save(response.OutputStream, System.Drawing.Imaging.ImageFormat.Jpeg)

End Try
End Sub

Public Function DoImage(ByVal msg As String, Optional ByVal w As Integer = 200, Optional ByVal h As Integer = 50) As System.Drawing.Image
Dim img As System.Drawing.Image
Dim g As Graphics

img = New Bitmap(w, h, System.Drawing.Imaging.PixelFormat.Format32bppArgb)

g = Graphics.FromImage(img)
g.FillRectangle(New SolidBrush(Color.White), 0, 0, img.Width, img.Height)
g.DrawString(msg, New Font("Verdana", 10.0F), New SolidBrush(Color.Black), 0, 0)
Return img
End Function

Protected Overrides Sub OnPreRender(ByVal e As System.EventArgs)

If UName <> "" Then
Me.Title = UName
Dim AuthUser As String = Right(context.Request.ServerVariables("AUTH_USER"), Len(context.Request.ServerVariables("AUTH_USER")) - InStr(context.Request.ServerVariables("AUTH_USER"), "\"))
Dim ds As New DirectorySearcher("ldap://dc=example,dc=net")
ds.Filter = "(sAMAccountname=" & AuthUser & ")"
Dim res As SearchResult
res = ds.FindOne
Me.Title = res.Properties("Display Name").Item(0)
Me.Title = "Your Photo"
End Try
End If
End Sub
End Class

Download: PhotoLoader.vbs

Additional to that .Net code, the assembly must be installed into the GAC, this made it pretty hard for me to debug the handler! I’m going to be splitting it into its own class as having the assembly installed in the GAC means it ignores the one I keep putting into /bin! Also, as mentioned by Simon you need to edit your sharepoint web.config and add a line to the httphandlers section.

I also had to set my Sharepoint trust level to Full as I kept getting a message about AllowPartiallyTrustedCallers() not being set, and I couldn’t for the life of me work out how to set it!

Tags: , , , ,

Incoming links

Comments (48)

  • Glad to be of help. Although I am still ont sure how “scary” the httphandler is yet.

    I’m working on a new usage of handlers for ajax proxys, even if this does was a lot of resources and loads the whole page again for an ajax call its worth it as its only the same that would happen on a postback.

    Long time ago I set security to full and gac’d everything where sharepoint was concerned, not the best solution but if your internal network only then less to worry about.

  • hi
    i used the code for active directory picture.. and there is no error in it.
    but i cant see anything happened after this code. i opened active directory and i didnt find the picture. i opened outlook exchange and i didnt find anything for the user too.
    so what does this code do excatly?

  • The code for retrieving and displaying the pic is a Sharepoint WebPart.

    The standard AD tools don’t have any features for using pictures, even though the AD schema has properties for them.

  • hi
    I used the code for active directory picture.. and it worked a treat. I did have to change the picture names to suit our username convention but it loaded the JPGs straight into the AD. Using Softera LDAP Browser I can click on the jpegPhoto field and it’ll open the JPG in ACDSee.

    I don’t know what to do with UserPhoto.vb, I tried some things but got nowhere. I got lost after that, don’t really know what I’m doing tbh.
    Still, the photos in AD are good 😉

  • Is it possible to see the pics in the Global Address list?

  • You mean in Outlook? Not to my knowledge.

  • How do I know the upload is working?
    Also, can you give more info about the viewing of pictures… how do I put something into the GAC? What exactly needs to go there?
    Step by step info would be very helpful.

  • You can check for something in the jpegPhoto attribute of users using adsiedit.

    GAC? Assuming you mean the GAL in Outlook, then no, there is no way I know of to get pictures to appear there.

  • Nice Work ! But i don’t know how to run vbscript in AD.

  • IIRC you just have to run it using a Domain Admin level account (or an account with sufficient delegated privs) as described, the script connects to the appropriate AD objects and updates the pics onto them.

  • Hi.
    I am not so familiar with .NET, and i am wondering what exactly to do with this .NET code (UserPhoto.vb). I downloaded .NET Framework SDK to use gacutil, but there is no result. I think that, this code must be compiled or somethink ,i don’t know.
    Can anyone help me ?

    Thank’s in advance.

  • UserPhoto.vb is the code for a Sharepoint 2003 webpart. They can be really fiddly to install and debug. If you’re not using sharepoint you may want to modify the code to your own solution.

  • Hi
    I know that userphoto.vb is the code. I tried to compile it with vbc(virtual basic compiler) but reports an error in the compilation process :
    BC40056: Namespace or type specified in the Imports ‘Microsoft.SharePoint’ does
    n’t contain any public member or cannot be found. Make sure the namespace or the
    type is defined and contains at least one public member. Make sure the imported
    element name doesn’t use any aliases. I

    Imports Microsoft.SharePoint

    There is installed .net framework SDK on the server.The server is with Windows Server 2003 64bit and the SDK is 64bit too.There is installed Share point serveces 64bit. I can’t understend what is wrong. I looked in c:\windows\assembly and find out that “Microsoft.Sharepint” assembly exists.

    I don’t know what to do.

  • Hi again.
    I compiled the dll but now when i try to install it ito the GAC the result is
    “Failure adding assembly to the cache: Attempt to install an assembly without a strong name”

    What is the Strong name of the assembly and how to sign it ?
    If anyone know, please help me because i am almost done.

  • Yordanov,
    If u r using Visual Studio 2005 (or VS2008) use the command:
    sn -k c:\keyfile.snk
    where the “keyfile.snk” its the output file, now this file must be use in your application (Visual Studio) using the IDE go to Project, Properties, Signing, clic on the checkbox “Sign the assembly” on the textbox choose your recently created “keyfile.snk”
    Compile the entire project, now your assembly has an strong name.

  • Hello Arricc:

    I am trying to implement your code on a MOSS system. Everything compiles, installs on “http://iplacer:4001/” etc. But I keep getting a “File Not Found” page display on the page http://iplacer:4001/_layouts/MySite.aspx when I try to open my users MySite. When I take out the web.config “HTTP Handlers” line the page again opens normally. I just can’t figure out what “file” is not being found. I’ve redone everything several times and am stuck. Any suggestions? Thanks in advance.

  • On #16, I was a bit worn out. I’m using the “UserPhoto” vb code to obtain photos already installed in our AD “jpegphoto” field. I got the complete error dump which follows:

    File Not Found. at System.RuntimeTypeHandle._GetTypeByName(String name, Boolean throwOnError, Boolean ignoreCase, Boolean reflectionOnly, StackCrawlMark& stackMark, Boolean loadTypeFromPartialName) at System.RuntimeTypeHandle.GetTypeByName(String name, Boolean throwOnError, Boolean ignoreCase, Boolean reflectionOnly, StackCrawlMark& stackMark) at System.RuntimeType.PrivateGetType(String typeName, Boolean throwOnError, Boolean ignoreCase, Boolean reflectionOnly, StackCrawlMark& stackMark) at System.Type.GetType(String typeName, Boolean throwOnError, Boolean ignoreCase) at System.Web.Compilation.BuildManager.GetType(String typeName, Boolean throwOnError, Boolean ignoreCase) at System.Web.Configuration.ConfigUtil.GetType(String typeName, String propertyName, ConfigurationElement configElement, XmlNode node, Boolean checkAptcaBit, Boolean ignoreCase)

  • Afraid I can’t help much with this anymore as I’ve not done any work with Sharepoint in a while…

    The only thing I do remember is having problems with the security model and having to drop all the permission levels way down to allow stuff to work…

  • Interesting page you have here.
    I did a similar project with pictures in Active Directory users and computers. You can see the results on my webpage:
    I managed to get pictures displayed directly in ADUC.

  • Forgot to create a direct link:
    Here you will find information on how to enable ADUC for pictures.

  • Dudes, the Address Book / Global Address List in Outlook 2007 has a built-in viewer for jpegs. When you double-click on a particular user to see their contact details, the jpeg will display as well (if you have populated the user attribute with the data / photo). Along with the vbscript code at the top of this page (which I gratefully acknowledge), your work is done! (All for the cost of upgrading to Outlook 2007, which has other benefits as well). If upgrading to outlook 2007 isnt an option, for $300 you can buy a web-page which you can publish on your corprate intranet – do a seach on Directory Manager, the company is Ithicos, they have 3 products for directory searching and updating that are dirt cheap ($300 each), brain-dead simple to install and configure, and really do the job as advertised (plus display the photos). Go ahead – make my day!

  • Thanks for this code, the VBS for uploading photos is great, the download links appear to be the wrong way round though (photoloader.vbs should be the first, second).

    I was wondering if there was a way of retrieving the photos as .jpg for all the users (assuming a picture exists). Unfortunately my scripting isn’t very good, but I guess it would be a process such as:

    Get all usernames
    For each username
    If jpegPhoto exists then
    Save jpegPhoto as username.jpg
    End If

    Does anyone know if this is possible, and how you’d go about it? Thanks!

  • You could try AD Pictures by Exclaimer
    they have this already built

  • Is there a way to do this without importing pictures into AD and making the size of AD larger? Can we just store the pictures in Sharepoint and somehow link them to our GAL so that the pictures show up when people email eachother?

  • I’ve still not found any method by which pictures can be stored in AD and automatically displayed in Outlook – without the installation of 3rd party software.

    One work around is to create a public folder with a contact with a picture for each user in it. That public folder is then set as an address book for all users and the pictures will then appear when users email.

  • Have you tested that Public Folder approach?

  • Works. PITA to keep up to date though.

    And also you have to work out how to set it as an address book for every user.

  • Use sharpoint contacts to store pictures and then make connection to outlook with sharepoint gui to use as contacts in outlook. Has to be done in each client.

  • Thats much the same as storing the contacts in a public folder, but requires the extra step of installing and managing Sharepoint…

  • It would seem that you could link the SharePoint User Photo (in the top left corner of a MySite) to the Active Directory jpegPhoto property, but I am finding that is not the case. Anyone have any luck doing this?

  • Could someone tell me the difference between the Photo attribute in the AD Schema vs, say the jpegphoto attribute? I keep reading that the Photo attribute is an object encoded in G3 fax format to store monochrome images, but then I’ve read in other articles that people are using that attribute to import .jpeg’s. I don’t understand the purpose of the attribute, and it irritates me. Can anyone enlighten me?

  • Is there a recommended limit to how big the photos should be? You suggest 25kb, all my photos are 40kb, would you suggest I make them smaller? If so can anyone suggest a batch tool? I have 1500 photos 🙁

    You can use the trial version of the program below to view the images, it was useful when I was testing the script.

  • Hi Steve,

    You have to remember that whatever pic size you use will increate the size of your AD, and also be aware of the initial hit of replication traffic to all of your DCs.

    1,500 pics at 40Kb = 60,000Kb or ~58.5Mb not too much of an increase in size maybe, certainly not as much as if you were using Group Policy to deploy and app!

    You can use Irfanview[1] for batch processing your images, its quite powerful.

    I’ve just found out that the #1 requirement of people posting on this article- photos in Outlook – is finally a feature of Outlook 2010 apparently against Exchange 2010. And, typically, it uses a different attribute. I’ve not had any time to look at this and check if the byte encoding my article uses is the same, and the script could just be changed to use the thumbnailPhoto instead.


  • For Outlook 2010 it seems that it is the thumbnailPhoto attribute that must be populated and not jpegphoto. I just the line in the vbs that has ObjUser.Put “jpegPhoto” to ObjUser.Put “thumbnailPhoto” and it worked perfectly (with a jpeg pic). I read somewhere else that photos must be < 10 kb, but haven't tested this myself.

    Thanks for the script!

  • Why not use the photo URL on the User Profile to display the image? It works in both MOSS 2007 and SharePoint Server 2010. No need for a custom web part to read AD. Also, properly configured SharePoint 2010 will write the Profile image URL back to AD if you want to keep everything in synch.

  • @Matthew – this was originally about a webpart for Sharepoint 2005…. 😉

    For some reason most of the comments are about pics in Outlook though!

  • I’m trying to use the photoloader.vbs file and it can’t find my user name – Mike Johnson. How would I configure the vbs to work with my user account mjohnson?

  • Works perfect!!!!

    But you have to change the attribute thumbnailPhoto for use with outlook 2010.

    Const ForReading = 1
    InDir = “H:\adpictures”
    Set fso = CreateObject(“Scripting.FileSystemObject”)
    set oIADS = GetObject(“LDAP://RootDSE”)
    strDefaultNC = oIADS.Get(“defaultnamingcontext”)
    Set theConn = CreateObject(“ADODB.Connection”)
    theConn.Provider = “ADsDSOObject”
    theConn.Open “ADs Provider”
    Set theCmd = CreateObject(“ADODB.Command”)
    theCmd.ActiveConnection = theConn
    Set objRecordSet = CreateObject(“ADODB.Recordset”)
    For Each tFile In fso.GetFolder(InDir).Files
    tName = tFile.Name
    ‘Gets the persons Name from the file by stripping the extention.
    tName = Left(tName, InStrRev(tName,”.”)-1)
    ‘You may need to tweak this bit depending on your naming conventions.
    strQuery = “;” & _
    “(&(objectClass=person)(name=” & tName & “));name,adspath;subtree”
    theCmd.CommandText = strQuery
    Set objRS = theCmd.Execute
    If objRS.RecordCount = 0 Then
    MsgBox “Can’t find account for ” & tName
    Set objUser = GetObject(objRS(“adspath”))
    ObjUser.Put “thumbnailPhoto”, ReadByteArray(tFile.Path)
    End If
    ‘Stolen from
    Function ReadByteArray(strFileName)
    Const adTypeBinary = 1
    Dim bin
    Set bin = CreateObject(“ADODB.Stream”)
    bin.Type = adTypeBinary
    bin.LoadFromFile strFileName
    ReadByteArray = bin.Read
    End Function

  • Hello Arricc!

    I’m looking for method to store pics in AD without the installation of 3rd party software, and your workaround with creating a public folder with a contact with a picture for each user in it seems to be very interesting for me.

    I’ve got two questions:
    – How to set up Adress book from public folders as a default adress book?

    – And what software do you use for keeping up to date public folder adress book? I couldn’t find any software called PITA…

  • I believe this was mentioned before but wasnt sure if it was answered if user names are in the format eripoll instead of eli ripoll. what change would we make to the vb code. thanks

  • Fizzgig, thanks so much. I have implemented your script, and also set an extended attribute in AD that replicates to my MOSS 2007 users. The photos go into a site in Sharepoint where each user has a thumbnail photo of themselves. When I want to do an update I copy all the photos from the photo library to a directory and then run the script that puts them in AD. Now all users have a photo that shows in email and the same photo that shows in Sharepoint.
    My problem is this. For user who did not have a photo, i created a picture called “no photo.jpg”. This gets entered into AD and the URL in AD points to http://site/imagelibrary/no%20photo.jpg. This also works. But then when the user updates thier photo, it gets entered in to AD with your script just fine, but the URL in Sharepoint does not get updated.
    If I look at the users profile in sharedservices the url now points to http://shite/imagelibrary/firstname%20lastname.jpg. This is correct. However if i look at the users properties on a site the old url and image apear. what is happening? why do the values not match?

  • Hi All,

    I have already setup photo’s in sharepoint and exchange 2010 using galphoto in the Exchange management shell. Now what i want to do is use the same pictures form the GAL to display on each users windows 7 logon screen. Does anybody know if this is possible? Would i need to run a script?



  • Can we just store the pictures in Sharepoint and somehow link them to our GAL so that the pictures show up when people email eachother?

  • Thats a long script for something that can be solved with 2 lines of PowerShell 🙂
    $photo = [byte[]](Get-Content C:\abc.jpg -Encoding byte)
    Set-ADUser abc -Replace @{thumbnailPhoto=$photo}

    If you are not running 2k8 R2 you can download Quest ADmanagement cmdlets and do it like this:
    Set-QADUser $_.UserName -ObjectAttributes @{thumbnailPhoto=”$photo”;}

  • Anders, can you be more explicit on how can i do it in w2K3. Pls i dont know even how to enable-use Power Shell in w2K3

    Thanks in advance.

Do you have anything to say?

Powered by Wordpress and Stripes Theme Entries (RSS) | Comments (RSS)