DekGenius.com
[ Team LiB ] Previous Section Next Section

19.1 The IADs Properties

The IADs properties are as follows:

Class

The object's schema class

GUID

The object's Globally Unique ID (GUID)

Name

The object's name

ADsPath

The ADsPath to the object in the current namespace

Parent

The ADsPath to the object's parent

Schema

The ADsPath to the object's schema class

Each of these properties has a corresponding property method in the IADs interface. You can use the property method, which has the same name as the property, to access that property's value. Example 19-1 contains code to display the six IADs properties for a user object.

Example 19-1. Using the explicit property methods to display the six IADs properties
Dim objUser 'An ADSI User object
Dim str     'A text string
   
` User object using the WinNT namespace
Set objUser=GetObject("WinNT://MYCORP/Administrator,User")
str = "Name: " & objUser.Name & vbCrLf
str = str & "GUID: " & objUser.GUID & vbCrLf
str = str & "Class: " & objUser.Class & vbCrLf
str = str & "ADsPath: " & objUser.ADsPath & vbCrLf
str = str & "Parent: " & objUser.Parent & vbCrLf
str = str & "Schema: " & objUser.Schema & vbCrLf & vbCrLf
Set objUser = Nothing
   
` User object using the LDAP namespace
Set objUser=GetObject("LDAP://cn=Administrator,cn=Users,dc=mycorp,dc=com") 
Str = str & "Name: " & objUser.Name & vbCrLf
Str = str & "GUID: " & objUser.GUID & vbCrLf
Str = str & "Class: " & objUser.Class & vbCrLf
Str = str & "ADsPath: " & objUser.ADsPath & vbCrLf
Str = str & "Parent: " & objUser.Parent & vbCrLf
str = str & "Schema: " & objUser.Schema & vbCrLf & vbCrLf
   
WScript.Echo str
   
Set objUser = Nothing

To begin, we declare two variables (i.e., str and objUser), invoke the GetObject method to create a reference to the user object, and assign it to objUser. We then set the str variable to the string "Name:" and apply the IADs::Name property method (i.e., objUser.Name) to retrieve the Name property's value (i.e., Administrator). The carriage-return line-feed constant (vbCrLf) specifies to move to the start of a new line. At this point, str represents the string "Name: Administrator."

In the next line, we use the IADs::GUID property method (objUser.GUID) to retrieve the GUID property's value (i.e., {D83F1060-1E71-11CF-B1F3-02608C9E7553}). We are appending the GUID to previous value set in str so the new str represents the Name property value and the GUID property value. This was repeated until all six core properties in both the WinNT and the LDAP namespaces were retrieved.

You might be surprised to find out that enumerating properties in different namespaces produces different output, as Figure 19-1 shows. For example, the Name property under the LDAP namespace has "cn=" included, whereas the Name property under the WinNT namespace doesn't.

Figure 19-1. The IADs properties from the WinNT and LDAP namespaces
figs/ads2.1901.gif

Both the code and the figure demonstrate another important point: The type of directory can affect the results. For example, using the IADs::Parent property makes sense when you're using the LDAP namespace to access a hierarchical directory such as Active Directory, because you can see parent-child relationships (e.g., you can see that the Users container is the parent for the Administrator User object). However, using the IADs::Parent property to look at NT's Security Accounts Manager (SAM) doesn't make sense where domains are concerned because the contents are all in one flat namespace.

19.1.1 Using IADs::Get and IADs::Put

While you can use property methods to access an object's properties, you can also use the IADs interface's IADs::Get and IADs::Put methods to retrieve any attribute on the object.

In other words, the following two sets of statements are equivalent:

strName = objUser.description
objUser.description = strName
   
strName = objUser.Get("description")
objUser.Put "description", strName

However, using the IADs::Get and IADs::Put methods is more of a performance hit as it involves internally doing a search for the property specified. Compared to this, the direct use of a property is what is known as a direct vtable binding per the COM documentation and is the faster of the two. IADs::Get and IADs::Put should be used only when a generic browser or program is written to work with any ADSI object. See Table 19-1 for the full set of methods and property methods for the IADs interface.

Table 19-1. The main IADs methods and properties

IADs methods and properties

Action

Get method

Retrieves a single item from the property cache

Put method

Sets a single item in the property cache

GetEx method

Retrieves a multivalued item from the property cache

PutEx method

Sets a multivalued item in the property cache

GetInfo method

Retrieves all of an object's properties into the property cache

GetInfoEx method

Retrieves one or more of an object's properties into the cache

SetInfo method

Writes out all the items in the property cache to the directory

