Click here to Skip to main content
15,881,859 members
Articles / Programming Languages / C#

How to Use AD Attributes Not Represented in UserPrincipal, GroupPrincipal and ComputerPrincipal

Rate me:
Please Sign up or sign in to vote.
5.00/5 (7 votes)
15 Oct 2010CPOL3 min read 89.4K   10   3
How to use AD attributes not represented in UserPrincipal, GroupPrincipal and ComputerPrincipal

Using System.DirectoryServices.AccountManagement compared to just using System.DirectoryServices is way simpler. Just look at these samples Active Directory and .NET 3.5/4.0 and Active Directory and .NET 2.0 clearly from those .NET3.5/4.0 is straightforward than the other but one thing is missing, exposing other attributes that are not represented in UserPrincipal, GroupPrincipal and ComputerPrincipal.

Using the old way, you can just do this. Go get and set the attributes, it's really that simple.

C#
/// <summary>
/// This will retreive the specified poperty value from the DirectoryEntry object 
/// (if the property exists)
/// </summary>
/// <param name="oDE"></param>
/// <param name="sPropertyName"></param>
/// <returns></returns>
public string GetProperty(DirectoryEntry oDE, string sPropertyName)
{
    if (oDE.Properties.Contains(sPropertyName))
    {
        return oDE.Properties[sPropertyName][0].ToString();
    }
    else
    {
        return string.Empty;
    }
}

/// <summary>
/// This will test the value of the propertyvalue and if empty will not set the property
/// as AD is particular about being sent blank values
/// </summary>
/// <param name="oDE"></param>
/// <param name="sPropertyName"></param>
/// <param name="sPropertyValue"></param>
public void SetProperty(DirectoryEntry oDE, string sPropertyName, string sPropertyValue)
{
    //check if the value is valid, otherwise dont update
    if (sPropertyValue != string.Empty)
    {
        //check if the property exists before adding it to the list
        if (oDE.Properties.Contains(sPropertyName))
        {
            oDE.Properties[sPropertyName].Value = sPropertyValue;
            oDE.CommitChanges();
            oDE.Close();
        }
        else
        {
            oDE.Properties[sPropertyName].Add(sPropertyValue);
            oDE.CommitChanges();
            oDE.Close();
        }
    }
}

But with using System.DirectoryServices.AccountManagement, the exposed attributes are limited to the following:

User Principal PropertiesComputer Principal PropertiesGroup Principal Properties
AccountExpirationDateAccountExpirationDateContext
AccountLockoutTimeAccountLockoutTimeContextRaw
AdvancedSearchFilterAdvancedSearchFilterContextType
AllowReversiblePasswordEncryptionAllowReversiblePasswordEncryptionDescription
BadLogonCountBadLogonCountDisplayName
CertificatesCertificatesDistinguishedName
ContextContextGroupScope
ContextRawContextRawGuid
ContextTypeContextTypeIsSecurityGroup
CurrentDelegationPermittedMembers
DelegationPermittedDescriptionName
DescriptionDisplayNameSamAccountName
DisplayNameDistinguishedNameSid
DistinguishedNameEnabledStructuralObjectClass
EmailAddressGuidUserPrincipalName
EmployeeIdHomeDirectory 
EnabledHomeDrive 
GivenNameLastBadPasswordAttempt 
GuidLastLogon 
HomeDirectoryLastPasswordSet 
HomeDriveName 
LastBadPasswordAttemptPasswordNeverExpires 
LastLogonPasswordNotRequired 
LastPasswordSetPermittedLogonTimes 
MiddleNamePermittedWorkstations 
NameSamAccountName 
PasswordNeverExpiresScriptPath 
PasswordNotRequiredServicePrincipalNames 
PermittedLogonTimesSid 
PermittedWorkstationsSmartcardLogonRequired 
SamAccountNameStructuralObjectClass 
ScriptPathUserCannotChangePassword 
SidUserPrincipalName 
SmartcardLogonRequired  
StructuralObjectClass  
Surname  
UserCannotChangePassword  
UserPrincipalName  
VoiceTelephoneNumber  

And if you would compare that to the full attribute set of Active Directory, I can safely say this is less than 10% of it. To view a full list, you can visit MSDN or better yet this website) as it has a really good Excel speadsheet that defines all attributes in a default installation which you can download as well.

So the question is how do I expose the other attributes like UserPrincipals mobile, UserPrincipals facsimileTelephoneNumber, GroupPrincipals info, etc.

Thanks to Principal Extensions! With this, Principals mentioned above can all be extended to create custom objects that extend the object model. These extended classes now have the ability to add or remove properties from the extended class as long as the properties that are added or removed are supported in the directory schema. Now to get and set the properties of the extension class, you will use the methods ExtensionGet and ExtensionSet and here is a sample below on a Group Principal for the “wWWHomePage” attribute etc. Thanks to Principal Extensions! With this, Principals mentioned above can all be extended to create custom objects that extend the object model. These extended classes have now the ability to add or remove properties from the extended class as long as the properties that are added or removed are supported in the directory schema. Now to get and set the properties of the extension class, you will use the methods ExtensionGet and ExtensionSet and here is a sample below on a Group Principal for the “wWWHomePage” attribute.

C#
[DirectoryObjectClass("group")]
[DirectoryRdnPrefix("CN")]

public class GroupPrincipalsEx : GroupPrincipal
{
    public GroupPrincipalsEx(PrincipalContext context) : base(context) { }

    public GroupPrincipalsEx(PrincipalContext context, string samAccountName)
        : base(context, samAccountName)
    {
    }

    [DirectoryProperty("wWWHomePage")]
    public string wWWHomePage
    {
        get
        {
            if (ExtensionGet("wWWHomePage").Length != 1)
                return null;

            return (string)ExtensionGet("wWWHomePage")[0];

        }
        set { this.ExtensionSet("wWWHomePage", value); }
    }
}

We call our class GroupPrincipalEx which is the extended class of GroupPrincipal which then exposes the Directory Property “wWWHomePage”. So from the screenshot below, you can see that the “wWWHomePage” now is exposed on intellisense.

Image 1

You can use this in many scenarios and one of the most useful ones is on searching. Just imagine if you had extended your active directory schema and you want to search using that extended attribute, or even use the built in attributes but was not exposed by the base class. I have an example to let you do that, let's say you had used the wWWHomePage attribute to store the AD Group Team Site address in Sharepoint and you want to search for all groups that have the parent site “http://sharepoint.com/mydepartment/“, now here is how it's done.

First, extend your Group Principal by using the same code above, then use PrincipalSearcher to use a Query Filter based on the exposed property.

C#
ArrayList myItems = new ArrayList();

PrincipalContext oPrincipalContext = new PrincipalContext
    (ContextType.Domain,
    sDomain,
    sDefaultOU,
    ContextOptions.SimpleBind,
    sServiceUser,
    sServicePassword);
GroupPrincipalsEx oGroups = new GroupPrincipalsEx(oPrincipalContext);
oGroups.wWWHomePage = "http://sharepoint.com/mydepartment/*";

PrincipalSearcher mySearch = new PrincipalSearcher(oGroups);
mySearch.QueryFilter = oGroups;

PrincipalSearchResult<Principal> oPrincipalSearchResult = mySearch.FindAll();

foreach (Principal oResult in oPrincipalSearchResult)
{
    myItems.Add(oResult.SamAccountName.ToString());
}

Another good example would be setting a value on that attribute on creation of the AD Object.

C#
PrincipalContext oPrincipalContext = new PrincipalContext
    (ContextType.Domain,
    sDomain,
    sDefaultOU,
    ContextOptions.SimpleBind,
    sServiceUser,
    sServicePassword);
GroupPrincipalsEx oGroups = new GroupPrincipalsEx(oPrincipalContext);

oGroups.DisplayName = "My Group";
oGroups.SamAccountName = "My Group";
oGroups.IsSecurityGroup = true;
oGroups.Description = "Automatically Created by Your Code";
oGroups.GroupScope = GroupScope.Local;
oGroups.wWWHomePage = "http://sharepoint.com/mydepartment/mygroup";
oGroups.Save();

So I guess that's it for now.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Technical Lead
New Zealand New Zealand
http://nz.linkedin.com/in/macaalay
http://macaalay.com/

Comments and Discussions

 
QuestionMultiValue Extensions Pin
Denver8021123-Dec-14 11:27
Denver8021123-Dec-14 11:27 
Questionhow to use FindByIdentity, after deriving UserPrinciple Pin
joph10-Feb-11 22:22
joph10-Feb-11 22:22 
AnswerRe: how to use FindByIdentity, after deriving UserPrinciple Pin
joph14-Feb-11 1:52
joph14-Feb-11 1:52 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.