Upload picture in Outlook 2010 using the Exchange Management Shell (Exchange 2010)
While prepping for one of my sessions @ TechEd Berlin on managing and administering Exchange 2010, I was looking for a demo to illustrate the changes introduced with Remote Powershell when importing and exporting files. That's when I stumbled into the Exchange Management Shell cmdlet Import-RecipientDataProperty, which is described in the following TechNet article: Import-RecipientDataProperty.
So here are the steps to get a picture uploaded into Active Directory, in this example my user Ilse doesn't have a picture yet
Step 1. Get a picture
You need a JPEG file, limited in size to 10 kilobytes!
Step 2. Run the Exchange Management Shell cmdlet Import-RecipientDataProperty
Run the Exchange Management Shell cmdlet to upload the picture. Running it will populate Active Directory with the picture, more specifically the attribute called thumbnailPhoto will be populated. Make sure this attribute is replicated to the Global Catalog (big thank you to Astrid for helping me out with this one :-)) .
Before running the cmdlet, the attribute doesn't have a value:
Check if the attribute is replicated to the Global Catalog, by using for example the Schema Snap-In:
Run the following cmdlet:
Few remarks:
- there is no need to refer to a UNC path, you can locate the file anywhere
- remember the limit of 10KB!!
After running this, Active Directory will be populated:
And after restarting Outlook, the picture will be there :-)
-Ilse
Follow-up: If you want to know if this will work with Exchange 2003-Exchange 2007, click this link:
http://blogs.technet.com/ilvancri/archive/2010/01/08/follow-up-import-recipientdataproperty.aspx
Comments
Anonymous
January 01, 2003
The comment has been removedAnonymous
January 01, 2003
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.Anonymous
January 01, 2003
Hi, where should I start trouble shooting if the thumbnailPhoto attribute is populated and I can export the users photo using powershell but no contact photos are showing in Outlook? ThanksAnonymous
January 01, 2003
Where are the pictures physically stored? In AD, in the db somewhere or in the user's mailbox on the Exchange server?Anonymous
January 01, 2003
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-2010Anonymous
January 01, 2003
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 SchemaAnonymous
January 01, 2003
@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 prepAnonymous
January 01, 2003
Information is stored in active directory database -IlseAnonymous
November 12, 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-toolAnonymous
November 17, 2010
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.Anonymous
November 18, 2010
hi, if we implement Outlook 2010 contact picture adding on Exch 2003, does anyone know what attribute in AD will the pics be stored?Anonymous
November 24, 2010
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 YavuzAnonymous
November 25, 2010
The comment has been removedAnonymous
November 25, 2010
Abbas, it still uses the same AD attribute - thumbnailPhotoAnonymous
January 07, 2011
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 th
Anonymous
January 07, 2011
email me if you need a working .exe that you can use to accomplish this without powershell or CLI commands. padams at sourcedirect dot comAnonymous
January 12, 2011
I work with Windows 2003, I see that It is necessary register schmmgmt.dll but I don't find the dll, somebody can help me?Anonymous
March 31, 2011
We have a free product available from our website that makes this very easy. www.exclaimer.com/.../Default.aspxAnonymous
July 07, 2011
Exclaimer's Outlook Photo tool is AWESOME! It is a GUI and automatically links up the pictures to the users if the filenames are the same as the usernames! Great!Anonymous
November 21, 2011
You can also use this free tool for importing and managing users' Active Directory photos. As shown in this vid: www.youtube.com/watchAnonymous
January 11, 2012
try this free tool, very easy top use, auto image editing and you can import pictures based on different conditions. www.codetwo.com/.../active-directory-photosAnonymous
June 27, 2014
if you already have a 20GB of ntds.dit and adding the photo of arround 2GB. Does it really going to create replication issues from there onwards? Also, if you push nearly 1.5Lakh employees together how about the data write/read going to effect the AD? Does it get stored in lync/outlook cache so that it doesnt require to read every time from AD. Really concerned about the ad replication once the db size is more than 21GB. Any suggesion on implimenting the changes on ad which has huge DB size already...Anonymous
December 03, 2015
The comment has been removed