Mombu the Microsoft Forum sponsored links

Go Back   Mombu the Microsoft Forum > Microsoft > ADO Connection, Error: (438) Object doesn't support this property
User Name
Password
REGISTER NOW! Mark Forums Read

sponsored links


Reply
 
1 5th August 03:16
richard mueller [mvp]
External User
 
Posts: 1
Default ADO Connection, Error: (438) Object doesn't support this property


You don't create the object adoCommand1 and assign the ActiveConnection
property. You are missing:

Set adoCommand1 = CreateObject("ADODB.Command")
adoCommand.ActiveConnection = adoConnection

This should be done once outside the loop. The other properties, like "Page
Size", can also be done outside the loop (so the properties are only
assigned values once). However, the CommandText property must be assigned to
the adoCommand1 object inside the loop since there is a different value each
time.

--
Richard Mueller
MVP Directory Services
Hilltop Lab - http://www.rlmueller.net
--
  Reply With Quote


  sponsored links


2 5th August 03:16
External User
 
Posts: 1
Default ADO Connection, Error: (438) Object doesn't support this prope


Richard,

thank you for the reply I've been trying to figure this out for days!

sorry to ask more from you but can you modify the code or even just some of
it to show me how to apply the changes you mention outside of the loop?

thanks in advance
  Reply With Quote
3 5th August 03:16
richard mueller [mvp]
External User
 
Posts: 1
Default ADO Connection, Error: (438) Object doesn't support this prope


I believe the following modification to your program should work, but I have
not tested:
========
Sub ModifyUserGroup(nUser As String, nGroupName As String, Operation As
String)
Dim user As IADsUser
Dim adoCommand, adoConnection, strBase, strFilter, strAttributes
Dim adoCommand1, adoRecordset1, Grp 'varibales for searching groups
Dim objRootDSE, strDNSDomain, strQuery, adoRecordset, strName, strCN

' Setup ADO objects.
Set adoCommand = CreateObject("ADODB.Command")
Set adoConnection = CreateObject("ADODB.Connection")
adoConnection.Provider = "ADsDSOObject"
adoConnection.Open "Active Directory Provider"
adoCommand.ActiveConnection = adoConnection
Set adoCommand1 = CreateObject("ADODB.Comand")
adoCommand.ActiveConnection = adoConnection

' Search entire Active Directory domain.
Set objRootDSE = GetObject("LDAP://RootDSE")
strDNSDomain = objRootDSE.Get("defaultNamingContext")
strBase = "<LDAP://" & strDNSDomain & ">"

' Filter on user objects and common name
strFilter = "(&(objectCategory=person)(objectClass=user)(c n=" & nUser &
"))"

' Comma delimited list of attribute values to retrieve.
strAttributes = "sAMAccountName,cn,adsPath"

' Construct the LDAP syntax query.
strQuery = strBase & ";" & strFilter & ";" & strAttributes & ";subtree"
adoCommand.CommandText = strQuery
adoCommand.Properties("Page Size") = 100
adoCommand.Properties("Timeout") = 30
adoCommand.Properties("Cache Results") = False
adoCommand1.Properties("Page Size") = 100
adoCommand1.Properties("Timeout") = 30
adoCommand1.Properties("Cache Results") = False

' Run the query.
Set adoRecordset = adoCommand.Execute

' Enumerate the resulting recordset.
Do Until adoRecordset.EOF
Set user = GetObject(adoRecordset.Fields("adsPath")).Value

' Retrieve values and display.
strName = adoRecordset.Fields("sAMAccountName").Value
strCN = adoRecordset.Fields("cn").Value

'Add the group to this user
'Search for the group
strFilter = "(&(objectCategory=group)((cn=" & nGroupName & "))"

' Construct the LDAP syntax query.
strQuery = strBase & ";" & strFilter & ";" & strAttributes &
";subtree"
adoCommand1.CommandText = strQuery

' Run the query.
Set adoRecordset1 = adoCommand1.Execute

' Enumerate the resulting recordset.
Do Until adoRecordset1.EOF

Set Grp = GetObject(adoRecordset1.Fields("adsPath")).Value
If Operation = "Add" Then
Grp.Add (user)
Else
Grp.Remove (user)
End If

adoRecordset1.MoveNext
Loop
adoRecordset1.Close
' Move to the next record in the recordset.
adoRecordset.MoveNext
Loop

' Clean up.
adoRecordset.Close
adoConnection.Close