get_Name method

Gets the name of the object[1]

get_GUID method

Gets the GUID of the object

get_Class method

Gets the schema class name of the object

get_ADsPath method

Gets the ADsPath of the object

get_Parent method

Gets the parent ADsPath of the object

get_Schema method

Gets the ADsPath of the object's schema class

Class property

Represents the Schema class of the object

GUID property

Represents the GUID of the object

Name property

Represents the name of the object

AdsPath property

Represents the ADsPath of the object

Parent property

Represents the ADsPath to the parent of this object

Schema property

Represents the ADsPath of the object's schema class

[1] A VC++ method. We won't include these in the future interface definitions, but they do serve as an example that VC++ does not support setting properties in a similar way to VBScript.

Why Microsoft couldn't have named IADs::SetInfo PutInfo, or renamed IADs::Put and IADs::PutEx Set and SetEx for consistency is beyond us.

For example, the next script shows how you use IADs::Get and IADs::Put to retrieve, change, and return the mail property. After we set the objGroup variable to the pointer to the Managers group, we use the IADs::Get method (objGroup.Get) with the "mail" argument to retrieve the mail property's value. The WScript.Echo method displays the results in a window.

Changing the value and returning it to the property cache is just as simple. You use the IADs::Put method with the argument "mail". You don't put the argument in parentheses when you use the IADs::Put method: the method in a subprocedure, not a function, and it doesn't return a value. The string that follows the IADs::Put function contains the Managers group's new mail contact address. To write the new mail property to Active Directory, you use IADs::SetInfo:

Set objGroup = GetObject("LDAP://cn=Managers,ou=Sales,dc=mycorp,dc=com")
WScript.Echo objGroup.Get("mail")
   
objGroup.Put "mail", "agl1@mycorp.com"
objGroup.SetInfo

19.1.2 The Property Cache

Having looked at properties and property methods, let's take a look at the property cache, a location in memory on the local machine running the script that stores properties for objects. Each object that you bind to has a personal property cache; the OS creates this cache the instant the bind succeeds. However, the OS doesn't immediately populate the cache with values.

Accessing the Property Cache with Microsoft Visual C++

VC++ cannot use the same property method mechanism that automation languages like VBScript can use to get and set values in the property cache. Instead, Microsoft designed a variety of nonautomation interfaces, methods, and properties VC++ can make use of.

For example, when setting properties for a group, VC++ has access to the IADs::Get and IADs::Put methods in the same way that VBScript does. In addition, it also has access to the IADsGroup::get_Description and IADs::put_Description methods. This is because VC++ cannot use the IADs::Description property method. Code in VC++ would look like this using IADs::Put:

// Declare the variables
IADsGroup  *pGroup;
IADs       *pObject;
ADsGetObject(
  TEXT("LDAP://cn=Managers,ou=Sales,dc=mycorp,dc=com"),
  IID_IADsGroup, 
  (void**) &pGroup);
// Set using IADs::Put method
pGroup->QueryInterface(IID_IADs,(void **) &pObject);
pObject->Put("Description",TEXT("My new group description goes here"))
pGroup->SetInfo;

Code in VC++ would look like this when using the IADsGroup::put_Description method:

// Declare the variables
IADsGroup  *pGroup;
IADs       *pObject;
ADsGetObject(     
  TEXT("LDAP://cn=Managers,ou=Sales,dc=mycorp,dc=com"),
  IID_IADsGroup, 
  (void**) &pGroup);
// Set using IADsGroup::put_Description property method
pGroup->put_Description(TEXT("My new group description goes here"));
pGroup->SetInfo;

When you use the IADs::Get method to retrieve an object's property, ADSI doesn't go to Active Directory to retrieve the value. Instead, ADSI reads the value from the property cache on the client executing the script. If ADSI doesn't find the property in the property cache when the call comes in, the system implicitly executes an IADs::GetInfo call to read all the properties for the current object into the cache. (You also can explicitly use the IADs::GetInfo method to populate the property cache with an object's properties.) The IADs::Get method then reads the appropriate value from the newly created cache.

Microsoft designed the property cache with efficiency in mind. The property cache lets you access an object's properties with a minimum number of calls, thereby minimizing network traffic. Retrieving all of an object's properties with one IADs::GetInfo call is more efficient than individually retrieving each property. Similarly, the process of writing all of an object's properties first to the cache and then to Active Directory with one IADs::SetInfo call is more efficient than writing each property individually to Active Directory.

19.1.3 Be Careful

The IADs::GetInfo and IADs::SetInfo methods are two of the most important methods you'll use. However, you need to be aware of two possible problems.

