Link to home
Start Free TrialLog in
Avatar of jfaraone
jfaraoneFlag for United States of America

asked on

Deleting ADAM (LDAP) objects based on attributes with vbscript.

I'm currently trying to create a vb script that will search through an OU in ADAM (Active directory application mode) and delete user accounts based on the ipPhone attribute.

Basically, if the field is empty, I want the account removed. All of our ipPhone numbers begin with "1"... Not sure if that helps.

I'm not sure how different dealing with ADAM through vbs is than dealing with AD, but the following script will show me what the ipPhone attribute is for a specified user.


On Error Resume Next
strUser = "CN=Generic User,CN=Users,DC=ADAM,DC=COM"
Set objUser = GetObject("LDAP://localhost:389/" & strUser)
WScript.Echo "Attributes for " & strUser
WScript.Echo "Phone: " & objUser.ipPhone

And this script will supposedly delete a specified user account:

'Delete user account in ADAM.
On Error Resume Next
strUser = "cn=Generic User"
strContainer = "cn=users,dc=ADAM,dc=com"
Set objContainer = GetObject("LDAP://localhost:389/" & strContainer)
objContainer.Delete "user", strUser

I'm just not very familiar with VB scripting and I'm not sure how to tie them together in order to achieve what I need to.
Avatar of jfaraone
jfaraone
Flag of United States of America image

ASKER

Updated point value to 300.
500...
Avatar of RobSampson
Hi, normally something like this would work for LDAP queries, but like you, I'm not sure about the ADAM interface....

This will only report on the users with no ipPhone value.  Once you have checked them, if you want to delete them, just uncomment the objContainer.Delete line.

Regards,

Rob.
Const ADS_SCOPE_SUBTREE = 2
 
Set objConnection = CreateObject("ADODB.Connection")
Set objCommand =   CreateObject("ADODB.Command")
objConnection.Provider = "ADsDSOObject"
objConnection.Open "Active Directory Provider"
Set objCommand.ActiveConnection = objConnection
 
objCommand.Properties("Page Size") = 1000
objCommand.Properties("Searchscope") = ADS_SCOPE_SUBTREE 
 
Set objRootDSE = GetObject("LDAP://RootDSE")
objCommand.CommandText = _
    "SELECT cn,dn FROM 'LDAP://" & objRootDSE.Get("defaultNamingContext") & "' WHERE objectCategory='user' " & _
        "AND ipPhone = ''"
Set objRecordSet = objCommand.Execute
 
objRecordSet.MoveFirst
Do Until objRecordSet.EOF
	strUser = objRecordSet.Fields("cn").Value
	strContainer = Replace(objRecordSet.Fields("cn").Value, strUser, "")
    Set objContainer = GetObject("LDAP://localhost:389/" & strContainer)
	WScript.Echo "Deleting " & strUser & " from " & objContainer.adsPath
	'objContainer.Delete "user", strUser
    objRecordSet.MoveNext
Loop

Open in new window

I get a Windows Script Host error on line 16 char 1 - "Unspecified error" Code = 80004005 Source = Provider.
Another comment; ADAM is designed so that you can run multiple instances on a single machine. It looks like you're connecting to localhost; it may need to specify "CN=Users,DC=ADAM,DC=COM" specifically, as this instance is named "ADAM". Does that make sense?
OK, so try modifying this bit:
objCommand.CommandText = _
    "SELECT cn,dn FROM 'LDAP://" & objRootDSE.Get("defaultNamingContext") & "' WHERE objectCategory='user' " & _
        "AND ipPhone = ''"


to something like
objCommand.CommandText = _
    "SELECT cn,dn FROM 'LDAP://CN=Users,DC=ADAM,DC=COM' WHERE objectCategory='user' " & _
        "AND ipPhone = ''"


to see if you can connect to that instance.

Regards,

Rob.
I think we're really close. It seems that we're just stuck at binding to my LDAP instance. The following script was included in a zip of example scripts MS offers for download. The following script is able to bind to my ADAM instance without problem.

