About these ads

How to use AD Attributes not represented in UserPrincipal, GroupPrincipal and ComputerPrincipal

Using System.DirectoryServices.AccountManagement comapred to just using System.DirectoryServices is way much 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, its really that simple.

/// <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 is limited to the following:

User Principal Properties Computer Principal Properties Group Principal Properties
AccountExpirationDate AccountExpirationDate Context
AccountLockoutTime AccountLockoutTime ContextRaw
AdvancedSearchFilter AdvancedSearchFilter ContextType
AllowReversiblePasswordEncryption AllowReversiblePasswordEncryption Description
BadLogonCount BadLogonCount DisplayName
Certificates Certificates DistinguishedName
Context Context GroupScope
ContextRaw ContextRaw Guid
ContextType ContextType IsSecurityGroup
Current DelegationPermitted Members
DelegationPermitted Description Name
Description DisplayName SamAccountName
DisplayName DistinguishedName Sid
DistinguishedName Enabled StructuralObjectClass
EmailAddress Guid UserPrincipalName
EmployeeId HomeDirectory
Enabled HomeDrive
GivenName LastBadPasswordAttempt
Guid LastLogon
HomeDirectory LastPasswordSet
HomeDrive Name
LastBadPasswordAttempt PasswordNeverExpires
LastLogon PasswordNotRequired
LastPasswordSet PermittedLogonTimes
MiddleName PermittedWorkstations
Name SamAccountName
PasswordNeverExpires ScriptPath
PasswordNotRequired ServicePrincipalNames
PermittedLogonTimes Sid
PermittedWorkstations SmartcardLogonRequired
SamAccountName StructuralObjectClass
ScriptPath UserCannotChangePassword
Sid UserPrincipalName
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 this MSDN (http://msdn.microsoft.com/en-us/library/ms675090%28v=VS.85%29.aspx) or better yet this website (http://www.rlmueller.net/UserAttributes.htm) as it has a really good excel speadsheet that defines each 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 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 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.

[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.

You can use this in many scenarios and one of the most useful one 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 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 its 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.

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

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 thats it for now.

About these ads

14 Responses to How to use AD Attributes not represented in UserPrincipal, GroupPrincipal and ComputerPrincipal

  1. Can you please show a more detail example of how to use the RemoveUserFromGroup function?

    THank you in advance.

    • rsmacaalay says:

      Its simple to use all you need is an AD UserName and AD GroupName so for example you have a username “raymund” and group name “administrators” then the usage is RemoveUserFromGroup(“raymund”, “administrators”), hope this clarifies your question.

  2. Pingback: Synchronizing Google Groups and Active Directory Group Members « Raymund Macaalay's Dev Blog

  3. shashi says:

    Hi I am looking for a solution to get user department name form the PrincipalContext Object any help would be appreciated. I have 2.0 code but unable to get it in 3.5

    if (result.Properties.Contains(“department”))
    cad.adProfile[2] = result.Properties["department"][0].ToString();

  4. Mike says:

    Excellent blog post, Thank-you. I’ve run into a similar situation where our AD has the student’s ID # entered as it’s own attribute. Unfortunately I have to search for the student’s username by their studentID in order to get their username. Is this possible?

  5. jess says:

    Hello,

    I am trying to set two properties: “OfficeNumber” and “Manager” on a DirectoryEntry object using the code in GetProperty and SetProperty as written above. When I attempt to set the value for the “Manager” attribute I get a “DirectoryServicesCOMException – a constraint violation occurred” in the SetPropert oDE.CommitChanges() method call – what is happening? I can’t seem to set the “OfficeNumber” property (maybe because it doesn’t actually exist?) either as I get an exception during attempt to commit those changes in SetProperty also. Any help you can offer is appreciated

  6. rsmacaalay says:

    “manager” value should be the distinguishedName of the manager
    also there is no officenumber property, it looks like you need the “telephoneNumber” for a full list of what properties and its real values in your AD instance download AD Explorer here http://technet.microsoft.com/en-us/sysinternals/bb963907.aspx

  7. ETS says:

    Great article about extending principals. Your suggestions helped me to derive a new class from GroupPrincipal and add additional properties. Micorsofft should have exposed those AD properties. :)

    Thanks very much for putting it all together. Appreciate your time and effort.

  8. So if I have a UserPrincipalEx and expose pwdLastSet, would this work?

    var upe = (UserPrincipalEx)UserPrincipal.FindByIdentity(context, IdentityType.SamAccountName, user);
    upe.PwdLastSet = -1;

    Trying to understand how to get the UserPrincipalEx to be for a specific user without doing what you do in the group example where you are finding a set of groups. I have the user, and I just want to set the pwdLastSet.

    Thank you so much!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

Join 197 other followers

%d bloggers like this: