phone bookActive Directory is the service used to manage security on Windows domains. In .NET, Microsoft makes available to us a number of classes for accessing Active Directory data.

One thing that is extremely important when dealing with Active Directory is to make sure that you have exception handling. Different domains have different security restrictions. On some domains, you may find yourself unable to use certain objects, such as the directory searcher, if you are not an administrator.

The most fundamental Active Directory object is DirectoryEntry. It represents an object on the domain. Consider this function, for instance, which can be used to enumerate all of the available Active Directory objects and populate a tree with them:

private void CreateADTree(TreeNode node, DirectoryEntry de)
{
try
{
if (null == de)
{
de = new DirectoryEntry();
de.Path = “WinNT:”;
}

foreach (DirectoryEntry deChild in de.Children)
{
TreeNode nodeChild = null;
if (null == node)
{
nodeChild = tvAD.Nodes.Add(deChild.Name + ” (“ + deChild.SchemaClassName + “)”);
}
else
{
nodeChild = node.Nodes.Add(deChild.Name + ” (“ + deChild.SchemaClassName + “)”);
}
nodeChild.Tag = deChild.Path;

CreateADTree(nodeChild, deChild);
}
}
catch
{
return;
}
}

If you create a form containing a TreeView called tvAD, add a reference to System.DirectoryServices, and call the above function from your form load event, you should now see your tree view populated with all of the objects on your domain. (Note: if you are on a domain of any size, this function will take a VERY long time to execute. You may want to modify it to ignore objects of schema class “Computer”. Or, for extra credit, use the BeforeExpand event to load children as needed.) Now, this is exciting, but let’s take it a tad bit further and view some properties for these items. Add a list view to your form called lvAD and add the following code to tvAD’s selected node event:

private void tvAD_AfterSelect(object sender, TreeViewEventArgs e)
{
lvAD.View = View.Details;
lvAD.Clear();
lvAD.Columns.Add(“Property”, 150);
lvAD.Columns.Add(“Value”, 350);

DirectoryEntry de = (DirectoryEntry)tvAD.SelectedNode.Tag;
try
{
foreach (String strProperty in de.Properties.PropertyNames)
{
ListViewItem item = lvAD.Items.Add(strProperty);

try
{
item.SubItems.Add(de.Properties[strProperty].Value.ToString());
}
catch (Exception ex)
{
item.SubItems.Add(“Exception: “ + ex.ToString());
}
}
}
catch(Exception ex)
{
ListViewItem item = lvAD.Items.Add(“Exception”);
item.SubItems.Add(ex.ToString());
}
}

One of the properties you will notice is the “objectSid” property. The SID is a number like S-1-5-15 that uniquely identifies an object. There is a Windows API function called ConvertSidToStringSid that we can use to convert the SID from the unreadable byte array to a (more or less) human readable value.

[DllImport(“advapi32”, CharSet = CharSet.Auto, SetLastError = true)]
static extern bool ConvertSidToStringSid(IntPtr pSid, out string strSid);

internal static string SidToText(DirectoryEntry objGroup)
{
try
{
string sSID = string.Empty;
byte[] SID = objGroup.Properties[“objectSID”].Value as byte[];
IntPtr sidPtr = Marshal.AllocHGlobal(SID.Length);
sSID = “”;

System.Runtime.InteropServices.Marshal.Copy(SID, 0, sidPtr, SID.Length);
ConvertSidToStringSid((IntPtr)sidPtr, out sSID);

System.Runtime.InteropServices.Marshal.FreeHGlobal(sidPtr);
return sSID;
}
catch (Exception ex)
{
MessageBox.Show(“Error reading SID:rnrn” + ex.ToString());
return “”;
}
}

We can then modify the AfterSelect handler to use this function to use this function to display our SID:

if (“objectsid” == strProperty.ToLower())
{
item.SubItems.Add(GetTextualSID(de));
}
else
{

Technology, active directory, network security in general are passions of our JASEtech team. How smoothly does Active Directly integrate with the rest of your network and your daily work tasks? Let’s talk about how Active Directory can make your life easier.

image credit: recyclethis.co.uk

Comments are closed.