Platform SDK: Active Directory, ADSI, and Directory Services

LDIF Scripts

LDIF stands for LDAP Data Interchange Format and is a standard as defined by the IETF LDAPEXT working group (http://www.ietf.org/html.charters/ldapext-charter.html) in the Internet Draft draft-good-ldap-ldif-02.txt. Windows 2000 includes a command-line utility, LDIFDE, to import directory objects using LDIF files and export directory objects as LDIF files. Although LDIFDE scripts don't support Unicode, schema administrators easily read the scripts. For Unicode or binary values, you must base64 encode the values. Base64 encoding is defined in RFC 2045, Section 6.8.

Note that an LDIF file must apply schema changes so that dependencies are accounted for (such as forward link attributes should be added before the corresponding back link attribute) and schema cache updates should be forced before adding classes that depend on attributes or classes added earlier in the LDIF script. See the example below.

Example

This example consists of the following:

  1. MYSCHEMAEXT.LDF is an LDIF script containing new attributes and classes. Note that this file is a modified version of the file generated from LGETATTCLS.VBS. Note that the My-Test-Attribute-DN-FL attribute was moved ahead of My-Test-Attribute-DN-BL because the back link (My-Test-Attribute-DN-BL) is dependent on the forward link (My-Test-Attribute-DN-FL). Also note that the schemaUpdateNow operational attribute is set in two places to trigger updates of the schema cache so that dependent attributes and classes will be available for adding the two classes in the script.
  2. LGETATTCLS.VBS is a VBScript file that generates the LDIF script used as the starting point for the MYSCHEMAEXT.LDF file. Note that the current schema path is replaced by CN=Schema,CN=Configuration,DC=myorg,DC=com. You can replace DC=myorg,DC=com to reflect whatever DN you want to publish in the LDIF script—just make sure that LSETATTCLS.VBS reflects the change in its sFromDN so that the correct DN is replaced when the LDIF script is applied. Also note that the script uses a prefix to find the classes and attributes—you should also define and use a prefix for all your classes and attributes (see Naming Attributes and Classes). In addition, the script outputs only the necessary attributes for the attributeSchema and classSchema objects to the LDIF file.
  3. LGETATTCLS.VBS is a VBScript file that uses the MYSCHEMAEXT.LDF script to add the new attributes and classes in the script. You must ensure that the schema master is writable before running the script.

MYSCHEMAEXT.LDF

dn: CN=My-Test-Attribute-CaseExactString,CN=Schema,CN=Configuration,DC=myorg,DC=com
changetype: add
adminDisplayName: My-Test-Attribute-CaseExactString
attributeID: 1.2.840.113556.1.4.7000.159.24.10.65
attributeSyntax: 2.5.5.3
cn: My-Test-Attribute-CaseExactString
description: 
 Test attribute of syntax CaseExactString used to show how to add a CaseExactSt
 ring attribute.
isMemberOfPartialAttributeSet: FALSE
isSingleValued: TRUE
lDAPDisplayName: myTestAttributeCaseExactString
distinguishedName: 
 CN=My-Test-Attribute-CaseExactString,CN=Schema,CN=Configuration,DC=myorg,DC=co
 m
objectCategory: CN=Attribute-Schema,CN=Schema,CN=Configuration,DC=myorg,DC=com
objectClass: attributeSchema
oMSyntax: 27
name: My-Test-Attribute-CaseExactString
schemaIDGUID:: 6ASznA3W0hGBpwDAT7mMGg==
searchFlags: 0
 
dn: CN=My-Test-Attribute-DN-FL,CN=Schema,CN=Configuration,DC=myorg,DC=com
changetype: add
adminDisplayName: My-Test-Attribute-DN-FL
attributeID: 1.2.840.113556.1.4.7000.159.24.10.614
attributeSyntax: 2.5.5.1
cn: My-Test-Attribute-DN-FL
description: 
 Test forward link attribute of syntax DN used to show how to add a forward link attribute. Back link is My-Test-Attribute-DN-BL.
isMemberOfPartialAttributeSet: FALSE
isSingleValued: TRUE
lDAPDisplayName: myTestAttributeDNFL
linkID: 146
distinguishedName: 
 CN=My-Test-Attribute-DN-FL,CN=Schema,CN=Configuration,DC=myorg,DC=com
objectCategory: CN=Attribute-Schema,CN=Schema,CN=Configuration,DC=myorg,DC=com
objectClass: attributeSchema
oMObjectClass:: KwwCh3McAIVK
oMSyntax: 127
rangeLower: 0
rangeUpper: 257
name: My-Test-Attribute-DN-FL
schemaIDGUID:: YGLudffa0hGLEwDAT7mMGg==
searchFlags: 0
 
dn: CN=My-Test-Attribute-DN-BL,CN=Schema,CN=Configuration,DC=myorg,DC=com
changetype: add
adminDisplayName: My-Test-Attribute-DN-BL
attributeID: 1.2.840.113556.1.4.7000.159.24.10.615
attributeSyntax: 2.5.5.1
cn: My-Test-Attribute-DN-BL
description: 
 Test back link attribute of syntax DN used to show how to add a back link attribute. Forward link is My-Test-Attribute-DN-FL.
isMemberOfPartialAttributeSet: FALSE
isSingleValued: TRUE
lDAPDisplayName: myTestAttributeDNBL
linkID: 147
distinguishedName: 
 CN=My-Test-Attribute-DN-BL,CN=Schema,CN=Configuration,DC=myorg,DC=com
objectCategory: CN=Attribute-Schema,CN=Schema,CN=Configuration,DC=myorg,DC=com
objectClass: attributeSchema
oMObjectClass:: KwwCh3McAIVK
oMSyntax: 127
rangeLower: 0
rangeUpper: 257
name: My-Test-Attribute-DN-BL
schemaIDGUID:: jFfbhffa0hGLEwDAT7mMGg==
searchFlags: 0
 
dn: CN=My-Test-Attribute-DN-Regular,CN=Schema,CN=Configuration,DC=myorg,DC=com
changetype: add
adminDisplayName: My-Test-Attribute-DN-Regular
attributeID: 1.2.840.113556.1.4.7000.159.24.10.613
attributeSyntax: 2.5.5.12
cn: My-Test-Attribute-DN-Regular
description: 
 Test attribute of syntax DN used to show how to add a DN attribute.
isMemberOfPartialAttributeSet: FALSE
isSingleValued: TRUE
lDAPDisplayName: myTestAttributeDNRegular
distinguishedName: 
 CN=My-Test-Attribute-DN-Regular,CN=Schema,CN=Configuration,DC=myorg,DC=com
objectCategory: CN=Attribute-Schema,CN=Schema,CN=Configuration,DC=myorg,DC=com
objectClass: attributeSchema
oMObjectClass:: KwwCh3McAIVK
oMSyntax: 64
rangeLower: 0
rangeUpper: 257
name: My-Test-Attribute-DN-Regular
schemaIDGUID:: 5QSznA3W0hGBpwDAT7mMGg==
searchFlags: 0
 
dn: CN=My-Test-Attribute-DNString,CN=Schema,CN=Configuration,DC=myorg,DC=com
changetype: add
adminDisplayName: My-Test-Attribute-DNString
attributeID: 1.2.840.113556.1.4.7000.159.24.10.611
attributeSyntax: 2.5.5.14
cn: My-Test-Attribute-DNString
description: 
 Test attribute of syntax DNString used to show how to add a DNString attribute
 .
isMemberOfPartialAttributeSet: FALSE
isSingleValued: TRUE
lDAPDisplayName: myTestAttributeDNString
distinguishedName: 
 CN=My-Test-Attribute-DNString,CN=Schema,CN=Configuration,DC=myorg,DC=com
objectCategory: CN=Attribute-Schema,CN=Schema,CN=Configuration,DC=myorg,DC=com
objectClass: attributeSchema
oMObjectClass:: KoZIhvcUAQEBDA==
oMSyntax: 127
rangeLower: 1
rangeUpper: 64
name: My-Test-Attribute-DNString
schemaIDGUID:: 5ASznA3W0hGBpwDAT7mMGg==
searchFlags: 0
 
dn: CN=My-Test-Attribute-UnicodeString,CN=Schema,CN=Configuration,DC=myorg,DC=com
changetype: add
adminDisplayName: My-Test-Attribute-UnicodeString
attributeID: 1.2.840.113556.1.4.7000.159.24.10.612
attributeSyntax: 2.5.5.12
cn: My-Test-Attribute-UnicodeString
description: 
 Test attribute of syntax Unicode String (DirectoryString) used to show how to 
 add a Unicode String attribute.
isMemberOfPartialAttributeSet: FALSE
isSingleValued: TRUE
lDAPDisplayName: myTestAttributeUnicodeString
distinguishedName: 
 CN=My-Test-Attribute-UnicodeString,CN=Schema,CN=Configuration,DC=myorg,DC=com
objectCategory: CN=Attribute-Schema,CN=Schema,CN=Configuration,DC=myorg,DC=com
objectClass: attributeSchema
oMSyntax: 64
rangeLower: 0
rangeUpper: 257
name: My-Test-Attribute-UnicodeString
schemaIDGUID:: 9QSznA3W0hGBpwDAT7mMGg==
searchFlags: 0
 
DN:
changetype: modify
add: schemaUpdateNow
schemaUpdateNow: 1
-
 
dn: CN=My-Test-Auxiliary-Class1,CN=Schema,CN=Configuration,DC=myorg,DC=com
changetype: add
adminDisplayName: My-Test-Auxiliary-Class1
cn: My-Test-Auxiliary-Class1
defaultHidingValue: FALSE
defaultObjectCategory: 
 CN=My-Test-Auxiliary-Class1,CN=Schema,CN=Configuration,DC=myorg,DC=com
description: Test class used to show how to add an auxiliary class.
governsID: 1.2.840.113556.1.4.7000.159.24.10.611.11
lDAPDisplayName: myTestAuxiliaryClass1
mayContain: myTestAttributeDNString
mustContain: myTestAttributeUnicodeString
mustContain: description
distinguishedName: 
 CN=My-Test-Auxiliary-Class1,CN=Schema,CN=Configuration,DC=myorg,DC=com
objectCategory: CN=Class-Schema,CN=Schema,CN=Configuration,DC=myorg,DC=com
objectClass: classSchema
objectClassCategory: 3
possSuperiors: container
possSuperiors: domainDNS
name: My-Test-Auxiliary-Class1
rDNAttID: cn
schemaIDGUID:: mmsxdsXb0hGL0AAA+HW2YA==
subClassOf: top
 
DN:
changetype: modify
add: schemaUpdateNow
schemaUpdateNow: 1
-
 
dn: CN=My-Test-Structural-Class1,CN=Schema,CN=Configuration,DC=myorg,DC=com
changetype: add
adminDisplayName: My-Test-Structural-Class1
auxiliaryClass: myTestAuxiliaryClass1
cn: My-Test-Structural-Class1
defaultHidingValue: FALSE
defaultObjectCategory: 
 CN=Organizational-Unit,CN=Schema,CN=Configuration,DC=myorg,DC=com
defaultSecurityDescriptor: 
 D:(A;;RPWPCRCCDCLCLOLORCWOWDSDDTDTSW;;;DA)(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;SY)
 (A;;RPLCLORC;;;AU)
description: Test class used to show how to add a structure class.
governsID: 1.2.840.113556.1.4.7000.159.24.10.611.12
lDAPDisplayName: myTestStructuralClass1
mayContain: myTestAttributeDNFL
mayContain: wWWHomePage
mustContain: url
distinguishedName: 
 CN=My-Test-Structural-Class1,CN=Schema,CN=Configuration,DC=myorg,DC=com
objectCategory: CN=Class-Schema,CN=Schema,CN=Configuration,DC=myorg,DC=com
objectClass: classSchema
objectClassCategory: 1
possSuperiors: organizationalUnit
name: My-Test-Structural-Class1
rDNAttID: ou
schemaIDGUID:: 1HsnsL7b0hGL0AAA+HW2YA==
subClassOf: organizationalUnit

LGETATTCLS.VBS

On Error Resume Next
 
''''''''''''''''''''''''''''''''''''''
'Bind to the rootDSE
'''''''''''''''''''''''''''''''''''''''
sPrefix = "LDAP://"
Set root= GetObject(sPrefix & "rootDSE")
If (Err.Number <> 0) Then
   BailOnFailure Err.Number, "on GetObject method"
End If
 
''''''''''''''''''''''''''''''''''''''
'Get the DN for the Schema
'''''''''''''''''''''''''''''''''''''''
sSchema = root.Get("schemaNamingContext")
If (Err.Number <> 0) Then
   BailOnFailure Err.Number, "on Get method"
End If
 
''''''''''''''''''''''''''''''''''''''
'Bind to the Schema container
'''''''''''''''''''''''''''''''''''''''
Set Schema= GetObject(sPrefix & sSchema )
If (Err.Number <> 0) Then
   BailOnFailure Err.Number, "on GetObject method to bind to Schema"
End If
'''''''''''''''''''''''''''''''''''''''
'Read the fsmoRoleOwner attribute to see which server is the schema master.
'''''''''''''''''''''''''''''''''''''''
sMaster = Schema.Get("fsmoRoleOwner")
If (Err.Number <> 0) Then
   BailOnFailure Err.Number, "on IADs::Get method for fsmoRoleOwner"
End If
'''''''''''''''''''''''''''''''''''''''
'fsmoRoleOwner attribute returns the nTDSDSA object.
'The parent is the server object.
'Bind to NTDSDSA object and get parent
'''''''''''''''''''''''''''''''''''''''
Set NTDS = GetObject(sPrefix & sMaster)
If (Err.Number <> 0) Then
   BailOnFailure Err.Number, "on GetObject method for NTDS"
End If
sServer = NTDS.Parent
If (Err.Number <> 0) Then
   BailOnFailure Err.Number, "on IADs::get_Parent method"
End If
'''''''''''''''''''''''''''''''''''''''
'Bind to server object
'and get the reference to the computer object.
'''''''''''''''''''''''''''''''''''''''
Set Server = GetObject(sServer)
If (Err.Number <> 0) Then
   BailOnFailure Err.Number, "on GetObject method for " & sServer
End If
'''''''''''''''''''''''''''''''''''''''
'Display the DN for the computer object.
'''''''''''''''''''''''''''''''''''''''
sComputerDNSName = Server.Get("DNSHostName")
strText = "Schema Master has the following DNS Name: "& sComputerDNSName
WScript.echo strText
 
sFile = "myschemaext.ldf"
sFromDN = sSchema
sToDN = "CN=Schema,CN=Configuration,DC=myorg,DC=com"
sAttrPrefix = "My-Test"
sFilter = "(&((cn=" & sAttrPrefix & "*)(|(objectCategory=classSchema)(objectCategory=attributeSchema))))"
sRetAttr = "dn,adminDescription,adminDisplayName,governsID,cn,mayContain,mustContain,systemMayContain,systemMustContain,lDAPDisplayName,objectClassCategory,distinguishedName,objectCategory,objectClass,possSuperiors,systemPossSuperiors,subClassOf,defaultObjectCategory,name,schemaIDGUID,auxiliaryClass,auxiliaryClass,systemAuxiliaryClass,description,defaultHidingValue,rDNAttId,defaultSecurityDescriptor,attributeID,attributeSecurityGUID,attributeSyntax,isMemberOfPartialAttributeSet,isSingleValued,mAPIID,oMSyntax,rangeLower,rangeUpper,searchFlags,oMObjectClass,linkID"
 
'Add flag rootDN--we want schema.
sCommand = "ldifde -d " & sSchema 
sCommand = sCommand & " -c " & sFromDN & " " & sToDN
'Add flag schema master
sCommand = sCommand & " -s " & sComputerDNSName
'Add flag filename
sCommand = sCommand & " -f " & sFile
'Add flag filter to search for my attributes
sCommand = sCommand & " -r " & sFilter
'Add flag for attributes to return
sCommand = sCommand & " -l " & sRetAttr
 
WScript.echo sCommand
Set WshShell = Wscript.CreateObject("Wscript.Shell")
WshShell.Run (sCommand)
 
 
'''''''''''''''''''''''''''''''''''''''
'Display subroutines
'''''''''''''''''''''''''''''''''''''''
 
Sub BailOnFailure(ErrNum, ErrText)    strText = "Error 0x" & Hex(ErrNum) & " " & ErrText
    MsgBox strText, vbInformation, "ADSI Error"
    WScript.Quit
End Sub

LSETATTCLS.VBS

On Error Resume Next
 
''''''''''''''''''''''''''''''''''''''
'Bind to the rootDSE
'''''''''''''''''''''''''''''''''''''''
sPrefix = "LDAP://"
Set root= GetObject(sPrefix & "rootDSE")
If (Err.Number <> 0) Then
   BailOnFailure Err.Number, "on GetObject method"
End If
 
''''''''''''''''''''''''''''''''''''''
'Get the DN for the Schema
'''''''''''''''''''''''''''''''''''''''
sSchema = root.Get("schemaNamingContext")
If (Err.Number <> 0) Then
   BailOnFailure Err.Number, "on Get method"
End If
 
''''''''''''''''''''''''''''''''''''''
'Bind to the Schema container
'''''''''''''''''''''''''''''''''''''''
Set Schema= GetObject(sPrefix & sSchema )
If (Err.Number <> 0) Then
   BailOnFailure Err.Number, "on GetObject method to bind to Schema"
End If
'''''''''''''''''''''''''''''''''''''''
'Read the fsmoRoleOwner attribute to see which server is the schema master.
'''''''''''''''''''''''''''''''''''''''
sMaster = Schema.Get("fsmoRoleOwner")
If (Err.Number <> 0) Then
   BailOnFailure Err.Number, "on IADs::Get method for fsmoRoleOwner"
End If
'''''''''''''''''''''''''''''''''''''''
'fsmoRoleOwner attribute returns the nTDSDSA object.
'The parent is the server object.
'Bind to NTDSDSA object and get parent
'''''''''''''''''''''''''''''''''''''''
Set NTDS = GetObject(sPrefix & sMaster)
If (Err.Number <> 0) Then
   BailOnFailure Err.Number, "on GetObject method for NTDS"
End If
sServer = NTDS.Parent
If (Err.Number <> 0) Then
   BailOnFailure Err.Number, "on IADs::get_Parent method"
End If
'''''''''''''''''''''''''''''''''''''''
'Bind to server object
'and get the reference to the computer object.
'''''''''''''''''''''''''''''''''''''''
Set Server = GetObject(sServer)
If (Err.Number <> 0) Then
   BailOnFailure Err.Number, "on GetObject method for " & sServer
End If
sComputer = Server.Get("serverReference")
'''''''''''''''''''''''''''''''''''''''
'Display the DN for the computer object.
'''''''''''''''''''''''''''''''''''''''
sComputerDNSName = Server.Get("DNSHostName")
'strText = "Schema Master has the following DN: "& sComputer
strText = "Schema Master has the following DNS Name: "& sComputerDNSName
WScript.echo strText
 
sFile = "myschemaext.ldf"
sFromDN = "CN=Schema,CN=Configuration,DC=myorg,DC=com"
sToDN = sSchema
'Add flag replace fromDN with ToDN.
sCommand = "ldifde -i -k -c " & sFromDN & " " & sToDN
'Add flag schema master
sCommand = sCommand & " -s " & sComputerDNSName
'Add flag filename
sCommand = sCommand & " -f " & sFile
'Add flag filter to search for my attributes
 
WScript.echo sCommand
Set WshShell = Wscript.CreateObject("Wscript.Shell")
WshShell.Run (sCommand)
 
 
'''''''''''''''''''''''''''''''''''''''
'Display subroutines
'''''''''''''''''''''''''''''''''''''''
 
Sub BailOnFailure(ErrNum, ErrText)    strText = "Error 0x" & Hex(ErrNum) & " " & ErrText
    MsgBox strText, vbInformation, "ADSI Error"
    WScript.Quit
End Sub