End Sub
=========
Also, it would be more efficient to use the IADsNameTranslate interface to
convert NT names (pre-Windows 2000 logon names) into Distinguishd Names.
This is faster than searching AD for the object. For more on using
NameTranslate see this link:

http://www.rlmueller.net/NameTranslateFAQ.htm

I will post a modification to your program that uses NameTranslate instead
of ADO shortly.

--
Richard Mueller
MVP Directory Services
Hilltop Lab - http://www.rlmueller.net
--
  Reply With Quote
4 5th August 03:16
richard mueller [mvp]
External User
 
Posts: 1
Default ADO Connection, Error: (438) Object doesn't support this prope


Sorry, when I replied I did not notice that you are using the Common Names
of the objects, not the NT names (pre-Windows 2000 names). You cannot use
IADsNameTranslate to convert Common Names into Distinguished Names. You must
use ADO.

I also see I had a typo in my reply. Instead of adding the statement (which
is redundant):

adoCommand.ActiveConnection = adoConnection

I should have added:

adoCommand1.ActiveConnection = adoConnection

Finally, there are two points to consider. First, the value of the cn
attribute may not be unique in the domain. To be safe you might want to
check how many records are returned in the recordsets. You must assign a
value to the cursorLocation property of the Connection object to permit
this, then use the MoveFirst method of the Recordset object to move back to
the beginning of the recordset after retrieving the RecordCount property.

Second, the user could already be a member of the group when you attempt to
add them, or they might not be a member when you attempt to remove them.
This can be checked. In my revised version below I have the Sub exit if any
of these bad conditions are detected, but you could also show a message or
somehow indicate to the calling program. My revised version is below:
=========
Sub ModifyUserGroup(nUser As String, nGroupName As String, Operation As
String)
Dim user
Dim adoCommand, adoConnection, strBase, strFilter, strAttributes
Dim adoCommand1, adoRecordset1, Grp 'varibales for searching groups
Dim objRootDSE, strDNSDomain, strQuery, adoRecordset, strName, strCN

' In VB this may not be necessary, if you add a reference to
' ADO (Microsoft ActiveX Data Objects) in the project.
Const adUseClient = 3

' Setup ADO objects.
Set adoCommand = CreateObject("ADODB.Command")
Set adoConnection = CreateObject("ADODB.Connection")
adoConnection.Provider = "ADsDSOObject"
adoConnection.CursorLocation = adUseClient
adoConnection.Open "Active Directory Provider"
adoCommand.ActiveConnection = adoConnection
Set adoCommand1 = CreateObject("ADODB.Comand")
adoCommand1.ActiveConnection = adoConnection

' Search entire Active Directory domain.
Set objRootDSE = GetObject("LDAP://RootDSE")

strDNSDomain = objRootDSE.Get("defaultNamingContext")
strBase = "<LDAP://" & strDNSDomain & ">"

' Filter on user objects and common name
strFilter = "(&(objectCategory=person)(objectClass=user)(c n=" & nUser &
"))"

' Comma delimited list of attribute values to retrieve.
strAttributes = "sAMAccountName,cn,adsPath"

' Construct the LDAP syntax query.
strQuery = strBase & ";" & strFilter & ";" & strAttributes & ";subtree"
adoCommand.CommandText = strQuery
adoCommand.Properties("Page Size") = 100
adoCommand.Properties("Timeout") = 30
adoCommand.Properties("Cache Results") = False
adoCommand1.Properties("Page Size") = 100
adoCommand1.Properties("Timeout") = 30
adoCommand1.Properties("Cache Results") = False

' Run the query.
Set adoRecordset = adoCommand.Execute

' Make sure there is only one record.
If (adoRecordset.RecordCount <> 1) Then
' Perhaps notify the user.
Exit Sub
End If

' Move the cursor back to the beginning.
adoRecordset.MoveFirst

' Enumerate the resulting recordset.
Do Until adoRecordset.EOF
Set user = adoRecordset.Fields("adsPath")

' Retrieve values and display.
strName = adoRecordset.Fields("sAMAccountName").Value
strCN = adoRecordset.Fields("cn").Value

'Add the group to this user
'Search for the group
strFilter = "(&(objectCategory=group)((cn=" & nGroupName & "))"

' Construct the LDAP syntax query.
strQuery = strBase & ";" & strFilter & ";" & strAttributes &
";subtree"
adoCommand1.CommandText = strQuery

