can anyone please help me with this?
here is what i have...
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
' 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)(cn=" & 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
' 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
adoCommand1.Properties("Page Size") = 100
adoCommand1.Properties("Timeout") = 30
adoCommand1.Properties("Cache Results") = False
' 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
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
--
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
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)(cn=" & 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
' 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.
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)(cn=" & 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.
1. does the project need to include variables to ADODB.Connection and
ADODB.Recordset?
quote:
> 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.
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.
"vb help" <vb he...@discussions.microsoft.com> wrote in message
news:51108413-EC24-4C2A...@microsoft.com...
> 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?
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.
>
> quote:
>> 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.
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 explicitly 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.
>
> 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 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.
>
> -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.
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.
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
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
Set adoRecordset1 = adoCommand1.Execute
Any ideas?
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")
--
' 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