jfaraone
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=C OM"
Set objUser = GetObject("LDAP://localhos t: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://localhos t: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.
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=C
Set objUser = GetObject("LDAP://localhos
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://localhos
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.
ASKER
500...
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.
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
ASKER
I get a Windows Script Host error on line 16 char 1 - "Unspecified error" Code = 80004005 Source = Provider.
ASKER
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("defaultNam ingContext ") & "' WHERE objectCategory='user' " & _
"AND ipPhone = ''"
to something like
objCommand.CommandText = _
"SELECT cn,dn FROM 'LDAP://CN=Users,DC=ADAM,D C=COM' WHERE objectCategory='user' " & _
"AND ipPhone = ''"
to see if you can connect to that instance.
Regards,
Rob.
objCommand.CommandText = _
"SELECT cn,dn FROM 'LDAP://" & objRootDSE.Get("defaultNam
"AND ipPhone = ''"
to something like
objCommand.CommandText = _
"SELECT cn,dn FROM 'LDAP://CN=Users,DC=ADAM,D
"AND ipPhone = ''"
to see if you can connect to that instance.
Regards,
Rob.
ASKER
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?
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
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.
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
ASKER
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?
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.
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
ASKER
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</includ e>
<include>sourceObjectGuid< /include>
<include>lastAgedChange</i nclude>
<include>sAMAccountName</i nclude>
<include>middleName</inclu de>
<include>ipPhone</include>
<include>mail</include>
<include>department</inclu de>
<include>givenName</includ e>
<include>manager</include>
<include>sn</include>
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</includ
<include>sourceObjectGuid<
<include>lastAgedChange</i
<include>sAMAccountName</i
<include>middleName</inclu
<include>ipPhone</include>
<include>mail</include>
<include>department</inclu
<include>givenName</includ
<include>manager</include>
<include>sn</include>
ASKER
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)(ip Phone=));c n,distingu ishedName; onelevel
Just wanted to verify that this was the expected contents of the pop-up window.
vbserror.jpg
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)(ip
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)(i pPhone=)); "
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.
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)(i
is not correct. It should be
strFilter = "(&(objectcategory=user)(!
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.
ASKER
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
Line: 10
Char: 1
Error: The directory property cannot be found in the cache.
Code: 8000500D
Source: Active Directory
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
Same error, but this time it occurs on line 9. I pasted your recent post verbatim for a line number reference...
ASKER
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...
(|(&(objectCatego ry=Person) (ipPhone=* ))(&(o bjectClass =user)(isD eleted=TRU E)))
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...
(|(&(objectCatego
ASKER
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.
Rob.
ASKER
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.
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.
ASKER