Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations gkittelson on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

ldap query - can't get desired values

Status
Not open for further replies.

kokser

Programmer
Sep 25, 2009
90
DK
I decided that it was a pita to change the script for every domain, so googling aroud I found that almost everywhere the scripts finds the information itself. This part was easy to get working, however, it no longer pulls out all the values I need.

Current functioning code
Code:
objCommand.CommandText = _
"SELECT Name, sAMAccountName, mail, proxyAddresses, homeDirectory, homeDrive, memberOf, scriptPath, ObjectClass, UserAccountControl FROM 'LDAP://dc=AdvizorIT,dc=local' WHERE objectCategory='Person'"
Set objRecordSet = objCommand.Execute


Current non-functioning code
Code:
Set rootDSE = GetObject("LDAP://RootDSE")
DomainContainer = RootDSE.Get("defaultNamingContext")

ldapStr = "<LDAP://" & DomainContainer & ">;(objectCategory=person);adspath;subtree"
Set objRecordSet = conn.Execute(ldapStr)

I can't get this output, like I could before
Code:
Wscript.Echo objRecordSet.Fields("Name").Value


The error:
Code:
Item Cannot be found in the collection corresponding to the requested name or ordinal

I understand that it cannot do this due to not having pulled out all the values like before, but I cannot figure out how to pull these values out with the new query.

Any ideas?
 
the first bit of code you presented it wholly different from the second, it uses different methods and objects etc, perhaps you should consider using the same method but just do a string replace based on the result of the DomainContainer = RootDSE.Get("defaultNamingContext")

at least then you are comparing apples to apples, i am willing to bet the farm that the below doesnt work for you either:

Set rootDSE = GetObject("LDAP://RootDSE")
DomainContainer = RootDSE.Get("defaultNamingContext")

ldapStr = "<LDAP://>dc=AdvizorIT,dc=local;(objectCategory=person);adspath;subtree"
Set objRecordSet = conn.Execute(ldapStr)
 
ah, sorry I forgot to write back. I just found that I made a little error when trying to merge them.

Code:
Set rootDSE = GetObject("LDAP://RootDSE")
DomainContainer = RootDSE.Get("defaultNamingContext")

objCommand.CommandText = _
"SELECT Name, sAMAccountName, mail, proxyAddresses, homeDirectory, homeDrive, memberOf, scriptPath, ObjectClass, UserAccountControl FROM 'LDAP://" & domaincontainer & "' WHERE objectCategory='Person'"
Set objRecordSet = objCommand.Execute
Actually works just fine :)
 
exactly my point which is why your post of non functioning code is a little confusing

Current non-functioning code:

CODE
Set rootDSE = GetObject("LDAP://RootDSE")
DomainContainer = RootDSE.Get("defaultNamingContext")

ldapStr = "<LDAP://" & DomainContainer & ">;(objectCategory=person);adspath;subtree"
Set objRecordSet = conn.Execute(ldapStr)
 
Another problem I have, is that I can't get the value of 'objectClass'.

Error:
Code:
Error: Expected statement
Code: 800A0400
Source: compilation error

Code:
Code:
Dim objFSO, objConnection, objCommand, objRecordSet, WriteText, arrProxyAddresses, arrMemberOf, strGrp

set objFSO = CreateObject("Scripting.FileSystemObject")
If objFSO.FileExists("test.txt") Then
objFSO.DeleteFile("test.txt")
end if

Set objConnection = CreateObject("ADODB.Connection")
Set objCommand = CreateObject("ADODB.Command")
objConnection.Provider = "ADsDSOObject"
objConnection.Open "Active Directory Provider"
Set objCommand.ActiveConnection = objConnection

Set rootDSE = GetObject("LDAP://RootDSE")
DomainContainer = RootDSE.Get("defaultNamingContext")

objCommand.CommandText = _
"SELECT Name, sAMAccountName, mail, proxyAddresses, homeDirectory, homeDrive, memberOf, scriptPath, ObjectClass, UserAccountControl FROM 'LDAP://" & domaincontainer & "' WHERE objectCategory='Person'"
Set objRecordSet = objCommand.Execute

Set WriteText = objFSO.OpenTextFile("test.txt", 8, true)

