Import user photo from LDAP into S-N (reloaded)
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
‎07-15-2013 01:16 PM
Dear Community,
my company is now changing to Service-Now and I'm currently working on adapting it to our needs. I worked the entire day long on the import of the LDAP user photo into S-N and I really got to thank john.roberts who first published in 2009 the base-script for what I need, see this topic: Importing user picture from LDAP into S-N.
Unfortunately his script is out-of-date as calling packages directly is now prohibited with the Calgary release and also his script is not able to update existing photos in S-N. So I accepted the challenge and modified his script.
It's already working and I want to share it with you in a minute, but maybe you guys can help me on a few questions as I'm new to S-N and JavaScript (previously I was more working on MS.NET).
1. Only import JPEG pictures into your LDAP, else you need to modify the script (to be honest I don't know if LDAP supports other formats)
2. Make sure to add the value "thumbnailphoto" to the system property "glide.ldap.binary_attributes". This system property should already exist on the sys_properties.list, otherwise add it manually by following the instructions that can be found on the S-N wiki.
Note: john.roberts script was aiming for the "jpegphoto", you can also use such attribute but you need to change the previous mentioned system property and also the following script accordingly (simply replace each thumbnailphoto with jpegphoto).
3. Make sure to set the system property "com.glide.loader.verify_target_field_size" to true. By default it's false. Otherwise follow the instructions given on john.roberts script.
Go to your "LDAP user import" transform map and add a new onAfter transform script.
Sorry, I'm horrible in giving proper comments on scripts. Please refer to john.roberts base-script or simply ask me if you have a question.
//add user image from ldap thumbnailphoto attribute and keep records in SN up-to-date
//**first check and get the existing photo of the SN-record
//this is vital if we want to update the photo when it has been changed in LDAP
//however the more users there are and the bigger the stored pictures are, it might slowdown the import process
//It can be simplified but then SN-pictures will not be removed automatically when the picture has been removed in LDAP
var existingPhoto = new GlideRecord('sys_attachment');
existingPhoto.addQuery('table_name','ZZ_YYsys_user');
existingPhoto.addQuery('table_sys_id',target.sys_id);
existingPhoto.addQuery('file_name','photo');
existingPhoto.query();
//**check if there is a picture on LDAP
if (source.u_thumbnailphoto != '') {
//**if there is no picture for the record in SN
if (!existingPhoto.next()) {
//**launch the function to attach the picture
attachPhoto();
}
//**if there is a picture for the record in SN
else {
var sysEncodedAttachment = new GlideSysAttachment();
var binData = sysEncodedAttachment.getBytes(existingPhoto);
var EncodedBytes = GlideStringUtil.base64Encode(binData);
//**verify if the current existing SN-picture for the record does not match the current LDAP picture
//if it does not match, delete the current SN-picture and launch the funtion to attach the new picture
if (EncodedBytes != source.u_thumbnailphoto) {
existingPhoto.deleteRecord();
attachPhoto();
}
}
}
//**if there is no picture on LDAP
else {
//**check if there is one on the SN-record and delete it
if (existingPhoto.next()) {
existingPhoto.deleteRecord();
}
}
//function to attach a new photo from the LDAP to the SN-record
function attachPhoto(){
var sysDecodedAttachment = new GlideSysAttachment();
var DecodedBytes = GlideStringUtil.base64DecodeAsBytes(source.u_thumbnailphoto);
var attID = sysDecodedAttachment.write(target, 'photo', 'image/jpeg', DecodedBytes);
var newAttachment = new GlideRecord("sys_attachment");
newAttachment.addQuery("sys_id", attID);
newAttachment.query();
if (newAttachment.next()) {
newAttachment.table_name = "ZZ_YYsys_user";
newAttachment.table_sys_id = target.sys_id;
newAttachment.content_type = 'image/jpeg';
newAttachment.update();
}
}
So... as you can see in order to be able to delete the photo on S-N if it has been removed in LDAP, I need to load the entire S-N image-data for each user-record there is. Meaning the more users you have and the bigger the stored pictures are, the longer it will take to verify and import. If you guys have an idea how to optimise this, I'd be grateful! Otherwise we can simplify the script, but then the photo on S-N will not be removed if it has been removed in LDAP, however it will still be able to update changes.
As john.roberts also suggested, you can afterwards test the script only on a specific user by adding to the LDAP filter (sAMAccountName=DesiredUsername*)
P.S.: Unfortunately S-N has not yet the possibility to directly import the LDAP photo, this is the only possibility we have
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
‎09-21-2015 12:33 AM
An update:
I have now verified that I get valid binary data into thumbnailPhoto in the import set. I copy pasted the binary and decoded it in a webapplication i found online and got the photo out of the data.
So to me it seems like OPs script doesn't decode the data although from the looks of it, the script does decode the data.
I also tried changing the import set attribute thumbnailPhoto to image-type instead of string-type but it didn't change anything.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
‎11-09-2015 01:53 AM
I have no idea how but I managed to make it work. Like mentioned before I use a MID-server to connect to LDAP. Apart from that everything else is baseline.
This is what I've done
- Add the glide.ldap.binary_attributes attribute to MID-server attributes (ecc_agent_property.list)
Name : glide.ldap.binary_attributes
Value : thumbnailPhoto
MID-server : <your midserver>
This might need to be added manually on versions before Fuji. (add the property to ../agent/properties/glide.properties) - Restart MID-servers to make them download the property from the servicenow instance.
- Do a test-import of the users to create all columns for the import set table.
- Extend the character limitation for the thumbnailPhoto column on the import set table to many characters (i went for 65 536, but a lower amount should suffice).
- Extend the character limitation for the photo column on the sys_user table to the same amount of characters.
- Add this onAfter-script to the transform map:
// Get record of existing photos
var photoExists_glide = new GlideRecord('sys_attachment');
photoExists_glide.addQuery('table_name', 'ZZ_YYsys_user');
photoExists_glide.addQuery('table_sys_id', target.sys_id);
photoExists_glide.addQuery('file_name', 'photo');
photoExists_glide.query();
// Check if photo has been gathered from AD
if (source.u_thumbnailphoto != '') {
// Look if there is a photo in SNow
if (!photoExists_glide.next()) {
attachPhoto();
// See if pictures from AD and SNow matches
} else {
var sysEncodedAttachment = new GlideSysAttachment();
var binData = sysEncodedAttachment.getBytes(existingPhoto);
var EncodedBytes = GlideStringUtil.base64Encode(binData);
// Check to see if pictures match
if (EncodedBytes != source.u_thumbnailphoto) {
gs.print("Outdated photo exists. Removed photo for user: " + source.u_samaccountname);
// Remove the outdated SNow photo
photoExists_glide.deleteRecord();
// Attach new photo from AD
attachPhoto();
}
}
// If no photo was gathered from AD
} else {
// Check to see if there is a photo in SNow
if (photoExists_glide.next()) {
gs.print("Photo missing in AD. Photo in ServiceNow left alone.");
}
}
// Main function that attaches photo to user record.
function attachPhoto() {
var sysDecodedAttachment = new GlideSysAttachment();
// Decode the pictures base64-string
var DecodedBytes = GlideStringUtil.base64DecodeAsBytes(source.u_thumbnailphoto);
var attID = sysDecodedAttachment.write(target, 'photo', 'image/jpeg', DecodedBytes);
var newAttachment_glide = new GlideRecord("sys_attachment");
newAttachment_glide.addQuery('sys_id', attID);
newAttachment_glide.query();
// Attach the picture to sys_attachment record
if (newAttachment_glide.next()) {
newAttachment_glide.table_name = 'ZZ_YYsys_user';
newAttachment_glide.table_sys_id = target.sys_id;
newAttachment_glide.content_type = 'image/jpeg';
newAttachment_glide.update();
}
}
The script is virtually the same as the one in OP (Atleast I don't see any differences) but I rewrote it to fit our corporation.
- Run the full import as well as transform and you should get the photos.
I'm fairly sure that's all I did.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
‎06-28-2018 06:36 AM
It worked for me after i restart the mid server, thank for the tip.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
‎05-11-2016 12:45 PM
We had this working for a long time, then it suddenly stopped working from January this year. We hadn't made any changes to the script or any of the properties, so we didn't know what had caused it to stop working - but we did notice that it coincided with a ServiceNow patch release (Fuji Patch 9 Hotfix 1). After a lot of experimentation (and raising a ticket on /HI) we found that the write method of the GlideSysAttachment API was not creating attachments if the filename parameter did not have an extension. We changed the script to make the filename "photo.jpg" instead of "photo" - the attachment record was created OK, but unfortunately the picture was not visible on the User form.
We tried it on a new Geneva instance, and it worked fine - then we realised that the system property glide.attachment.extensions on the Geneva instance was blank, whereas the property on the Fuji instance contained a list of extensions. We cleared the property on the Fuji instance, and it worked OK, so we knew the issue was with the lack of an extension on the filename. We reset the property value back to the list of extensions, but added a comma at the start of the value to see if that would be taken as meaning that a blank extension was valid - and it worked!
So, if you have defined a list of valid extensions in the glide.attachment.extensions system parameter, and your photo import has stopped working, try adding a comma at the start - for example, if the property is currently "jpg,png,doc" try setting it to ",jpg,png,doc".
We still think the issue was caused by something in the patch upgrade, but we can't be certain.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
‎05-11-2016 11:46 PM
Interesting. We upgraded to geneva at it's release in December and we haven't encountered this issue at all.