Change photo on AD user account from Linux shell

You need a photo, with a suitable small size, probably 100×100 or smaller. I heard a size limit, 10KB, but my reference photo was 2KB.

Install openldap-clients, or the appropriate package to get ldapmodify command.

You will need the reference photo, which I will call input.jpg.

$ file input.jpg
input.jpg: JPEG image data, JFIF standard 1.01

Convert it with base64 with no wrapping.

$ base64 -w0 < input.jpg > photo.ldif

And now, add the ldif commands to the photo.ldif file:

dn: CN=Example user,OU=Users,DC=example,DC=com
changetype: modify
add: thumbnailPhoto

Observe that there is a blank line after the attribute being modified.

If you’re using kerberos auth, make sure you have a ticket with kinit $LDAPUSER. Run the ldapmodif command!

ldapmodify -v -f photo.ldif -H ldaps:// -O maxssf=0 -Y gssapi

To use simple binding, you would want a command more like this:

ldapmodify -v -f photo.ldif -H ldaps:// -O maxssf=0 -x -W -D 'CN=Example user,OU=Users,DC=example,DC=com'

This works because in Active Directory a user has the permissions (NTACLs) to update certain attributes for himself.


Original research
Refresher on ldif syntax:

ldapsearch find disabled users in Active Directory

If you want to find the disabled users in your AD environment, you can use a specific filter. Additionally, due to the number of records returned, I had to turn on paging (pr = some arbitrarily high value) so I could actually retrieve more than just the first 1000 entries.

echo '' | ldapsearch -E 'pr=4500' -z max -b 'dc=prod1,dc=example,dc=com' -s 'sub' -x -D 'CN=B Stack15,OU=Users,DC=prod1,DC=example,DC=com' -W -H 'ldaps://' '(&(objectCategory=person)(objectClass=user)(userAccountControl:1.2.840.113556.1.4.803:=2))' dn

The userAccountControl item in the search filter stores various useful information. The := operator is a bitmask.



  2. Found from web search string “userAccountControl:1.2.840.113556.1.4.803”

Get SID from Linux ldapsearch in Active Directory

With the help of a fantastic post on ServerFault, here is a way to find a user’s SID in string format from an ldapsearch against Active Directory.

# Filename:
# Author: YasithaB
# Startdate: 2018-02-14 15:58
# Title: Script that Converts Sid from AD Ldap Hexadecimal into String
# Purpose: Help convert sid to usable value
# History:
#    2018-02-15 Modified to work with kornshell
# Usage:
#    ldapsearch -b 'dc=prod,dc=example,dc=com' -s 'sub' -x -D 'CN=My Username,OU=Domain Users,DC=prod,DC=example,DC=com' -W -H 'ldaps://' '(cn=Target Username)' objectSid | grep -E '^objectSid:' | awk '{print $2}' | ./ --stdin
# Reference:
# Improve:
# Document: Below this line

# Base-64 encoded objectSid
case "${1}" in
   "--stdin" ) read OBJECT_ID ;;
   "") : ;;
   *) OBJECT_ID="${1}" ;;

# Decode it, hex-dump it and store it in an array
H="$(echo -n $OBJECT_ID | base64 -d -i | hexdump -v -e '1/1 "%02X"')"

# SID Structure:
# LESA = Little Endian Sub Authority
# BESA = Big Endian Sub Authority
# LERID = Little Endian Relative ID
# BERID = Big Endian Relative ID



echo "${SID}"

Ldapsearch notes

This post will be updated over time.

List all members of an AD group, including following the nested group membership

ldapsearch -b 'dc=dc=example,dc=com' -s 'sub' -x -D 'CN=B Stack,OU=Domain Users,DC=example,DC=com' -W -H 'ldaps://' '(&(objectClass=user)(memberof:1.2.840.113556.1.4.1941:=CN=complex_sample_group,OU=Linux,OU=Security Groups,DC=example,DC=com))' samaccountname | awk '/^samaccountname/{print $2;}'

AD via ldap – how can I return all ancestor groups from a query []

List all groups of an AD user, including nested groups

