Query disabled users and delete their memberof associations

Discussion in 'Active Directory' started by bryan, Feb 8, 2007.

  1. bryan

    bryan Guest

    Hi guys

    Just a quick Q.
    I need to query a particular OU "disabled users" with all the disabled user
    accounts and have all their memberof details deleted.

    I can get the disabled user accounts fine, I just need a way to pipe into
    DSMOD (or another method) and delete the groups that they are members of
    (just leaving the primary group, I.e. Domain Users)-

    I have looked at the -RMMBR switch but this seems to apply to a group itself.
    Is there a quick way of doing this.

    Appreciate any help on this

    Many thanks
    Bry
     
    bryan, Feb 8, 2007
    #1
    1. Advertisements

  2. bryan

    Erik Cheizoo Guest

    May I ask why you want to do this.
    Normally, users get disabled because if they rejoin (or a mistake has been
    made), the account can be quickly reinstated.
    If you remove the group memberships, what's the use of disabling the
    accounts? Why don't you just delete them?

    This isn't as simple as it sounds. The MemberOf attribute is a so called
    back-linked attribute. It cannot be modified on the user object and it is
    not replicated. You have to modify the group object and remove the user from
    there. Each individual DC will then notice this membership change and update
    the MemberOf attribute on the user object.

    The 2nd problem arises in a multi-domain forest. On the user object, the
    MemberOf attribute contains only the groups from its own domain. Group
    memberships from other domains are not shown here. Therefore, you have to
    look at each group in the entire forest to see if the user is a member...
    Universal Group Memberships are only shown when you talk to a Global
    Catalog.

    --
    Kind regards,

    Erik Cheizoo
    eXcellence & Difference - we keep your business running
    ============================================
    Always test in a non-production environment before implementing
    Guidelines for posting: http://support.microsoft.com/?id=555375
    ============================================
     
    Erik Cheizoo, Feb 8, 2007
    #2
    1. Advertisements

  3. bryan

    bryan Guest

    Hi Erik

    Thanks for getting back so quick.

    That's a valid point and one I have raised with the Co I am currently
    contracting at. They are still in the process of determining their 'formal'
    account deletion process.

    There is a 'temporary' policy in place to ensure that at the very least any
    newly disabled users have their memberships removed, but there is still a
    whole bunch of legacy disabled accounts (not pretty, I know [but their rules
    and as a contractor, I am bound to follow] :)

    The reason I would like to be able to do this, is as a sys admin, I keep
    getting requests for membership removal because some are in distribution
    groups and obviously get NDR'd...

    I do have a multi-domain environment utilising Universal Groups.

    I will have to take a look at ADMODIFY? Maybe this can assist?

    Again, thanks for your reply - Any further info/pointers, very welcomed.

    Many thanks
    Bry
     
    bryan, Feb 8, 2007
    #3
  4. bryan

    Joe Kaplan Guest

    Basically, you can only modify the group's member attribute, so you need to
    get the DN of each group from memberOf and then go back and modify each of
    those to remove the user. I'm not sure if you can easily script this with
    command lines tools. It might be more straightforward to write an ADSI
    script that does it.

    Joe R. might know a slick way to get ADFind/ADModify to do it as a one liner
    though. :)

    Joe K.

    --
    Joe Kaplan-MS MVP Directory Services Programming
    Co-author of "The .NET Developer's Guide to Directory Services Programming"
    http://www.directoryprogramming.net
    --
     
    Joe Kaplan, Feb 8, 2007
    #4
  5. As discussed in other forums, group stuff is a bit trickier than the
    average. To truly comply to the intent, get the user out of all groups,
    there really is no way to do a single command line and actually to it
    unless there is a tool built specifically to hide all of the logic.
    Personally I would tackle this with a perl script and it would chase
    group nesting, DLs, cross domain memberships, etc.

    --
    Joe Richards Microsoft MVP Windows Server Directory Services
    Author of O'Reilly Active Directory Third Edition
    www.joeware.net


    ---O'Reilly Active Directory Third Edition now available---

    http://www.joeware.net/win/ad3e.htm
     
    Joe Richards [MVP], Feb 9, 2007
    #5
  6. bryan

    bryan Guest

    Hi guys

    Many thanks for your replies - Most interesting..!
    As i'm not a PERL man, I suppose I might be tasked with a manual process for
    now...

    Are there any pointers where I might find a starting point for a perl script
    that may do what I need?

    Appreciate all feedback.

    Thanks again guys
    Bry
     
    bryan, Feb 9, 2007
    #6
  7. I had a similar request for this, but in my case "they" wanted to keep the
    membership somewhere so that it could easliy be retained. I took a
    developer aside and told him this (this isn't pretty, but we had certain
    security requirements and political crap that had to be dealt with):

    Write some code that does the following:

    -- Takes the user's sAMAccountName as input
    -- Grab the memberOf attribute and dump the contents into an array
    -- Disable the user object
    -- Get the RID of each group in the array, and concatenate into a semi-colon
    delimited string value.
    -- Write that value to an unused string attribute of the user.
    -- If the string is > 1000 characters, split it and use another attribute.
    -- Connect to each group in that list and remove the user object.


    We had three attributes that would be used for this.

    It hasn't been implemented yet.

    LOL.


    As others have said, you need to code this.
     
    Paul Williams [MVP], Feb 9, 2007
    #7
  8. Paul Williams [MVP], Feb 9, 2007
    #8
  9. bryan

    bryan Guest

    Hi Paul

    Thanks for the pointers - I shall beaver away at this :) - 'If' I manage to
    get my script to work as I want, I shall of course back up here, as i'm sure
    i'm not alone on this...

    I'll keep you (ALL) posted.

    Many thanks
    Bry
     
    bryan, Feb 9, 2007
    #9
  10. bryan

    bryan Guest

    Hi

    Ok - I have a .VBS that does what I want on an individual user obj (I have
    tested in my test env [just leaves the primary group [[in my case, Domain
    Users]]]).

    What I need to work out now, is how to query the disabled users OU and put
    the user DNs as an array (thanks Paul) into this vbscript.

    ==================================================

    Const ADS_PROPERTY_DELETE = 4
    Const E_ADS_PROPERTY_NOT_FOUND = &h8000500D

    Set objUser = GetObject("LDAP://CN=USER1,OU=Disabled User Accounts
    Test,DC=MyDomain, DC=com")
    arrMemberOf = objUser.GetEx("MemberOf")

    If Err.Number = E_ADS_PROPERTY_NOT_FOUND Then
    WScript.Echo "No Group Memberships Found"
    WScript.Quit

    End If

    For each group in arrMemberOf
    Set objGroup = GetObject("LDAP://" & Group)
    objGroup.PutEx ADS_PROPERTY_DELETE, _
    "member", Array("CN=USER1,OU=Disabled User Accounts Test,DC=MyDomain,
    DC=com")

    objGroup.SetInfo
    Next


    ==================================================


    Any ideas? - I am still researching this as well.

    Many thanks
    Bry
     
    bryan, Feb 9, 2007
    #10
  11. Hey Paul do you have multiple domains and use domain local groups? If
    so, you need to add the step

    -- Connect to every domain and search through all of the groups for each
    user you are concerned about.

    --
    Joe Richards Microsoft MVP Windows Server Directory Services
    Author of O'Reilly Active Directory Third Edition
    www.joeware.net


    ---O'Reilly Active Directory Third Edition now available---

    http://www.joeware.net/win/ad3e.htm
     
    Joe Richards [MVP], Feb 10, 2007
    #11
  12. Thankfully we don't have multiple domains, which means I can avoid such a
    royal PITA! ;-)

    We made a concious decision to have one big fat domain, as opposed to four
    or five smaller ones. Which is simplifying the design and deployment of a
    number of large enterprise apps.
     
    Paul Williams [MVP], Feb 12, 2007
    #12
  13. Use ADO to search for disabled users. The LDAP query is (one line):

    (|(&(objectCategory=person)(objectClass=user)(userAccountControl:1.2.840.113556.1.4.803:=2))
    (&(objectCategory=person)(objectClass=inetOrgPerson)(userAccountControl:1.2.840.113556.1.4.803:=2)))

    Or, you may want to simplify that to (one line):

    (&(objectCategory=person)(userAccountControl:1.2.840.113556.1.4.803:=2))


    Here's a start on how to use ADO:
    -- http://www.rlmueller.net/ADOSearchTips.htm
    -- http://techtasks.com/code/viewbookcode/1581


    Wrap your existing code as a Sub and then call the sub from within the loop
    that iterates the result set.
     
    Paul Williams [MVP], Feb 12, 2007
    #13
  14. Yep it absolutely does. :)

    --
    Joe Richards Microsoft MVP Windows Server Directory Services
    Author of O'Reilly Active Directory Third Edition
    www.joeware.net


    ---O'Reilly Active Directory Third Edition now available---

    http://www.joeware.net/win/ad3e.htm
     
    Joe Richards [MVP], Feb 12, 2007
    #14
  15. bryan

    bryan Guest

    Hi guys

    Sorry for delay, I have been away.
    I shall look at the ADO query and get back once I have tested.

    Many many thanks
    Bry
     
    bryan, Feb 14, 2007
    #15
  16. bryan

    bryan Guest

    Hi Paul / Joe

    I have got this script now and would appreciate a quick look over to see if
    I am heading in the right direction, as I do not have access to my test AD
    today to start testing...

    This really is getting beyond my script skillset (but thouroughly enjoyable
    though) :) so I appreciate any feedback as always..

    Kind rgds
    Bry



    ******************
    Option Explicit

    Dim objDSE, objConnection, objCommand, objRecordset, i

    Set objDSE = GetObject("LDAP://rootDSE")

    Set objConnection = CreateObject("ADODB.Connection")
    objConnection.Provider = "ADsDSOObject"
    objConnection.Open

    Set objCommand = CreateObject("ADODB.Command")
    Set objCommand.ActiveConnection = objConnection

    objCommand.CommandText = _
    (|(&(objectCategory=person)(objectClass=user)(userAccountControl:1.2.840.113556.1.4.803:=2)) _
    (&(objectCategory=person)(objectClass=inetOrgPerson)(userAccountControl:1.2.840.113556.1.4.803:=2)))

    Set objRecordset = objCommand.Execute

    i = 0
    If Not objRecordset.EOF Then
    While Not objRecordset.EOF
    i = i + 1
    Call ModifyObject(objRecordset.Fields("arrMemberOf"))
    objRecordset.MoveNext
    Wend
    WScript.Echo "Modified " & i & " objects"
    Else
    WScript.Echo "No objects to modify"
    End if

    objRecordset.Close
    objConnection.Close

    Sub ModifyObject(strObjectUser)
    Dim objUser

    Set objUser = GetObject("LDAP://" & strObjectUser"))
    arrMemberOf = objUser.GetEx("MemberOf")

    If Err.Number = E_ADS_PROPERTY_NOT_FOUND Then
    WScript.Echo "No Group Memberships Found"
    WScript.Quit

    End If

    For each group in arrMemberOf
    Set objGroup = GetObject("LDAP://" & Group)
    objGroup.PutEx ADS_PROPERTY_DELETE, _
    "member", Array("strObjectUser")

    objGroup.SetInfo
    End Sub



    'Const ADS_PROPERTY_DELETE = 4
    'Const E_ADS_PROPERTY_NOT_FOUND = &h8000500D



    ******************
     
    bryan, Feb 19, 2007
    #16
  17. bryan

    bryan Guest

    Hi guys

    I have been testing the following script and it is failing on line <41, 58>
    "microsoft vbscript compilation error: Unterminated string constant"

    Any ideas?

    Also, are you able to sanitise the script itself to see if my logic is
    correct?

    Much thanks in advance

    Cheers
    Bry



    ***********************************************

    Option Explicit

    Dim objDSE, objConnection, objCommand, objRecordset, i

    Set objDSE = GetObject("LDAP://rootDSE")

    Set objConnection = CreateObject("ADODB.Connection")
    objConnection.Provider = "ADsDSOObject"
    objConnection.Open

    Set objCommand = CreateObject("ADODB.Command")
    Set objCommand.ActiveConnection = objConnection

    objCommand.CommandText = _
    "<LDAP://DC=TEST,DC=cp,DC=uk>;" & _

    "(&(objectCategory=person)(objectClass=user)(userAccountControl:1.2.840.113556.1.4.803:=2))"


    Set objRecordset = objCommand.Execute

    i = 0
    If Not objRecordset.EOF Then
    While Not objRecordset.EOF
    i = i + 1
    Call ModifyObject(objRecordset.Fields("arrMemberOf"))
    objRecordset.MoveNext
    Wend
    WScript.Echo "Modified " & i & " objects"
    Else
    WScript.Echo "No objects to modify"
    End if

    objRecordset.Close
    objConnection.Close

    Sub ModifyObject(strObjectUser)
    Dim objUser

    Const ADS_PROPERTY_DELETE = 4
    Const E_ADS_PROPERTY_NOT_FOUND = &h8000500D

    Set objUser = GetObject("LDAP://" & strObjectUser"))
    arrMemberOf = objUser.GetEx("MemberOf")

    If Err.Number = E_ADS_PROPERTY_NOT_FOUND Then
    WScript.Echo "No Group Memberships Found"
    WScript.Quit

    End If

    For each group in arrMemberOf
    Set objGroup = GetObject("LDAP://" & Group)
    objGroup.PutEx ADS_PROPERTY_DELETE, _
    "member", Array("strObjectUser")

    objGroup.SetInfo
    End Sub

    ***********************************************
     
    bryan, Feb 23, 2007
    #17
  18. Joe picked out the typo in the other thread -


    Needs to be

    Set objUser = GetObject("LDAP://" & strObjectUser)


    Basically, you're making the brackets a string. Which you don't want to do.

    There's also too many closing brackets. You only need one, for the
    getObject call.
     
    Paul Williams [MVP], Feb 26, 2007
    #18
    1. Advertisements

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments (here). After that, you can post your question and our members will help you out.