Thursday, August 24, 2017

Unspecified error when create Domain local groups via DirectoryServices programmatically in .Net

In order to create AD group programmatically we can use DirectoryServices .Net assembly. Here is the code which create domain global group:

   1: string groupName = "...";
   2: var de = new DirectoryEntry("LDAP://...");
   3: var group = de.Children.Add("CN=" + groupName, "group");
   4: group.Properties["samAccountName"].Value = groupName;
   5: group.CommitChanges();
   6: return true;

If we want to create Domain local group we need to set one more property for created group: groupType. Value of this property should be created as bitmask from the following values (see ADS_GROUP_TYPE_ENUM enumeration):

ADS_GROUP_TYPE_GLOBAL_GROUP

0x00000002

ADS_GROUP_TYPE_DOMAIN_LOCAL_GROUP

0x00000004

ADS_GROUP_TYPE_UNIVERSAL_GROUP

0x00000008

ADS_GROUP_TYPE_SECURITY_ENABLED

0x80000000

But if we use C# and try to create group like this:

   1: string groupName = "...";
   2: bool local = ...;
   3: var de = new DirectoryEntry("LDAP://...");
   4: DirectoryEntry group = de.Children.Add("CN=" + groupName, "group");
   5: group.Properties["samAccountName"].Value = groupName;
   6: group.Properties["groupType"].Value = (local ? 0x00000004 : 0x00000002) | 0x80000000;
   7: group.CommitChanges();

we will get exception with Unspecified error message:

Unspecified error
   at System.DirectoryServices.Interop.UnsafeNativeMethods.IAds.PutEx(Int32 lnControlCode, String bstrName, Object vProp)
   at System.DirectoryServices.PropertyValueCollection.set_Value(Object value)

The reason is that by default C# will cast value (local ? 0x00000004 : 0x00000002) | 0x80000000 as long and will pass 2147483652 to the groupType property which is incorrect value here. In order to avoid this error we need to pass int value to this property, i.e. in our code we should explicitly cast it to int – in this case it will pass negative value -2147483644 there:

   1: string groupName = "...";
   2: bool local = ...;
   3: var de = new DirectoryEntry("LDAP://...");
   4: DirectoryEntry group = de.Children.Add("CN=" + groupName, "group");
   5: group.Properties["samAccountName"].Value = groupName;
   6: group.Properties["groupType"].Value =
   7:     (int)((local ? 0x00000004 : 0x00000002) | 0x80000000);
   8: group.CommitChanges();

and group will be successfully created.

No comments:

Post a Comment