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

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 mydomain.com)
        '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
Who is Participating?
ihenryConnect With a Mentor Commented:
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;
jawhitmoyerAuthor Commented:
I tried adding this, but I get an error saying unknown object:

Dim grp2 As DirectoryEntry = New DirectoryEntry("LDAP://" & sDomain, sUsername, sPassword)
addMe = grp2.Children.Find("CN=Domain Users", "group")
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.
Cloud Class® Course: Microsoft Exchange Server

The MCTS: Microsoft Exchange Server 2010 certification validates your skills in supporting the maintenance and administration of the Exchange servers in an enterprise environment. Learn everything you need to know with this course.

jawhitmoyerAuthor Commented:
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"?

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.
jawhitmoyerAuthor Commented:
I can definitely work with the C#. You have been a big help.

Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.