ldapsearch -LLL -O maxssf=0 -o ldif-wrap=300 '(&(objectCategory=group)(member:1.2.840.113556.1.4.1941:=CN=John Doe,OU=Domain Users,DC=ad,DC=example,DC=com))' dn /dev/null | sed -r -e 's/^\s*#.*//g;' -e '/^\s*$/d;'

Source: Active Directory: LDAP Syntax Filters []

Multiple servers
If your ldaps servers do not use correct SANs on their certs and therefore do not present a certificate that matches the name used to connect, just provide multiple URIs in ldap.conf.

URI     ldaps:// ldaps:// ldaps:// ldaps:// ldaps://

Use host kerberos auth and work with AD

ldapsearch -LLL -O maxssf=0 -o ldif-wrap=300 '(cn=User Name)' memberOf 2>/dev/null | sed -r -e 's/^\s*#.*//g;' -e '/^\s*$/d;'

The maxsff is needed because AD does not use a proper security setting apparently, and the ldif-wrap just fixes the output.
Source: Can’t query AD using kerberos from linux host []

Overcoming the ADLDS MaxValRange Hard Limit


Microsoft Active Directory Lightweight Directory Services (AD LDS), formerly known as Active Directory Application Mode (ADAM), is a directory server application. Some companies use it to store a stripped-down ldap directory of the full AD environment. Whether you need just certain OUs, or just certain attributes available, using ADLDS might solve your problem.
Lots of places online can show you how to use userProxy objects to allow ldap simple binds to the AD LDS instance. LDS, when using userProxy objects, takes the sAMAccountName, finds the object with that attribute, and passes its objectSid and the user-supplied password to the real AD for authentication. So you can accomplish a ldap simple bind. You can even configure ldaps! I have it down to a science now that I’ve done it several times.
But the point of the post today is to show you how to exceed the hard-coded limit for ADLDS in Windows Server 2008 or 2012/2012R2 on the number of multi-value attributes returned for a query.
So AD groups are directory objects of objectClass=group. Group membership is defined by the member attribute of a group. Incidentally, AD (and LDS) provide a derived attribute, “memberof,” on the user (or userProxy) objects that are members of that group. Some applications check either one, but since the memberof is calculated, it doesn’t really matter anyway.
So with a group of your entire userbase, say, “Wiki-Users_Grp,” you might have more than 5000 members.

Adjusting MaxValRange

You probably are already aware of the MaxValRange=5000 value for the attribute lDAPAdminLimits on
CN=Default Query Policy,CN=Query-Policies,CN=Directory Service,CN=Windows NT,CN=Services,CN=Configuration,CN=X
ADSI edit showing the navigation to MaxValRange
You can adjust it to whatever number you want. This attribute affects how many attributes will be returned on an object, such as how many members will be returned on the very large group.
ADSI Edit is the application to use to modify this. Make a connection to the configuration context, and navigate to the dn and you can modify its attributes.
If you have more members than the MaxValRange, you will get an attribute returned like this:
member;range=0-4999 (5000): CN=user1,OU=Users,DC=example,DC=com; CN=user2,OU=Users,DC=example,DC=com; [...]
The applications I’ve worked with don’t like that “member;range=” nomenclature. So you have to make the MaxValRange higher so it returns just “member:” for each member.
Well, apparently Windows Server 2008 introduced a hard limit on the number of returned attributes. The MaxValRange will not take effect any higher than 5000.

Changing the hard limit

Qasim Zaidi at TechNet demonstrated how to change the limit:
Use ADSI Edit (adsiedit.msc) and navigate to this DN:
CN=Directory Service,CN=Windows NT,CN=Services,CN=Configuration,CN=X
The attribute that should be modified is dSHeuristics. If the value is blank, enter this value:
Straight from the TechNet article:

If a value has already been set for this attribute, incorporate the existing settings into the new value. When you do this, note the following:
The tenth character from the left must be 1. Twentieth bit must be 2, and so on.
The eighteenth character from the left must be 1.
None of the other characters of the existing value should be changed. For instance, if the existing value is 0000002 then the new value should be 000000200100000001

ADSI Edit showing navigation to dSHeuristics attribute
To ensure this change takes effect, restart the LDS service.
Run an ldap search, and see if the result is what you want for a large group!



  1. Overriding default hard limit in Windows Server 2008
  2. MaxValRange official source
  3. MaxValRange original source from 2014 doc