I need to delete a user from Domain Users in AD using VB

Posted on 2005-04-25
Last Modified: 2008-01-09
For security reasons, I need to delete a user from the Domain Users group in AD. I already have them in an OU with their Primary Group set to a special group.

Here's the code I am using to create them, and assign them to the new group.

    Private Sub AddUserToAD()
        'This code adds a NEW USER to a specified OU.
        'Useful in constructing LDAP "Paths":
        'cn = Computer, Contact, Container, Group, Print Queue, and User objects
        'ou = Organizational Unit
        'dc = Domain controller name (example dc=mydomain,dc=com for
        'o = Domain name

        'First, connecto to the Active Directory.
        Dim sDomain As String = "gafcon"
        Dim sUsername As String = "admin"
        Dim sPassword As String = "password"

        Dim dom As DirectoryEntry = New DirectoryEntry("LDAP://" & sDomain, sUsername, sPassword)

        'Connect to the specific OU
        Dim ouToAddTo As DirectoryEntry = dom.Children.Find("OU=SHAREPOINT")

        'Use the Add method to add a user in an organizationalUnit.
        Dim newUser As DirectoryEntry = ouToAddTo.Children.Add("CN=Cliff", "User")

        'Set the core AD properties
        ' Pre-Windows 2000 Name
        newUser.Properties("sAMAccountName").Value = "Cliff"
        ' User Logon Name
        ' Email
        newUser.Properties("mail").Value = "Cliff@gafcon.local"
        ' First Name
        ' Initials
        ' Last Name
        ' Display Name
        newUser.Properties("displayName").Add("Cliff West")
        ' Description
        newUser.Properties("description").Add("Added by " & _

        'Create the account

        'set the password for the new user
        newUser.Invoke("setPassword", "password")

        Dim userACFlags As Object = newUser.Properties("userAccountControl").Value
        newUser.Properties("userAccountControl").Value = userACFlags Or &H200 Or &H10000 Xor &H2

        'Commit the changes

        Dim grp As DirectoryEntry = New DirectoryEntry("LDAP://" & sDomain, sUsername, sPassword)
        Dim addMe As DirectoryEntry = grp.Children.Find("CN=Extranet", "group")


        'Dim addMe As DirectoryEntry = grp.Children.Find("CN=Extranet", "group")
        If Not addMe.Properties.Contains("PrimaryGroupToken") Then
            addMe.RefreshCache(New String() {"PrimaryGroupToken"})
        End If

        newUser.Properties("PrimaryGroupID").Value = addMe.Properties("PrimaryGroupToken").Value

    End Sub
Question by:jawhitmoyer

    Author Comment

    I tried adding this, but I get an error saying unknown object:

    sDomain = "DC=GAFCON,DC=LOCAL"
    Dim grp2 As DirectoryEntry = New DirectoryEntry("LDAP://" & sDomain, sUsername, sPassword)
    addMe = grp2.Children.Find("CN=Domain Users", "group")
    LVL 20

    Expert Comment

    Jim, you are almost there. But first you need to understand a couple of things. Let say you want SecurityGroupA to replace "Domain Users" primary group for UserA. You're allowed to do that if SecurityGroupA already has UserA as its member. Other than that you'll get exception. So essentially your code needs to check whether the above condition is satisfied or manually set UserA to be SecurityGroupA's member. Then the next step is to bind to "Domain Users" group and manually remove UserA from its "member" attribute.

    Pseudo code:

    securityGroupA = getGroupFromAD()
    If userA is not a member of securityGroupA Then
       add UserA as member of securityGroupA
    End If
    Replace "Domain User" with securityGroupA
    domainUsers = getGroupFromAD()
    Remove UserA from domainUsers membership.

    Please try that and let me know if you have any problem.

    Author Comment

    By default all users are created in the Domain Users group. That's why I tought I would just need the code above to remove them. I get an error because I am not finding the group in AD. Is Domain Users group in the root of AD, or do I need to look for it something like "CN=USERS"?

    LVL 20

    Expert Comment

    Ok, you have the code to replace primary group with another group and you know how to remove a user's membership from a group. Now I'll tell you how to get a user's primary group. "Domain Users" group as the default primary group for all user objects exists in every domain in the forest. That means, if you have multiple domains in your AD forest you can't exactly tell what "Domain Users" group map to what user without knowing where the user comes from. The "shortest way" (and the best performance can be achieved) to determine the primary group of a user is to build an sid bind string for the group object from the domain rid component of the user's sid and the PrimaryGroupID attribute on the user object. Then use the sid string to bind to the group using DirectoryEntry class.

    I guess, there's no easy way to explain this without actually posting some code. I have the code handy and it does exactly what you need, but...the code is written in c# and it's involving some pointer operations. For that I'm not sure how you're going to convert it to VB.NET. But I have something for your consideration:

    1. Compile the c# code into a separate assembly and call it from your VB.NET project.
    2. If point 1. is not an option, throw another question to VB.NET TA about the code conversion problem, someone might be able to show you a workaround
    3. Forget about the code, open adsiedit via mmc snap-ins and copy the "distinguishedName" attribute of the default "Domain Users" group and hard code it in your code (this won't be so simple if you have multiple domains).
    4. Comeback here, there's another workaround. No pointer operation, whatsoever but I don't have it handy and I can't promise you'll see any  good performance from it. Another bad news is you have to write and test more lines of code if you want to go with this.

    Please reply and let me know which one are you able to go with.
    LVL 20

    Accepted Solution

    And of course the code:

          using PSID = System.IntPtr;
          using BOOL = System.Int32;

          [DllImport("advapi32.dll", CharSet=CharSet.Auto, SetLastError=true)]
          static extern BOOL ConvertSidToStringSid(
                PSID pSID,
                out IntPtr pStringSid

          private static String hostName = "";
          private static String provider = "LDAP";
          private static String ldapPath = String.Format( "{0}://{1}", provider, hostName );

          public DirectoryEntry GetPrimaryGroup( DirectoryEntry user )
                if ( user == null )
                      throw new ArgumentNullException("user");
                if ( !user.Properties.Contains("objectSid") || !user.Properties.Contains("primaryGroupID") )
                      user.RefreshCache( new String[] {"primaryGroupID", "objectSid"} );
                int primaryGroupId = (int) user.Properties["PrimaryGroupID"].Value;
                byte[] userSid = user.Properties["objectSid"].Value as byte[];
                byte[] primaryGroupSid = BuildPrimaryGroupSID( userSid, primaryGroupId );
                String adsPath = String.Format( "{0}/<SID={1}>", ldapPath, UnsafeConvertSidToStringSid(primaryGroupSid) );

                DirectoryEntry pg = new DirectoryEntry();
                pg.Path = adsPath;
                pg.Username = user.Username;
                pg.Password = user.Password;
                pg.AuthenticationType = user.AuthenticationType;
                String dnpg;
                      dnpg = (String) pg.Properties["distinguishedName"].Value;
                      pg.Close(); pg.Dispose();
                return new DirectoryEntry(String.Format("{0}/{1}", ldapPath, dnpg), user.Username, user.Password, user.AuthenticationType );

          private byte[] BuildPrimaryGroupSID( byte[] userSid, int primaryGroupId )
                byte[] rid = BitConverter.GetBytes( primaryGroupId );
                for ( int i=0; i < rid.Length; i++ )
                      userSid.SetValue(rid[i], new long[] {userSid.Length - (rid.Length - i)} );
                return userSid;

          private unsafe String UnsafeConvertSidToStringSid( object sid )
                String sidString = null;
                IntPtr strPtr;
                fixed ( byte *psid = (byte[]) sid )
                      IntPtr psidPtr = (IntPtr)psid;
                      BOOL rc = ConvertSidToStringSid( psidPtr, out strPtr );
                            sidString = Marshal.PtrToStringAuto( strPtr );      
                return sidString;

    Author Comment

    I can definitely work with the C#. You have been a big help.


    Write Comment

    Please enter a first name

    Please enter a last name

    We will never share this with anyone.

    Featured Post

    Looking for New Ways to Advertise?

    Engage with tech pros in our community with native advertising, as a Vendor Expert, and more.

    Well, all of us have seen the multiple EXCEL.EXE's in task manager that won't die even if you call the .close, .dispose methods. Try this method to kill any excels in memory. You can copy the kill function to create a check function and replace the …
    The ECB site provides FX rates for major currencies since its inception in 1999 in the form of an XML feed. The files have the following format (reducted for brevity) (CODE) There are three files available HERE (…
    It is a freely distributed piece of software for such tasks as photo retouching, image composition and image authoring. It works on many operating systems, in many languages.
    Excel styles will make formatting consistent and let you apply and change formatting faster. In this tutorial, you'll learn how to use Excel's built-in styles, how to modify styles, and how to create your own. You'll also learn how to use your custo…

    760 members asked questions and received personalized solutions in the past 7 days.

    Join the community of 500,000 technology professionals and ask your questions.

    Join & Ask a Question

    Need Help in Real-Time?

    Connect with top rated Experts

    13 Experts available now in Live!

    Get 1:1 Help Now