objRecordSet.MoveFirst
While Not objRecordSet.EOF
	if UserAccountControl <> 514 Then
		Case Select objRecordSet.Fields("ObjectClass").Value
			Case "User"
				WriteText.WriteLine("Username" & vbTab & ":" & vbCr & objRecordSet.Fields("Name")
			Case "Contact"
				WriteText.WriteLine("Contact" & vbTab & ":" & vbCr & objRecordSet.Fields("Name")
'		WriteText.WriteLine("Name" & vbTab & vbTab & ":" & objRecordSet.Fields("Name").Value & vbCr)
		WriteText.WriteLine("Account" & vbTab & vbTab & ":"  & objRecordSet.Fields("sAMAccountName").Value & vbCr)
		WriteText.WriteLine("Mail Addresser" & vbTab & ":" & vbCrLf & vbTab & vbTab & "Primær:" & objRecordSet.Fields("mail").Value & vbCr)
			arrProxyAddresses = objRecordSet.Fields("proxyAddresses")
			if isArray(objRecordSet.Fields("proxyAddresses")) Then
				For Each ProxyAddress in arrProxyAddresses
					WriteText.WriteLine (vbTab & vbTab & ProxyAddress & vbCr)
				Next
			End if
		WriteText.WriteLine("Memberships" & vbTab & ":" & vbCr)
			arrMemberOf = objRecordSet.Fields("memberOf")
			if isArray(objRecordSet.Fields("memberOf")) Then
				For Each aMemberOf in arrMemberOf
					StrGrp = Right(aMemberOf,Len(aMemberOf)-3)
					StrGrp = Left(StrGrp,InStr(StrGrp,",")-1)
					WriteText.WriteLine (vbTab & vbTab & ":" & StrGrp & vbCr)
				Next
			End if
		WriteText.WriteLine("Homedir" & vbTab & vbTab & ":" & objRecordSet.Fields("homeDirectory").Value & vbCr)
		WriteText.WriteLine("Homedrive" & vbTab & ":" & objRecordSet.Fields("homeDrive").Value & vbCr)
		WriteText.WriteLine("Scriptpath" & vbTab & vbTab & ":" & objRecordSet.Fields("scriptPath").Value)
		WriteText.WriteLine(vbCr & "--------------------------------------------------------------------------")
	objRecordSet.MoveNext
	End if
wend

WriteText.WriteLine("Total Users: " & objRecordSet.RecordCount)

WriteText.Close
Set WriteText = NOTHING
Set objFSO= NOTHING

WScript.Echo "Done"
The problem is my "case". I can't echo the value of objRecordSet.Fields("ObjectClass").Value, so obviously my case doesn't work either, but I can't quite figure out how I can determine whether it's a user or a contact.

Got any ideas?
 
its objectClass not ObjectClass,
i would definitely think objectClass is a required property so it will have a value, if you want echo it then it implies it cannot be implicitly converted to a string....perhaps Not IsNull, IsArray(), Join()
 
afaik, vbscript isn't case sensitive.

and exactly my point, objectclass is not a string, which is why I'm not quite sure how to echo (or WriteText.WriteLine) it. Weird thing is, when I export it through ldifde/csvde it comes out as a string, so I'm on bare ground right now.
 
vbscript isnt case sensitive? really? i think you are limiting your context in the extreme. you may very find other OLE providers are case sensitive. you look in adsiedit and you will clearly see that properties typically start with lowercase, but dont take my word for it.

<q>objectclass is not a string</q>, then why are you treating it like one?

i have pointed you in the direct you need to go in with regards my last post. perhaps you should re-read it
 
Is it possible to not export the contacts instead?

I tried with
Code:
"SELECT Name, sAMAccountName, mail, proxyAddresses, homeDirectory, homeDrive, memberOf, scriptPath, ObjectClass, UserAccountControl FROM 'LDAP://" & domaincontainer & "' WHERE (&(objectCategory='Person')(objectClass='User')"
but this doesn't work.
 
i thought we had established that objectClass was not directly a string Type, it is a multistring array ish type. so, Where objectClass='User' wouldnt work on the face of it as objectClass is not a string (the LDAP provider might be nice to you and so a compare to the contents of the multistring but i guess you have discovered that it wont)

not wanting to divert you from your current path the previous posts which mentioned the use of IsArray() and Join() should be enough to take the returned array and deal with the contents
 
after a quick google my assertions would appear to be incorrect in some regards, the LDAP provider will do something nice with objClass='User' despite it being multivalued, see this info i grabbed from InformIT

Let’s start with the LDAP filter. Our goal is to build an LDAP filter that will find exactly what we want and that will be as efficient as possible. A few attributes in Active Directory distinguish user objects from other object types that we can use to build a filter:

objectCategory
objectClass
sAMAccountName
sAMAccountType
The objectCategory attribute has the advantage of being single-valued and indexed by default on all versions of Active Directory. This attribute is meant to be used to group common types of objects together so that we can search across all of them. Many of the schema classes related to users share the same value of person as their object category. While this is useful for searches in which we want to find information across many different types of user-related objects, it is not as useful for finding the user objects we typically care about (which are usually security principals). For example, in Active Directory, since both user and contact classes share the same objectCategory value of person, it alone will not tell them apart.

The objectClass attribute seems like a no-brainer, as (objectClass=user) will always find user objects exclusively. The problem here is that in many forests, the objectClass attribute is not indexed and it is always multivalued. As we know from the section titled Optimizing Search Performance, in Chapter 5, we generally want to try to avoid searches on nonindexed attributes, so using objectClass alone in a filter might not be the most efficient solution. This is why we see a lot of samples that search for user objects using an indexed filter like this:

(&(objectCategory=person)(objectClass=user))This will get the job done, but we can do even better than this.

NOTE

Behavior Change in Windows Server 2003

Windows Server 2003 Active Directory indexes the objectClass attribute by default, so this rule really only applies to Windows 2000 Active Directory now. Additionally, the schema administrators for your domain may have already indexed it, so check the schema before making assumptions.

One key difference between contact objects and user objects in Active Directory is that user objects have a sAMAccountName attribute that is indexed by default. Thus, we could build a filter like this:

(&(objectCategory=person)(sAMAccountName=*))This will separate the contacts from the users effectively. However, another approach is available that can find user objects directly, and it may be the most efficient technique for Active Directory:

(sAMAccountType=805306368)Using the sAMAccountType attribute with a value of 805306368 accesses a single-valued, indexed attribute that uniquely defines user objects. The only downside here is that this attribute is not well documented, so it may
 
youre not using the LDAP provider type string searching (technical term not), you are using

Set objConnection = CreateObject("ADODB.Connection")
Set objCommand = CreateObject("ADODB.Command")
objConnection.Provider = "ADsDSOObject"
objConnection.Open "Active Directory Provider"
Set objCommand.ActiveConnection = objConnection

which may not be as nice to you
 
i dont mean to be cheeky with you but i seem to recall replying in a post to about reading through your code. the large piece of code you posted above includes:

arrProxyAddresses = objRecordSet.Fields("proxyAddresses")
If isArray(objRecordSet.Fields("proxyAddresses")) Then
For Each ProxyAddress in arrProxyAddresses
WriteText.WriteLine (vbTab & vbTab & ProxyAddress & vbCr)
Next
End if

this is a good example of how to access the contents of a multistring value/array.

i would guess this is the same logic you will need to apply to your objectClass field?

 
Since only users have sAMAccountName(s), should it not be possible to do a
Code:
if (sAMAccountName = *) Then
	WriteText.WriteLine("Name" & vbTab & vbTab & ":" & objRecordSet.Fields("Name").Value & vbCr)
else
	WriteText.WriteLine("Contact" & vbTab & vbTab & ":" & objRecordSet.Fields("Name").Value & vbCr)
End if
or something along the lines of that? I just tried this as well as
Code:
if (sAMAccountName <> 0) Then
if (sAMAccountName > 0) Then
but with the first I get a syntax error, and the 2 next everything is just a contact.
 
Figured I might add that I also tried with
Code:
if (sAMAccountType=805306368) Then
but this didn't work either. I'll keep looking around.
 
quite annoying you can't edit posts, but anyway! I figured I'd try to echo the samaccounttype and indeed this worked. The contacts samaccounttype value is Null, but again my ideas keep failing.
Code:
if (sAMAccountType = Null) Then

I have made sure to export the value in the ldap string od course.

Code:
"SELECT Name, sAMAccountName, sAMAccountType, mail, proxyAddresses, homeDirectory, homeDrive, memberOf, scriptPath, UserAccountControl FROM 'LDAP://" & domaincontainer & "' WHERE (&(objectCategory='Person')(objectClass='User')
 
to be honest my head hurts, you seem to skip from one problem to the next, just go back to where you had the first problem and solve it, you will never learn anything unless you take that approach
 
My first problem has been solved. I solved it by finding a way that looks like it's a lot easier. I'm not looking for the easy way out, I'm looking for the simplest code, and my new approach seems a lot more simple, if it just worked.
 
try

"SELECT Name, sAMAccountName, mail, proxyAddresses, homeDirectory, homeDrive, memberOf, scriptPath, ObjectClass, UserAccountControl FROM 'LDAP://" & domaincontainer & "' WHERE (&(objectCategory='Person')(sAMAccountName='*')
 
That seems to be a mixture of SQL-dialect and LDAP-dialect. Literally, it would be this in sql-dialect, rightly or wrongly.
[tt]
"SELECT Name, sAMAccountName, mail, proxyAddresses, homeDirectory, homeDrive, memberOf, scriptPath, ObjectClass, UserAccountControl FROM 'LDAP://" & domaincontainer & "' WHERE [blue]objectCategory='Person' and sAMAccountName='*'" [/blue]
[/tt]
SQL-dialect grammar can be found here.
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top