Does this help?

'Bind to ADAM object.
strServer = "localhost" 'Server running ADAM instance.
strPort = "389" 'Optional
strObject = "CN=Users,DC=ADAMPAULO,DC=com" 'Optional
strPath = "LDAP://" & strServer & ":" & strPort & "/" & strObject
WScript.Echo "Attempting to bind to: " & strPath & VbCrLf
Set objADAM = GetObject(strPath)
If Err.Number = vbEmpty Then
    WScript.Echo "Bind succeeded."
    WScript.Echo "Name:    " & objADAM.Name
    WScript.Echo "Parent:  " & objADAM.Parent
    WScript.Echo "DN:      " & objADAM.distinguishedName
    WScript.Echo "Created: " & objADAM.whenCreated
Else
    WScript.Echo "ERROR: Bind failed."
End If

Open in new window

OK, so that script you posted doesn't execute a query, which should be able to be done, but I'll need to look for an example, unless the below works.....the script you provided does, however, give more clues on how to connect to your instance...

Regards,

Rob.
Const ADS_SCOPE_SUBTREE = 2
 
strServer = "localhost" 'Server running ADAM instance.
strPort = "389" 'Optional
strObject = "CN=Users,DC=ADAMPAULO,DC=com" 'Optional
strPath = "LDAP://" & strServer & ":" & strPort & "/" & strObject
 
Set objConnection = CreateObject("ADODB.Connection")
Set objCommand =   CreateObject("ADODB.Command")
objConnection.Provider = "ADsDSOObject"
objConnection.Open "Active Directory Provider"
Set objCommand.ActiveConnection = objConnection
 
objCommand.Properties("Page Size") = 1000
objCommand.Properties("Searchscope") = ADS_SCOPE_SUBTREE 
 
Set objRootDSE = GetObject("LDAP://RootDSE")
objCommand.CommandText = _
	"SELECT cn,dn FROM '" & strPath & "' WHERE objectCategory='user' AND ipPhone = ''"
Set objRecordSet = objCommand.Execute
 
objRecordSet.MoveFirst
Do Until objRecordSet.EOF
	strUser = objRecordSet.Fields("cn").Value
	strContainer = Replace(objRecordSet.Fields("cn").Value, strUser, "")
    Set objContainer = GetObject("LDAP://" & strServer & ":" & strPort & "/" & strContainer)
	WScript.Echo "Deleting " & strUser & " from " & objContainer.adsPath
	'objContainer.Delete "user", strUser
    objRecordSet.MoveNext
Loop

Open in new window

I get an error...


Line:20
Char:1
Error: Unspecified Error
Code: 80004005
Source: Provider

Is there any way I can set up a MeetingPlace session so we can just troubleshoot a few things?
Hi, I have been looking at some code from the Active Directory Cookbook, 2nd Edition, and it doesn't seem like this should be any different to the LDAP methods....

Rob.
' ------ SCRIPT CONFIGURATION ------
strServer = "localhost"
strPort = "389" 'Optional
'strObject = "CN=Users,DC=ADAMPAULO,DC=com" 'Optional
strPath = "LDAP://" & strServer & ":" & strPort
' ------ END CONFIGURATION --------
 
Set objRootDSE = GetObject("LDAP://" & strServer & ":" & strPort & "/RootDSE")
Set objLDAP = GetObject("LDAP://" & strServer & ":" & strPort & "/" & objRootDSE.Get("rootDomainNamingContext"))
 
strBase = "<LDAP://cn=USERS," & objRootDSE.Get("rootDomainNamingContext") & ">;"
strFilter = "(&(objectcategory=user)(ipPhone=));"
strAttrs  = "cn,distinguishedName;"
strScope  = "onelevel"
strQuery = strBase & strFilter & strAttrs & strScope
	
MsgBox "About to execute " & VbCrLf & strQuery
	
Set objConn = CreateObject("ADODB.Connection")
objConn.Provider = "ADsDSOObject"
objConn.Open "Active Directory Provider"
Set objRecordSet = objConn.Execute(strQuery)
 