' Run the query.
Set adoRecordset1 = adoCommand1.Execute

' Make sure there is only one record.
If (adoRecordset1.RecordCount <> 1) Then
' Perhaps notify the user.
Exit Sub
End If

' Move the cursor back to the beginning.
adoRecordset1.MoveFirst

' Enumerate the resulting recordset.
Do Until adoRecordset1.EOF

Set Grp = GetObject(adoRecordset1.Fields("adsPath").Value)
If Operation = "Add" Then
If (Grp.IsMember(user) = False) Then
Grp.Add(user)
Else
' Perhaps notify user.
Exit Function
End If
Else
If (Grp.IsMember(user) = True) then
Grp.Remove(user)
Else
' Perhaps notify user.
Exit Function
End If
End If

adoRecordset1.MoveNext
Loop
adoRecordset1.Close
' Move to the next record in the recordset.
adoRecordset.MoveNext
Loop

' Clean up.
adoRecordset.Close
adoConnection.Close

End Sub
=======
One more point I just noticed. The variable "user" should be the AdsPath of
the user retrieved by ADO. This is actually a string, not an IADsUser
object. If you bind to the object, so it is an IADsUser object (which is
unnecessary), then you must pass the ADsPath property to the Grp object Add
and Remove methods. That is, you would use Grp.Add(user.AdsPath and
Grp.Remove(user.AdsPropery). Since you already are retrieving the value of
ADsPath with ADO, there is no need to bind to the object. I have corrected
for this above. Again, I have not tested.

And still one more problem. When you bind to the "Grp" object, the statement
should not be:

Set Grp = GetObject(adoRecordset1.Fields("adsPath")).Value

but instead:

Set Grp = GetObject(adoRecordset1.Fields("adsPath").Value)

Although the former may work (I have not checked), it seems confusing to me.
We want to pass the value of the AdsPath property to the GetObject method. I
have no idea what the Value of the resulting object might be.

--
Richard Mueller
MVP Directory Services
Hilltop Lab - http://www.rlmueller.net
--
  Reply With Quote
5 5th August 03:16
External User
 
Posts: 1
Default ADO Connection, Error: (438) Object doesn't support this prope


Thanks for spending so much time on this for me, i still have a couple of
questions if you dont mind.

1. does the project need to include variables to ADODB.Connection and
ADODB.Recordset?

quote:


2. is there an easier way to add or remove members to a group via VB this is
the first time i have used ADO and this is what i came up with...

-the input data will be a cn / samAccountname which are the same value, and
the group name / cn name which again are the same value.
  Reply With Quote
6 5th August 03:16
richard mueller [mvp]
External User
 
Posts: 1
Default ADO Connection, Error: (438) Object doesn't support this prope


See inline below:

Assuming this is a classic VB project, you should include a reference to
"Microsoft ActiveX Data Objects" (in Project, References...). Then you can
use early binding instead of late binding. For example:

Dim adoConnection As ADODB.Connection
Set adoConnection = New ADODB.Connection

What you have will still work (using CreateObject), but the above is
preferred, and in the vb IDE intellisense helps you code. The same can be
done with user and group objects if you include a reference to the "Active
DS Type Library" (activeds.tlb). For example

Dim Grp As IADsGroup
Set Grp = GetObject(strAdsPath)

You still use the GetObject method to bind to user and group objects, but
again intellisense helps select the correct properties of the object when
you declare with the correct IADs interface. Of course you cannot use early binding in VBScript.

In the statement:

strAdsPath = adoRecordset.Fields("AdsPath").Value

we reference the "Fields" collection of the recordset object. We select the
specific field called "AdsPath". We specify the "Value" property of that
field and assign this to the variable "strAdsPath". Since Value is the
default property of the fields collection, you could skip the .Value part,
but I like to not assume defaults and specify things ********ly whenever
possible.

Rather than assigning the value to a variable, you can use it in a binding
string. For example:

Set objUser = GetObject(adoRecordset.Fields("AdsPath").Value)

The AdsPath is valid here. However, you used code similar to the following:

Set objUser = GetObject(adoRecordset.Fields("AdsPath")).Value

In this case, even though you do not specify the Value property of the
AdsPath field, the same value is retrieved because Value is the default
property. That is, these two are equivalent (are the same value):

adoRecordset.Fields("AdsPath").Value
adoRecordset.Fields("AdsPath")

So, the following will work:

Set objUser = GetObject(adoRecordset.Fields("AdsPath"))

However, your statement references the Value property of this object. I
tested and there is no such property. An error is raised when I attempt to use it.

The procedure you are using (with the Add and Remove methods of the group
object) is the best in my opinion. These methods were designed for the purpose.

If you know that the values passed to the Sub are the sAMAccountName of the
user and group, then it would be more efficient to use NameTranslate.
However, if your program works, it doesn't matter much. When I get a chance,
I'll post a version that uses NameTranslate.

--
Richard Mueller
MVP Directory Services
Hilltop Lab - http://www.rlmueller.net
--
  Reply With Quote
7 5th August 03:16
External User
 
Posts: 1
Default ADO Connection, Error: (438) Object doesn't support this prope


I got somewhat confused trying to make the amendments as you mention Set
objUser and strAdsPath which I dont have set as values in my project.

also I thought we didn't want to set Dim user as IADsUser in this project as
we're using it as a string?


here is what I have now, would you mind taking a look.


Sub ModifyUserGroup(nUser As String, nGroupName As String, Operation As
String)
Dim user
Dim strBase, strFilter, strAttributes
Dim Grp 'varibales for searching groups
Dim objRootDSE, strDNSDomain, strQuery, strName, strCN
Dim adoConnection As ADODB.Connection
Dim adoCommand As ADODB.Command
Dim adoCommand1 As ADODB.Command
Dim adoRecordset As ADODB.Recordset
Dim adoRecordset1 As ADODB.Recordset


' Setup ADO objects.
Set adoCommand = New ADODB.Command
Set adoConnection = New ADODB.Connection
adoConnection.Provider = "ADsDSOObject"
adoConnection.CursorLocation = adUseClient
adoConnection.Open "Active Directory Provider"
adoCommand.ActiveConnection = adoConnection
Set adoCommand1 = New ADODB.Command
adoCommand1.ActiveConnection = adoConnection

' Search entire Active Directory domain.
Set objRootDSE = GetObject("LDAP://RootDSE")

strDNSDomain = objRootDSE.Get("defaultNamingContext")
strBase = "<LDAP://" & strDNSDomain & ">"

' Filter on user objects and common name
strFilter = "(&(objectCategory=person)(objectClass=user)(c n=" & nUser &
"))"

' Comma delimited list of attribute values to retrieve.
strAttributes = "sAMAccountName,cn,adsPath"

' Construct the LDAP syntax query.
strQuery = strBase & ";" & strFilter & ";" & strAttributes & ";subtree"
adoCommand.CommandText = strQuery
adoCommand.Properties("Page Size") = 100
adoCommand.Properties("Timeout") = 30
adoCommand.Properties("Cache Results") = False
adoCommand1.Properties("Page Size") = 100
adoCommand1.Properties("Timeout") = 30
adoCommand1.Properties("Cache Results") = False

' Run the query.
Set adoRecordset = adoCommand.Execute

' Make sure there is only one record.
If (adoRecordset.RecordCount <> 1) Then
' Perhaps notify the user.
Exit Sub
End If

' Move the cursor back to the beginning.
adoRecordset.MoveFirst

' Enumerate the resulting recordset.
Do Until adoRecordset.EOF
Set user = adoRecordset.Fields("adsPath")

' Retrieve values and display.
strName = adoRecordset.Fields("sAMAccountName").Value
strCN = adoRecordset.Fields("cn").Value

'Add the group to this user
'Search for the group
strFilter = "(&(objectCategory=group)((cn=" & nGroupName & "))"

' Construct the LDAP syntax query.
strQuery = strBase & ";" & strFilter & ";" & strAttributes &
";subtree"
adoCommand1.CommandText = strQuery

' Run the query.
Set adoRecordset1 = adoCommand1.Execute

' Make sure there is only one record.
If (adoRecordset1.RecordCount <> 1) Then
' Perhaps notify the user.
Exit Sub
End If

' Move the cursor back to the beginning.
adoRecordset1.MoveFirst

' Enumerate the resulting recordset.
Do Until adoRecordset1.EOF

Set Grp = GetObject(adoRecordset1.Fields("adsPath").Value)
If Operation = "Add" Then
If (Grp.IsMember(user) = False) Then
Grp.Add (user)
Else
' Perhaps notify user.
Exit Sub
End If
Else
If (Grp.IsMember(user) = True) Then
Grp.Remove (user)
Else
' Perhaps notify user.
Exit Sub
End If
End If

adoRecordset1.MoveNext
Loop
adoRecordset1.Close
' Move to the next record in the recordset.
adoRecordset.MoveNext
Loop

' Clean up.
adoRecordset.Close
adoConnection.Close

Exit Sub
End Sub
  Reply With Quote
8 5th August 03:16
External User
 
Posts: 1
Default ADO Connection, Error: (438) Object doesn't support this prope


with the code I just provided I receive error (-2147217900) one or more
errors occured during processing of command. The error line is:

Set adoRecordset1 = adoCommand1.Execute

Any ideas?
  Reply With Quote
9 5th August 03:16
richard mueller [mvp]
External User
 
Posts: 1
Default ADO Connection, Error: (438) Object doesn't support this prope


Subtle error in the second query. The parentheses don't match in this
statement:

strFilter = "(&(objectCategory=group)((cn=" & nGroupName & "))"

It should be:

strFilter = "(&(objectCategory=group)(cn=" & nGroupName & "))"

I would also not use "Set" when assigning the string value for "user".
Instead of:

Set user = adoRecordset.Fields("adsPath")

I would recommend:

user = adoRecordset.Fields("adsPath")

--
Richard Mueller
MVP Directory Services
Hilltop Lab - http://www.rlmueller.net
--
  Reply With Quote
10 5th August 23:10
richard mueller [mvp]
External User
 
Posts: 1
Default ADO Connection, Error: (438) Object doesn't support this prope


A revised version that uses the IADsNameTranslate object instead of ADO. The
ADO version is fine, and it if works, no real reason to modify, but
NameTranslate is more efficient:
==========
Sub ModifyUserGroup(nUser As String, nGroupName As String, Operation As
String)
Dim objRootDSE, strDNSDomain, objTrans, strNetBIOSDomain
Dim strUserADsPath, strGroupADsPath, objGroup

' Constants for the NameTranslate object.
Const ADS_NAME_INITTYPE_GC = 3
Const ADS_NAME_TYPE_NT4 = 3
Const ADS_NAME_TYPE_1779 = 1

Set objRootDSE = GetObject("LDAP://RootDSE")
strDNSDomain = objRootDSE.Get("defaultNamingContext")

' Use the NameTranslate object.
Set objTrans = CreateObject("NameTranslate")
objTrans.Init ADS_NAME_INITTYPE_GC, ""

' Convert DNS domain name into NetBIOS name of domain.
objTrans.Set ADS_NAME_TYPE_1779, strDNSDomain
strNetBIOSDomain = objTrans.Get(ADS_NAME_TYPE_NT4)
' Remove trailing backslash.
strNetBIOSDomain = Left(strNetBIOSDomain, Len(strNetBIOSDomain) - 1)

' Convert NT name of user into Distinguished Name.
' Trap error if user does not exist.
On Error Resume Next
objTrans.Set ADS_NAME_TYPE_NT4, strNetBIOSDomain & "\" & nUser
If (Err.Number <> 0) Then
On Error GoTo 0
' User not found.
Exit Sub
End If
On Error GoTo 0
strUserADsPath = "LDAP://" & objTrans.Get(ADS_NAME_TYPE_1779)

' Convert NT Name of group into Distinguished Name.
' Trap error if group does not exist.
On Error Resume Next
objTrans.Set ADS_NAME_TYPE_NT4, strNetBIOSDomain & "\" & nGroupName
If (Err.Number <> 0) Then
On Error GoTo 0
' Group not found.
Exit Sub
End If
On Error GoTo 0
strGroupADsPath = "LDAP://" & objTrans.Get(ADS_NAME_TYPE_1779)

' Bind to the group object.
Set objGroup = GetObject(strGroupADsPath)

If (Operation = "Add") Then
If (objGroup.IsMember(strUserADsPath) = False) Then
objGroup.Add(strUserADsPath)
Else
' User already a member.
Exit Sub
End If
Else
If (objGroup.IsMember(strUserADsPath) = True) Then
objGroup.Remove(strUserADsPath)
Else
' User not a member.
Exit Sub
End If
End If
End Sub

--
Richard Mueller
MVP Directory Services
Hilltop Lab - http://www.rlmueller.net
--
  Reply With Quote
Reply


Thread Tools
Display Modes




Copyright 2006 SmartyDevil.com - Dies Mies Jeschet Boenedoesef Douvema Enitemaus -
666