The first problem can arise if you try to access a property that doesn't have a value. For example, when you create a group object, the mail property doesn't automatically receive a value; you must provide a value, such as agl1@mycorp.com. When you use the IADs::GetInfo method, only those properties that have values appear in the property cache. Thus, if you don't give the mail property a value and you use IADs::GetInfo, the mail property value won't be in the property cache. If you try to access a property that doesn't exist in the cache, the script will give an empty value as the result.

Later on we talk about navigating the property cache. If you want to see a good example of how this actually works, try this: create a new object of type group, which has around 21 properties set by the system by default. You then use IADs::GetInfo in a script and display the number of properties, and possibly their names, in a dialog box. Then set the description. Now, when you rerun the script, you will find that you have one more property in the cache than you did before the description. In other words, the description does not appear in the cache until you do an IADs::GetInfo after it has been set.

Another problem can arise if you forget to use IADs::SetInfo after modifying a property. For example, suppose you want to change the Managers group's mail property value and you create the script shown in Example 19-2.

Example 19-2. Making the mistake of forgetting the SetInfo call
Dim objGroup  'An ADSI group object
   
Set objGroup = GetObject("LDAP://cn=Managers,ou=Sales,dc=mycorp,dc=com")
   
'**********************************************************************
'Get and write the mail property value, which forces an
'implicit GetInfo call
'**********************************************************************
WScript.Echo objGroup.Get("mail")
   
'**********************************************************************
'Set the new mail address in the cache
'**********************************************************************
objGroup.Put "mail", "new-address@mycorp.com"
   
'**********************************************************************
'Use an explicit GetInfo call to again retrieve all items into the cache
'**********************************************************************
objGroup.GetInfo
   
WScript.Echo objGroup.mail

In Example 19-2, we set the objGroup variable to the pointer to the Managers group. To display the current mail property value in a window, we use the WScript::Echo method with the IADs::Get method, which forces an implicit IADs::GetInfo call. We then set the new value for the objGroup's mail property, after which we use an explicit IADs::GetInfo call to again retrieve all the object's properties into the cache. Finally, we use the WScript.Echo method to display the results in a window.

When you run the script, two windows pop up. To your dismay, both windows state the original value of the mail property, which means that the system didn't write the new mail address to Active Directory. This cache write didn't occur because you need to explicitly call the IADs::SetInfo method to write out data from the cache to Active Directory. To fix the script, you need to insert the line:

objGroup.SetInfo

between the line setting the new mail address and the line making the explicit IADs::GetInfo call.

19.1.4 More Complexities of Property Access: IADs::GetEx and IADs::PutEx

Using the IADs interface's IADs::Get method works well for properties with one value. However, some properties have multiple values, such as a user with several telephone numbers. If a property stores multiple values, you need to use the IADs interface's IADs::GetEx[2] and IADs::PutEx methods to retrieve and return the values.

[2] You also can use IADs::GetEx for single-value properties.

19.1.4.1 Using IADs::GetEx

The following script shows how to use IADs::GetEx. In this script, we pass the multiple-value property as an argument to the IADs::GetEx method. We then use a For Each...Next loop on the resulting list.

Dim objUser        'An ADSI user object
Dim arrPhoneList   'An array of phone numbers
Dim strPhoneNumber 'An individual phone number
Set objUser=GetObject("LDAP://cn=administrator,cn=Users,dc=mycorp,dc=com")
arrPhoneList = objUser.GetEx("telephoneNumber")
For Each strPhoneNumber In arrPhoneList
  WScript.Echo strPhoneNumber
Next

When we make the IADs::GetEx call, the system makes an implicit IADs::GetInfoEx call rather than an implicit IADs::GetInfo call to Active Directory. You can use an explicit IADs::GetInfoEx call to get one or more properties if you don't want to use IADs::GetInfo to get all the property values. However, few scriptwriters use IADs::GetInfoEx for this purpose, because they typically use implicit calls or use IADs::GetInfo to read all values into the property cache. In addition, if you use IADs::GetEx for every property retrieval rather than using IADs::GetInfo, your underlying network traffic will increase. Instead of sending one request to the server for all the information, you'll be sending several requests for smaller amounts of information.

Although IADs::GetInfoEx isn't a good substitute for IADs::GetInfo, it works well for selectively reading properties into the property cache. Example 19-3 shows how to selectively retrieve only two properties.

Example 19-3. Selectively reading properties into the property cache using the GetInfo method
Dim objUser  'An ADSI user object
Dim arrProps 'An array of properties to return
   