Do Until objRecordSet.EOF
	strUser = objRecordSet.Fields("cn").Value
	strContainer = Replace(objRecordSet.Fields("cn").Value, strUser, "")
	Set objContainer = GetObject("LDAP://" & strServer & ":" & strPort & "/" & strContainer)
	WScript.Echo "Deleting " & strUser & " from " & objContainer.adsPath
	'objContainer.Delete "user", strUser
	objRecordSet.MoveNext
Loop

Open in new window

New error... this one seems promising.

Line: 9
Char: 1
Error: The directory property cannot be found in the cache.

Code: 8000500D
Source: Active directory

A couple of quick searches turned up this

http://www.microsoft.com/technet/scriptcenter/guide/sas_usr_zbco.mspx?mfr=true

which says that we're trying to query an attribute that doesn't contain a value. Which makes sense, I think.

Just to make sure I'm not leaving anything out, our ADAM server is not a complete copy of our AD. Only certain attributes were imported to keep our ADAM server as lightweight as possible.

Here is a list of the imported attributes, just so we can verify that we aren't querying an attribute that doesn't actually exist...

    <include>objectSID</include>    
    <include>sourceObjectGuid</include>
    <include>lastAgedChange</include>
    <include>sAMAccountName</include>
    <include>middleName</include>
    <include>ipPhone</include>
    <include>mail</include>
    <include>department</include>
    <include>givenName</include>
    <include>manager</include>
    <include>sn</include>

As suggested by the MS article, I added

On Error Resume Next

and the script ran at 99% for a good while with no noticeable changes to our ADAM directory, so I'm thinking it got hung up somewhere. One other note, when running the script the popup displays the following:

About to execute
(&(objectcategory=user)(ipPhone=));cn,distinguishedName;onelevel

Just wanted to verify that this was the expected contents of the pop-up window.
vbserror.jpg
Oh great! That's progress!  OK, so from here:
http://www.microsoft.com/technet/scriptcenter/guide/sas_usr_hqdo.mspx?mfr=true

it looks like the part of the query for the empty ipPhone:
strFilter = "(&(objectcategory=user)(ipPhone=));"

is not correct.  It should be
strFilter = "(&(objectcategory=user)(!ipPhone=*));"

but if that doesn't work, you could also try the IsNull method described in that article too.

Oh, and by the way, currently it won't delete account, it will just tell you whether it *would* or not.  This line is commented out:
      'objContainer.Delete "user", strUser

so once you're happy with the results, remove the apostrophe, and accounts will start to be deleted.

Regards,

Rob.
I receive a windows script host error:

Line: 10
Char: 1
Error: The directory property cannot be found in the cache.

Code: 8000500D
Source: Active Directory
ASKER CERTIFIED SOLUTION
Avatar of RobSampson
RobSampson
Flag of Australia image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Same error, but this time it occurs on line 9. I pasted your recent post verbatim for a line number reference...
Well, I wasn't able to resolve this via vbs, but I found a way to accomplish this via ADAM itself.

I used the  parameter in ADAM to a) filter users on import, and b) delete users that don't exist in Active directory. In case anyone else has the same problem, here is the object-filter I used...

(&#124;(&amp;(objectCategory=Person)(ipPhone=*))(&amp;(objectClass=user)(isDeleted=TRUE)))

Didn't solve my problem, but A for effort. Thanks!
Thanks for the grade.  Very strange that such a filter works directly, but not via VBS....

Rob.
I should also point out that the whole purpose of this ordeal was to filter users in a custom LDAP directory for our Unified Communications Manager (formerly CallManager) phone system. The system itself as of version 6.x only supports filtering based on OU's, and I didn't want to restructure my OU's into IP phone and non-IP phone containers...

For some reason, LDAP import filtering was removed after CM 5.x... hopefully this will allow me to keep a current list of users with valid internal phone numbers.

At any rate, hope this helps anyone else with the same issue.