GAL photos in Exchange 2010

So i started to look into the idea of adding photos of our staff to our GAL and thought I would note down some things i learnt on the way. The first i would suggest is to have a good read to the below 2 URL’s as they have documented quite well what you need to do and how to do it. I will go over the basic steps, and tips i learnt along the way.

GAL Photos in Exchange 2010 and Outlook 2010
http://msexchangeteam.com/archive/2010/03/10/454223.aspx
GAL Photos: Frequently Asked Questions
http://msexchangeteam.com/archive/2010/06/01/455005.aspx

My Comments

The word GAL and Exchange get thrown about a bit so its easy to get confused with where the image is being stored. It actually goes into Active Directory and is stored under thumbnailPhoto field as a hexadecimal. You can upload it a number of ways but i chose to use an Exchange powershell command.

Uploading the image

The command that i used to do this in my environment is as follows:

Import-RecipientDataProperty -Identity "Ivan Dretvic" -Picture -FileData ([Byte[]]$(Get-Content -Path "C:\photos\ivand.jpg" -Encoding Byte -ReadCount 0))

Its very simple to use this script to upload an individual photo. If you want to do a large number of photos you can do a search for similar script that caters for it, or the lazy way by using Excel to get a list of all the formatted commands (with some playing around) and paste output of all the lines in PS. I had to made sure all the images were with the username accordingly so i could do it in one big hit.

Formatting the Image

This part took most of the time for me. The end result should be a 96×96 pixel image (recommended by MS) with a size of 2-5kb. The limit is 10kb but there is no need to have it bigger than 5kb. Two programs i used to resize all the images (in batch) were called EasyImageModifier and ThumbMaker. They are great because they are under 1MB each, are portable apps that work with Win7, and are free.

Other notes

Removing image from a user: The only way i have found so far to remove a user’s thumbnailPhoto was to go to ADSIEDIT and manually remove the information by clicking on the clear button. I am yet to find a PS script to do this.

Including images in Offline Address book: An option to take note on is whether you want the Offline Address Book to hold the actual photo, or just the reference to the AD location. For large organisations its not recommend, but for smaller companies it is feasable to do so.
The benefits of this is you will be able to view the photos when a clients machine is offline. (note it will still work if you are running in Outlook Anywhere mode without this setting)

Program to upload individual photos: A good bloke by the name of Paul Adams wrote a little program (and even modified it to clear the photo) that i now use to make individual changes moving forward. It would be fantastic for more development of this type of software so that i could pass on the role to HR but dont want to give admin rights. Maybe MS will provide that one day, for now here is the software im talking about, its code and the compiled version for you to use. (permission granted by Paul Adams – Contact details can be provided on request.)

ImportUserPictureToAD 1.4.exe (.zip file)


Screenshot of the software in action.

And finally the source code for the above program. Please reference Paul Adams as the author if you are going to update the code in any way.

Paul was kind enough to provide the complete solution file to help someone continue the development of this. It has been written in Visual C# 2010 Express.

ImportUserPictureToAD 1.4.exe source code (the project file is corrupted and i cannot find the original)

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.DirectoryServices;

namespace UpdateUserImage
{
 public partial class MainForm : Form
 {
 public MainForm()
 {
 InitializeComponent();
 }

 private void SaveButton_Click(object sender, EventArgs e)
 {
 AddPictureToUser("cn=" + txtUserName.Text + "," + txtLDAPString.Text, txtDomainController.Text, txtImageLocation.Text);
 }

 void AddPictureToUser(string strDN, string strDCName, string strFileName)
 {

 try
 {
 //check size of file and make sure it is less than
 // 300x300 and smaller than 25k

 if (ImageSizeIsAcceptable(strFileName) == true)
 {
 // Open file
 System.IO.FileStream inFile = new System.IO.FileStream(strFileName, System.IO.FileMode.Open, System.IO.FileAccess.Read);

 // Retrive Data into a byte array variable
 byte[] binaryData = new byte[inFile.Length];

 int bytesRead = inFile.Read(binaryData, 0, (int)inFile.Length);
 inFile.Close();
 inFile.Dispose();

 // Connect to AD
 System.DirectoryServices.DirectoryEntry myUser = new System.DirectoryServices.DirectoryEntry(@"LDAP://" + strDCName + @"/" + strDN);

 if (chkJpegPhoto.Checked)
 {
 // Clear existing picture if exists
 if (myUser.Properties["jpegPhoto"] != null)
 {
 myUser.Properties["jpegPhoto"].Clear();
 }
 // Update attribute with binary data from file
 myUser.Properties["jpegPhoto"].Add(binaryData);
 }

 if (chkThumbnailPhoto.Checked)
 {
 if (myUser.Properties["thumbnailPhoto"] != null)
 {
 myUser.Properties["thumbnailPhoto"].Clear();
 }

 myUser.Properties["thumbnailPhoto"].Add(binaryData);
 }

 myUser.CommitChanges();

 //close/dispose user object
 myUser.Close();
 myUser.Dispose();

 //reset the binary data to keep it clean between operatons
 binaryData = null;

 MessageBox.Show("No errors were encountered during the operation.","Epic Win",MessageBoxButtons.OK,MessageBoxIcon.Information);
 }
 else
 {
 MessageBox.Show("The image must be less than 300 pixels wide and 300 pixels high, and less than 25,000 bytes..", "Hold up there, toughguy", MessageBoxButtons.OK, MessageBoxIcon.Hand);
 }
 }
 catch (Exception ex)
 {
 MessageBox.Show("Error: " + ex.Message, "Error", MessageBoxButtons.AbortRetryIgnore, MessageBoxIcon.Error);
 }
 }

