LDIF – Directory Import and Export using LDIFDE.EXE and LDAPMODIFY
You can obtain ldifde.exe from any existing domain controller – copy \\dcname\c$\winnt\system32\ldifde.exe to your SYSTEM32 folder. The ldapmodify command is part of the openldap-clients package on Linux. Windows builds of the openldap clients are available. The data being imported is essentially the same, just the command line to invoke the program differs.
Using LDIF files to update LDAP data is facilitated if you know the directory schema attributes, especially those associated to the user object class. Active Directory schema is well documented on MSDN – base Active Directory schema can be found at http://msdn.microsoft.com/library/default.asp?url=/library/en-us/adschema/adschema/active_directory_schema_site.asp and the extensions made by Exchange are documented at http://msdn.microsoft.com/library/default.asp?url=/library/en-us/wss/wss/wss_ldf_AD_Schema_intro.asp
LDIFDE is a command line program which runs with currently logged on user’s credentials – this means that your ID can write changes to AD using LDIFDE. Please do not play with this program in the production Active Directory domain but rather test writing to a test domain.
LDIF Export
Exporting directory information is fairly straight forward:
ldifde –f filename.txt –d “ou=base,DC=windstream,DC=com” –p subtree –r “(&(attribute=value)(otherattribute=othervalue))” –s domaincontroller.windstream.com –l “attribute1, attribute2, attribute3 …”
-f | File to contain exported data |
-d | Search base |
-p | Search scope |
-r | RFC-2254 compliant filter |
-s | Domain controller from which to obtain data |
-l | Attributes to be returned (eliding this command will return values for all attributes) |
This will create a file named ljlexport.txt of all e####### users with email addresses whose accounts are located under WINDSTREAM.COM\WINDSTREAM\IT. The file will contain, for each user, their logon ID (sAMAccountName), email address (mail), account status (userAccountControl), display name, and telephone number.
ldifde –f ljlexport.txt –d “ou=IT,ou=windstream,DC=windstream,DC=com” –r “(&(sAMAccountName=e*)(mail=*))” –s neohtwnnt836.windstream.com –l “sAMAccountName, mail, userAccountControl, displayName, telephoneNumber”
-r specifies the search filter and can become a rather complex query depending on what you are looking for — & is an AND filter, | is an OR filter. ! can be used to find unmatched values and * works as a wildcard
“(&(mail=*)(!sAMAccountName=n99*))” find all mail enabled accounts which are not N99’s for instance.
“(&(sAMAccountName=e0*)(!(employeeID=*)))” Find all employee accounts with no employee ID specified
“(&(mail=*)(|(sAMAccountName=n99*)(sAMAccountName=g99*)))” mail enabled accounts which are either n99’s or g99’s
“(&(objectClass=user)(objectCategory=person))” Real user accounts, objectClass=user alone will return a lot of things you don’t believe are users J
“(&(objectClass=user)(objectCategory=person)(telephoneNumber=813*))” Real user accounts with phone numbers in the 813 area code
“(&(objectClass=user)(objectCategory=person)(msExchHomeServerName=*SCARLITNT841))” Real user with mailboxes on SCARLITNT841
-d specifies the search base (subtree search by default) – you can use “DC=windstream,DC=com” to get the entire directory or something like “ou=Central,ou=windstream,DC=windstream,DC=com” to just get users within the Central OU.
LDIF Import
Importing Directory Information is not so straight forward and again do not play with this program in the production Active Directory domain. You need to create an ldif import file to make changes to objects. A sample file content:
dn: cn=Landers\, Lisa,ou=GPOTest,ou=IT,ou=windstream,dc=windstreamtest,dc=com changetype: modify add: proxyAddresses proxyAddresses: smtp:lisa@newtestdomain.windstream.com - replace: telephoneNumber telephoneNumber: 501-905-4305 - delete: mobile mobile: 501-607-3750 - delete: facsimileTelephoneNumber - dn: cn=Ahrend\, Sam,ou=IT,ou=windstream,dc=windstreamtest,dc=com changetype: modify replace: mDBUseDefaults mDBUseDefaults: FALSE - replace: mDBStorageQuota mDBStorageQuota: 190000 - replace: mDBOverQuotaLimit mDBOverQuotaLimit: 200000 -
Provided you have an import file, the syntax of the command is ldifde –i –v –k –y –f filename.txt
-i | LDIFDE import operation |
-v | Produce verbose output |
-k | Ignore constraint violations (and entry exists errors on add) |
-y | Lazy commit |
-f | File name to be imported |
Changetype Add
A changetype of add is used when the entire object does not currently exist – this ldap operation creates a new object with the attributes specified in the stanza.
dn: cn=TestingGroup 10001,ou=testing,ou=it,DC=windstream,DC=com changetype: add cn: TestingGroup 10001 distinguishedName: cn= TestingGroup 10001,ou=testing,ou=it,DC=windstream,DC=com name: TestingGroup10001 sAMAccountName: TestingGroup10001 objectClass: group objectCategory: CN=Group,CN=Schema,CN=Configuration,DC=windstream,DC=com groupType: -2147483646 managedBy: cn=Landers\, Lisa,OU=GPOTest,ou=IT,OU=WINDSTREAM,DC=windstream,DC=com member: cn=Landers\, Lisa,OU=GPOTest,ou=IT,OU=WINDSTREAM,DC=windstream,DC=com member: cn=Ahrend\, Sam, ou=IT,OU=WINDSTREAM,DC=windstream,DC=com legacyExchangeDN: /o=WINDSTREAMEXCH/ou=First Administrative Group/cn=Recipients/cn=TestingGroup10001 mailNickname: TestingGroup10001 reportToOriginator: TRUE
This example will create an e-mail enabled global security group named “TestingGroup 10001” under windstream.com – it – testing. Both Sam and I will be listed as members of the group and I will be listed as the group owner. Add operations can be chained together with just a blank line between them should you need to add multiple objects in batch.
Any mandatory attributes for the schema classes need to be included (handled by ldifde works too) or the add operation will fail. Attributes not valid for the object classes will cause the operation to fail as well. If an object already exists, no change will be made even if some of the attributes specified differ from the values within AD.
Changetype Delete
Delete is used to delete the entire object – so be extra careful here. The syntax is quite simple – the DN of the object to be removed and a line that says “changetype: delete”. Again, multiple operations can be chained together with just a blank line.
dn: cn=TestingGroup 10002,ou=testing,ou=it,DC=windstream,DC=com changetype: delete dn: cn=TestingGroup 10003,ou=testing,ou=it,DC=windstream,DC=com changetype: delete dn: cn=TestingGroup 10004,ou=testing,ou=it,DC=windstream,DC=com changetype: delete dn: cn=TestingGroup 10005,ou=testing,ou=it,DC=windstream,DC=com changetype: delete
Changetype Modify
Modify is used to change attributes on an existing object. Modify can be used to add, replace, or delete an attribute. The example above has two different stanza’s (separated by a blank line). Within each stanza several operations are made:
First to add another email address to the secondary email addresses. For a multi-value attribute (member, proxyAddresses …) changetype: modify\nadd: attribute adds another value to the attribute. For single-valued attributes modify/add will fail if a value is present.
dn: cn=Landers\, Lisa,ou=GPOTest,ou=IT,ou=windstream,DC=windstream,DC=com changetype: modify add: proxyAddresses proxyAddresses: smtp:lisa@newtestdomain.windstream.com -
The next operation replaces the telephone number with the value specified – this will overwrite the existing value. Be careful not to replace multi-value attributes
replace: telephoneNumber telephoneNumber: 501-905-4305 -
The next operation deletes the mobile phone number with the value specified – if the value does not match, a change is not made. This can be used as a failsafe, in this case only delete my mobile telephone number if the value is what I expect it to be, or to remove entries from multi-value attributes. Delete the member of the group which is the specific member listed without changing the other group members, for instance.
delete: mobile mobile: 501-607-3750 -
The next operation deletes the fax number – regardless of content the value is removed.
delete: facsimileTelephoneNumber -
A blank line separates the two stanzas and a new object is specified. Again the modify/replace option is used which will change the attributes to the values specified.
dn: cn=Ahrend\, Sam,ou=IT,ou=windstream,DC=windstream,DC=com changetype: modify replace: mDBUseDefaults mDBUseDefaults: FALSE - replace: mDBStorageQuota mDBStorageQuota: 190000 - replace: mDBOverQuotaLimit mDBOverQuotaLimit: 200000 - dn: cn=Landers\, Lisa,ou=IT,ou=windstream,DC=windstream,DC=com changetype: modify replace: mDBUseDefaults mDBUseDefaults: TRUE -
Changetype ModDN
ModDN changes the object’s distinguishedName. This is interesting as it can be used to move users – this example would move my account into the Central OU under ACI
dn: CN=Landers\, Lisa,OU=GPOTest,OU=IT,OU=WINDSTREAM,,DC=windstream,DC=com changetype: moddn newrdn: CN= Landers \, Lisa,OU=Central,OU=WINDSTREAM,DC=windstream,DC=com deleteoldrdn: 1
ModDN can also be used to rename the object’s display in administrative listings:
dn: CN=Landers\, Lisa,OU=GPOTest,OU=IT,OU=WINDSTREAM,,DC=windstream,DC=com changetype: moddn newrdn: CN= Landers\, Jane, OU=GPOTest,OU=IT,OU=WINDSTREAM,,DC=windstream,DC=com deleteoldrdn: 1
You would of course want to modify/replace at least givenName and displayName on the object dn to avoid confusion – otherwise my middle name would appear in active directory users and computers but my first name in Outlook. I would modify the attributes first – if you modify the DN first, you need to remember to use the new DN for subsequent attribute value changes.
dn: CN=Landers\, Lisa,OU=GPOTest,OU=IT,OU=WINDSTREAM,,DC=windstream,DC=com changetype: modify replace: givenName givenName: Jane - replace: displayName displayName: Landers, Jane - dn: CN=Landers\, Lisa,OU=GPOTest,OU=IT,OU=WINDSTREAM,,DC=windstream,DC=com changetype: moddn newrdn: CN= Landers\, Jane, OU=GPOTest,OU=IT,OU=WINDSTREAM,,DC=windstream,DC=com deleteoldrdn: 1 -