Where are the pictures physically stored? In AD, in the db somewhere or in the user's mailbox on the Exchange server?
Where are the pictures physically stored? In AD, in the db somewhere or in the user's mailbox on the Exchange server?
I realize this post was meant more to describe the new tools in Exchange 2010, but this actually alerted me to the fact that this could be done in Exchange 03/07 as well. However, your domain does have to have the forest prep done for Server 2008 (but does not need any 2008 DC's). I discovered this after much head banging with MS beta support. With those schema additions, Outlook pulls the picture from the thumbnailphoto attribute like a charm.
Great new Outlook 2010 feature.
I actually got this working in a 2003 Native AD forest without any of the 2008 and up schema extensions. The thumbnailPhoto attribute is there, though I'm not sure what schema update added them. I do have the Exchange 2010 schema updates, so maybe that added them.
The step I did forget was replicating the attribute to the global catalog. Once I did that, it all worked like a charm.
@ctobio: you dont need a forest prep or anything else to get this work....this works with a native 2003 ad, too. No need to prep
Thanks for the tip - nice feature, it would be really good if the clients could change this.
Just a reminder (as it took me a while to remember/find) to set the attribute to sync, first register the schema plugin with "regsvr32 schmmgmt.dll"
Run mmc, add Active Directory Schema
I'm confused... why does every single article on the internet state that this attribute is limited to 10 KB when it is actually 100 KB ? Look at the screenshot in this blog post of the thumbnailPhoto attribute properties and you can see the maximum is 102400 (bytes) which is 100 KB. I thought maybe I was missing something obvious but I just confirmed it by uploading an image into this attribute that was roughly 90 KB - it worked fine. When I tried to upload an image that was 120 KB however it failed with the error "a constraint violation occurred" which is exactly what you would expect if the attribute is limited to 100 KB.
I don't know if the powershell cmdlets that come with Exchange 2010 prevent you from actually choosing an image larger than 10 KB though... but if anyone wants a free easy to use GUI program for uploading single or multiple images, I've nearly finished making such a program. You can find more info on my blog here: cjwdev.wordpress.com/.../ad-photo-edit-a-program-for-uploading-images-into-the-active-directory-thumbnailphoto-attribute-used-by-outlook-2010
Hi, i have developed a GUI application for managing the thumbnailPhoto Attribute, too. You can find it on my blog here: www.starcoder.net/thumbnailphoto-tool
Yavuz, I'm a bit disappointed that your app won't even open if you are not running it on a computer that is a member of a domain. I wanted to try it out from my home PC against a test domain over a VPN.
hi, if we implement Outlook 2010 contact picture adding on Exch 2003, does anyone know what attribute in AD will the pics be stored?
Chris128, hello Chris thank you for your respond. The reason is, that the tool allows the current logged in user to change his photo or another persons /accounts photo in the ad. That emans the that it tries to connect top the ad with your current credentials. I will have a look for extending the application, so that you provide different credentials to connect to the ad. thank you. best regards Yavuz
Yavuz, yeah if it is a .NET application then it is pretty easy to bind to the domain with different credentials and also let the user specify a domain name themselves. In my AD Photo Edit application (www.cjwdev.co.uk/.../Info.html) I try to bind to the user's domain first but have an option to disable this and enter a domain name and credentials of your own - I think its a useful option personally but I guess the majority of people will be running this on the domain they actually want to work with anyway.
Abbas, it still uses the same AD attribute - thumbnailPhoto
Codez: Updates two attributes so that it also shows up in Cisco Unified Presence as well as Outlook 2010.
Cheers
form1.cs
------------------------------------------
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 WindowsFormsApplication1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
AddPictureToUser("cn=" + txtUserName.Text + "," + txtLDAPString.Text, txtDomainController.Text, txtImageLocation.Text);
}
void AddPictureToUser(string strDN, string strDCName, string strFileName )
{
try
{
// 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);
// 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 (myUser.Properties["thumbnailPhoto"] != null)
{
myUser.Properties["thumbnailPhoto"].Clear();
}
myUser.Properties["thumbnailPhoto"].Add(binaryData);
myUser.CommitChanges();
myUser.Close();
myUser.Dispose();
binaryData = null;
MessageBox.Show("Done!");
}
catch (Exception ex)
{
MessageBox.Show("Error: " + ex.Message, "FUUUUU... You are doing it wr-", MessageBoxButtons.AbortRetryIgnore, MessageBoxIcon.Error);
}
}
private void button2_Click(object sender, EventArgs e)
{
ofd.ShowDialog();
if (ofd.FileName.Length > 0)
{
this.txtImageLocation.Text = ofd.FileName;
try
{
this.panel1.BackgroundImage = Image.FromFile(ofd.FileName);
this.panel1.BackgroundImageLayout = ImageLayout.Stretch;
}
catch (Exception ex1)
{
MessageBox.Show(ex1.ToString());
}
}
}
}
}
--------------------
namespace WindowsFormsApplication1
namespace WindowsFormsApplication1
{
partial class Form1
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.button1 = new System.Windows.Forms.Button();
this.txtUserName = new System.Windows.Forms.TextBox();
this.txtImageLocation = new System.Windows.Forms.TextBox();
this.label1 = new System.Windows.Forms.Label();
this.label2 = new System.Windows.Forms.Label();
this.label3 = new System.Windows.Forms.Label();
this.txtLDAPString = new System.Windows.Forms.TextBox();
this.button2 = new System.Windows.Forms.Button();
this.ofd = new System.Windows.Forms.OpenFileDialog();
this.panel1 = new System.Windows.Forms.Panel();
this.label5 = new System.Windows.Forms.Label();
this.txtDomainController = new System.Windows.Forms.TextBox();
this.SuspendLayout();
//
// button1
//
this.button1.Location = new System.Drawing.Point(423, 194);
this.button1.Name = "button1";
this.button1.Size = new System.Drawing.Size(75, 23);
this.button1.TabIndex = 0;
this.button1.Text = "Save!";
this.button1.UseVisualStyleBackColor = true;
this.button1.Click += new System.EventHandler(this.button1_Click);
//
// textBox1
//
this.txtUserName.Location = new System.Drawing.Point(35, 73);
this.txtUserName.Name = "textBox1";
this.txtUserName.Size = new System.Drawing.Size(100, 20);
this.txtUserName.TabIndex = 1;
this.txtUserName.Text = "Paul Adams";
//
// textBox2
//
this.txtImageLocation.Location = new System.Drawing.Point(35, 167);
this.txtImageLocation.Name = "textBox2";
this.txtImageLocation.ReadOnly = true;
this.txtImageLocation.Size = new System.Drawing.Size(229, 20);
this.txtImageLocation.TabIndex = 2;
this.txtImageLocation.Text = "pick a jpg";
//
// label1
//
this.label1.AutoSize = true;
this.label1.Location = new System.Drawing.Point(21, 57);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(272, 13);
this.label1.TabIndex = 3;
this.label1.Text = "Users Name as it appears in active directory (and LDAP)";
//
// label2
//
this.label2.AutoSize = true;
this.label2.Location = new System.Drawing.Point(21, 149);
this.label2.Name = "label2";
this.label2.Size = new System.Drawing.Size(164, 13);
this.label2.TabIndex = 4;
this.label2.Text = "Location of Image (300x300 max)";
//
// label3
//
this.label3.AutoSize = true;
this.label3.Location = new System.Drawing.Point(21, 9);
this.label3.Name = "label3";
this.label3.Size = new System.Drawing.Size(156, 13);
this.label3.TabIndex = 6;
this.label3.Text = "LDAP Location of user account";
//
// textBox3
//
this.txtLDAPString.Location = new System.Drawing.Point(35, 25);
this.txtLDAPString.Name = "textBox3";
this.txtLDAPString.Size = new System.Drawing.Size(264, 20);
this.txtLDAPString.TabIndex = 5;
this.txtLDAPString.Text = "ou=users,ou=corporate,dc=corp,dc=ad";
//
// button2
//
this.button2.Location = new System.Drawing.Point(268, 165);
this.button2.Name = "button2";
this.button2.Size = new System.Drawing.Size(28, 23);
this.button2.TabIndex = 9;
this.button2.Text = "...";
this.button2.UseVisualStyleBackColor = true;
this.button2.Click += new System.EventHandler(this.button2_Click);
//
// ofd
//
this.ofd.DefaultExt = "jpg";
this.ofd.FileName = "Picture.jpg";
this.ofd.InitialDirectory = "c:\\";
//
// panel1
//
this.panel1.BackColor = System.Drawing.Color.Silver;
this.panel1.Location = new System.Drawing.Point(323, 12);
this.panel1.Name = "panel1";
this.panel1.Size = new System.Drawing.Size(175, 175);
this.panel1.TabIndex = 10;
//
// label5
//
this.label5.AutoSize = true;
this.label5.Location = new System.Drawing.Point(21, 101);
this.label5.Name = "label5";
this.label5.Size = new System.Drawing.Size(130, 13);
this.label5.TabIndex = 12;
this.label5.Text = "Random domain controller";
//
// textBox4
//
this.txtDomainController.Location = new System.Drawing.Point(35, 117);
this.txtDomainController.Name = "textBox4";
this.txtDomainController.Size = new System.Drawing.Size(100, 20);
this.txtDomainController.TabIndex = 11;
this.txtDomainController.Text = "DC03";
//
// Form1
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(509, 226);
this.Controls.Add(this.label5);
this.Controls.Add(this.txtDomainController);
this.Controls.Add(this.panel1);
this.Controls.Add(this.button2);
this.Controls.Add(this.label3);
this.Controls.Add(this.txtLDAPString);
this.Controls.Add(this.label2);
this.Controls.Add(this.label1);
this.Controls.Add(this.txtImageLocation);
this.Controls.Add(this.txtUserName);
this.Controls.Add(this.button1);
this.Name = "Form1";
this.Text = "Picture-ater Gizmo";
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.Button button1;
private System.Windows.Forms.TextBox txtUserName;
private System.Windows.Forms.TextBox txtImageLocation;
private System.Windows.Forms.Label label1;
private System.Windows.Forms.Label label2;
private System.Windows.Forms.Label label3;
private System.Windows.Forms.TextBox txtLDAPString;
private System.Windows.Forms.Button button2;
private System.Windows.Forms.OpenFileDialog ofd;
private System.Windows.Forms.Panel panel1;
private System.Windows.Forms.Label label5;
private System.Windows.Forms.TextBox txtDomainController;
}
}
{
partial class Form1
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.button1 = new System.Windows.Forms.Button();
this.txtUserName = new System.Windows.Forms.TextBox();
this.txtImageLocation = new System.Windows.Forms.TextBox();
this.label1 = new System.Windows.Forms.Label();
this.label2 = new System.Windows.Forms.Label();
this.label3 = new System.Windows.Forms.Label();
this.txtLDAPString = new System.Windows.Forms.TextBox();
this.button2 = new System.Windows.Forms.Button();
this.ofd = new System.Windows.Forms.OpenFileDialog();
this.panel1 = new System.Windows.Forms.Panel();
this.label5 = new System.Windows.Forms.Label();
this.txtDomainController = new System.Windows.Forms.TextBox();
this.SuspendLayout();
//
// button1
//
this.button1.Location = new System.Drawing.Point(423, 194);
this.button1.Name = "button1";
this.button1.Size = new System.Drawing.Size(75, 23);
this.button1.TabIndex = 0;
this.button1.Text = "Save!";
this.button1.UseVisualStyleBackColor = true;
this.button1.Click += new System.EventHandler(this.button1_Click);
//
// textBox1
//
this.txtUserName.Location = new System.Drawing.Point(35, 73);
this.txtUserName.Name = "textBox1";
this.txtUserName.Size = new System.Drawing.Size(100, 20);
this.txtUserName.TabIndex = 1;
this.txtUserName.Text = "Paul Adams";
//
// textBox2
//
this.txtImageLocation.Location = new System.Drawing.Point(35, 167);
this.txtImageLocation.Name = "textBox2";
this.txtImageLocation.ReadOnly = true;
this.txtImageLocation.Size = new System.Drawing.Size(229, 20);
this.txtImageLocation.TabIndex = 2;
this.txtImageLocation.Text = "pick a jpg";
//
// label1
//
this.label1.AutoSize = true;
this.label1.Location = new System.Drawing.Point(21, 57);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(272, 13);
this.label1.TabIndex = 3;
this.label1.Text = "Users Name as it appears in active directory (and LDAP)";
//
// label2
//
this.label2.AutoSize = true;
this.label2.Location = new System.Drawing.Point(21, 149);
this.label2.Name = "label2";
this.label2.Size = new System.Drawing.Size(164, 13);
this.label2.TabIndex = 4;
this.label2.Text = "Location of Image (300x300 max)";
//
// label3
//
this.label3.AutoSize = true;
this.label3.Location = new System.Drawing.Point(21, 9);
this.label3.Name = "label3";
this.label3.Size = new System.Drawing.Size(156, 13);
this.label3.TabIndex = 6;
this.label3.Text = "LDAP Location of user account";
//
// textBox3
//
this.txtLDAPString.Location = new System.Drawing.Point(35, 25);
this.txtLDAPString.Name = "textBox3";
this.txtLDAPString.Size = new System.Drawing.Size(264, 20);
this.txtLDAPString.TabIndex = 5;
this.txtLDAPString.Text = "ou=users,ou=corporate,dc=corp,dc=ad";
//
// button2
//
this.button2.Location = new System.Drawing.Point(268, 165);
this.button2.Name = "button2";
this.button2.Size = new System.Drawing.Size(28, 23);
this.button2.TabIndex = 9;
this.button2.Text = "...";
this.button2.UseVisualStyleBackColor = true;
this.button2.Click += new System.EventHandler(this.button2_Click);
//
// ofd
//
this.ofd.DefaultExt = "jpg";
this.ofd.FileName = "Picture.jpg";
this.ofd.InitialDirectory = "c:\\";
//
// panel1
//
this.panel1.BackColor = System.Drawing.Color.Silver;
this.panel1.Location = new System.Drawing.Point(323, 12);
this.panel1.Name = "panel1";
this.panel1.Size = new System.Drawing.Size(175, 175);
this.panel1.TabIndex = 10;
//
// label5
//
this.label5.AutoSize = true;
this.label5.Location = new System.Drawing.Point(21, 101);
this.label5.Name = "label5";
this.label5.Size = new System.Drawing.Size(130, 13);
this.label5.TabIndex = 12;
this.label5.Text = "Random domain controller";
//
// textBox4
//
this.txtDomainController.Location = new System.Drawing.Point(35, 117);
this.txtDomainController.Name = "textBox4";
this.txtDomainController.Size = new System.Drawing.Size(100, 20);
this.txtDomainController.TabIndex = 11;
this.txtDomainController.Text = "DC03";
//
// Form1
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(509, 226);
this.Controls.Add(this.label5);
this.Controls.Add(this.txtDomainController);
this.Controls.Add(this.panel1);
this.Controls.Add(this.button2);
this.Controls.Add(this.label3);
this.Controls.Add(this.txtLDAPString);
this.Controls.Add(this.label2);
this.Controls.Add(this.label1);
this.Controls.Add(this.txtImageLocation);
this.Controls.Add(this.txtUserName);
this.Controls.Add(this.button1);
this.Name = "Form1";
this.Text = "Picture-ater Gizmo";
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.Button button1;
private System.Windows.Forms.TextBox txtUserName;
private System.Windows.Forms.TextBox txtImageLocation;
private System.Windows.Forms.Label label1;
private System.Windows.Forms.Label label2;
private System.Windows.Forms.Label label3;
private System.Windows.Forms.TextBox txtLDAPString;
private System.Windows.Forms.Button button2;
private System.Windows.Forms.OpenFileDialog ofd;
private System.Windows.Forms.Panel panel1;
private System.Windows.Forms.Label label5;
private System.Windows.Forms.TextBox txtDomainController;
}
}
email me if you need a working .exe that you can use to accomplish this without powershell or CLI commands. padams at sourcedirect dot com