Set objUser=GetObject("LDAP://cn=administrator,cn=Users,dc=mycorp,dc=com")
   
'**********************************************************************
'Set the list of properties to return
'**********************************************************************
ArrProps = Array("cn","ADsPath")
   
'**********************************************************************
'Get the specified properties
'**********************************************************************
objUser.GetInfoEx arrProps, 0
   
WScript.Echo objUser.cn & vbTab & objUser.ADsPath

After we set the objUser variable, we create an array containing the properties we want (i.e., cn and ADsPath). Next, we pass that array to the IADs::GetInfoEx method as the first parameter. (The second parameter must be 0 for all actions; however, it is reserved and could be used in a later version of ADSI.) Then, the last line uses the WScript.Echo method to print the cn and ADsPath attributes, separating them with a tab.

19.1.4.2 Using IADs::PutEx

To set multivalue properties, you use the IADs::PutEx method. This is slightly more complicated than using IADs::GetEx. Suppose a property already has three values (e.g., pager numbers), and you want to put in two more. You must let IADs::PutEx know whether it needs to overwrite, update, or add to the existing values. You use the constants in Table 19-2 to tell IADs::PutEx what to do.

Table 19-2. The constants for updating the property cache with the PutEx method

Constant name

Value

Action

ADS_PROPERTY_CLEAR

1

Use when clearing all values

ADS_PROPERTY_UPDATE

2

Use when replacing all existing values

ADS_PROPERTY_APPEND

3

Use when adding to existing values

ADS_PROPERTY_DELETE

4

Use when deleting specific values

Use the constant name only if you're using VB. If you use VBScript with the WSH, you must either define the constants, as we've done in Example 19-4, or use the values directly. The four values are fairly straightforward to use, as the example script shows.

Example 19-4. Using constants with the PutEx method to update the property cache
Const ADS_PROPERTY_CLEAR = 1
Const ADS_PROPERTY_UPDATE = 2
Const ADS_PROPERTY_APPEND = 3
Const ADS_PROPERTY_DELETE = 4
   
Dim objUser  'An ADSI User object
Dim strPager 'A text string holding a phone number
   
Set objUser=GetObject("LDAP://cn=Administrator,cn=Users,dc=mycorp,dc=com")
   
'**********************************************************************
'Set three telephone numbers for the Administrator account
'**********************************************************************
objUser.PutEx ADS_PROPERTY_UPDATE, "pager", _
  Array("123-1234", "234-2345", "345-3456") 
objUser.SetInfo
objUser.GetInfo
For Each strPager in objUser.telephoneNumber
  WScript.Echo strPager
Next
   
'**********************************************************************
'Delete the first and last number
'**********************************************************************
objUser.PutEx ADS_PROPERTY_DELETE, "pager", Array("123-1234", "345-3456")
objUser.SetInfo
objUser.GetInfo
For Each strPager in objUser.telephoneNumber
  WScript.Echo strPager
Next
   
'**********************************************************************
'Add a new telephone number without deleting the remaining number
'**********************************************************************
objUser.PutEx ADS_PROPERTY_APPEND, "pager", Array("456-4567") 
objUser.SetInfo
objUser.GetInfo
For Each strPager in objUser.telephoneNumber
  WScript.Echo strPager
Next
   
'**********************************************************************
'Delete all values
'**********************************************************************
objUser.PutEx ADS_PROPERTY_CLEAR, "pager", vbNull
objUser.SetInfo
objUser.GetInfo
For Each strPager in objUser.telephoneNumber
  WScript.Echo strPager
Next

After binding to the user object, three pager numbers are set for the Administrator account, wiping out any existing values. The property cache is then reloaded explicitly to make sure it contains the new values that were just set. Now, a For Each loop is used to go through the newly set property to show the individual pager numbers. The first and last pager numbers of the new property are deleted in the cache and written to Active Directory with SetInfo.

At this point, Active Directory should contain only one pager number, which is displayed by looping through the values again. Next we append a number to the value held for that property in the cache and subsequently write it out to Active Directory, leaving two numbers in Active Directory for that property. Looping through the values again shows there are two numbers. Finally, all values in the property cache for that property are deleted, and the changes are updated in Active Directory. Using the For Each loop one last time should show no values.

Knowing now that you can access all of an object's properties from the cache individually, it would make sense if there were a way to count the number of items, display their names as well as their values, and so on. For this purpose, Microsoft provided three interfaces: IADsPropertyList, IADsPropertyEntry, and IADsPropertyValue.

    [ Team LiB ] Previous Section Next Section