 void ClearUserPicture(string strDN, string strDCName)
 {
 try
 {
 // Connect to AD
 System.DirectoryServices.DirectoryEntry myUser = new System.DirectoryServices.DirectoryEntry(@"LDAP://" + strDCName + @"/" + strDN);

 if (chkJpegPhoto.Checked)
 {
 // Clear existing picture if exists
 if (myUser.Properties["jpegPhoto"] != null)
 {
 myUser.Properties["jpegPhoto"].Clear();
 }
 }

 if (chkThumbnailPhoto.Checked)
 {
 if (myUser.Properties["thumbnailPhoto"] != null)
 {
 myUser.Properties["thumbnailPhoto"].Clear();
 }
 }
 myUser.CommitChanges();

 //close/dispose user object
 myUser.Close();
 myUser.Dispose();

 MessageBox.Show("User image was cleared!", "Epic Win", MessageBoxButtons.OK, MessageBoxIcon.Information);

 }
 catch (Exception ex)
 {
 MessageBox.Show("Error: " + ex.Message, "Error", MessageBoxButtons.AbortRetryIgnore, MessageBoxIcon.Error);
 }
 }

 private void SelectFileButton_Click(object sender, EventArgs e)
 {
 ofd.Filter = "Jpeg files (*.jpg)|*.jpg";
 ofd.FileName = "";
 ofd.ShowDialog();
 if (ofd.FileName.Length > 0)
 {
 this.txtImageLocation.Text = ofd.FileName;
 try
 {
 this.imagePanel.BackgroundImage = Image.FromFile(ofd.FileName);
 this.imagePanel.BackgroundImageLayout = ImageLayout.Stretch;
 }
 catch (Exception ex1)
 {
 MessageBox.Show(ex1.ToString());
 }
 }
 }

 private bool ImageSizeIsAcceptable(string strFileName)
 {
 bool isOK = false;

 //get size of file in bytes
 System.IO.FileStream inFile = new System.IO.FileStream(strFileName, System.IO.FileMode.Open, System.IO.FileAccess.Read);
 Int64 len = inFile.Length;
 inFile.Close();
 inFile.Dispose();

 if ((imagePanel.BackgroundImage.Width <= 300) && (imagePanel.BackgroundImage.Height <= 300) && (len < 25000))
 {
 isOK = true;
 }
 return isOK;
 }

 private void btnEraseImage_Click(object sender, EventArgs e)
 {
 ClearUserPicture("cn=" + txtUserName.Text + "," + txtLDAPString.Text, txtDomainController.Text);
 }
 }
}

Comments welcome.

  1. Just thought I would mention that I’ve made a free application for editing the thumbnailPhoto attribute that offers a few more features than the software you mentioned in this article and is a bit more user friendly. If you want to check it out you can download the free edition here: http://cjwdev.co.uk/Software/ADPhotoEdit/Info.html
    There is a commercial version but the free edition should be able to do everything most people want to do, the commercial version just allows you to do bulk imports and bulk exports.

    Thanks
    Chris

  2. Login user picture on domain - Admins Goodies - pingback on 16 August, 2011 at 21:17
  3. Hi Ivan,

    I was looking to download your “ImportUserPictureToAD-ProjectSourceCode” however it appears to be a broken link.

    Are you able to provide me with a working link please?

    Thank you.

    • Hi Mirza,

      Apologies but it appears that the file is corrupted and missing. I have searched but am not able to find the original. The source code is there however the project file (which would import easily into VisualStudio) is gone.

      Since writing this document i have been using Chris Wright’s program called ADPhotoEdit and have found it to do exactly what I want. I have spoken to the author and since purchased his other AD software because i have found it very useful.
      http://cjwdev.co.uk/Software/ADPhotoEdit/Info.html

      Regards,
      Ivan

  4. use codetwo software..and its free..

Leave a Reply

QR Code Business Card
%d bloggers like this: