Skip to content

Instantly share code, notes, and snippets.

@jcorderodr
Last active July 13, 2021 00:18
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save jcorderodr/9f732e83236b32a69617d6e4c2ec59c4 to your computer and use it in GitHub Desktop.
Save jcorderodr/9f732e83236b32a69617d6e4c2ec59c4 to your computer and use it in GitHub Desktop.
ActiveDirectory Basic Management on C#
using System;
using System.Linq;
using System.Collections.Generic;
using System.DirectoryServices;
using System.DirectoryServices.AccountManagement;
using System.Text;
namespace TestAD.ActiveDirectory
{
/*
*
* MSDN: http://msdn.microsoft.com/en-us/library/system.directoryservices.accountmanagement%28v=vs.110%29.aspx
*/
public class ActiveDirectoryManager
{
public const String DOMAIN_NAME = "DOMAINSRV";
public const String LOCAL_DOMAIN = "@organization.local";
public const String DOMAIN_ADDRESS = "organization.com";
public const String OFFICE_NAME = "OrgAnizaTion";
private const string TemporalPassword = "temporal2014";
/// <summary>
/// Creates an empty UserPrincipal object joined to the Domain.
/// </summary>
/// <returns></returns>
protected static UserPrincipal Create()
{
var context = new PrincipalContext(ContextType.Domain, DOMAIN_NAME);
var userObj = new UserPrincipal(context) { Enabled = true, PasswordNeverExpires = false };
return userObj;
}
public static bool ValidateLogin(string username, string password)
{
bool valid = false;
using (var context = new PrincipalContext(ContextType.Domain))
{
valid = context.ValidateCredentials(username, password);
}
return valid;
}
public static string CreateEmail(String user)
{
return String.Format("{0}@{1}", user.ToLowerInvariant(), DOMAIN_ADDRESS);
}
public static bool Disable(string userName)
{
var context = new PrincipalContext(ContextType.Domain, DOMAIN_NAME);
var user = UserPrincipal.FindByIdentity(context, userName);
if (user == null) return false;
user.Enabled = false;
user.Save();
return true;
}
/// <summary>
/// Checks if exists.
/// </summary>
/// <param name="userName"></param>
/// <returns></returns>
public static bool Exists(String userName)
{
var context = new PrincipalContext(ContextType.Domain, DOMAIN_NAME);
var userObj = UserPrincipal.FindByIdentity(context, userName);
// if not null, exists
return userObj != null;
}
public static IEnumerable<string> FilterNonExist(IEnumerable<string> users)
{
return users.Where(userName => !Exists(userName)).ToList();
}
/// <summary>
/// Checks if exists.
/// </summary>
/// <param name="userName"></param>
/// <returns></returns>
public static UserPrincipal GetUserPrincipal(String userName)
{
var context = new PrincipalContext(ContextType.Domain, DOMAIN_NAME);
var userObj = new UserPrincipal(context)
{
SamAccountName = userName
};
var searcher = new PrincipalSearcher
{
QueryFilter = userObj
};
return searcher.FindOne() as UserPrincipal;
}
/// <summary>
/// Looks for an User using the Domain as datasource
/// </summary>
/// <param name="userName"></param>
/// <returns></returns>
public static User GetUserByUserName(String userName)
{
var dirSearch = new DirectorySearcher(GetDirectoryEntry);
dirSearch.Filter = "(&(objectClass=user)(SAMAccountName=" + userName + "))";
SearchResult results = dirSearch.FindOne();
if (results != null)
{
var tempUser = new DirectoryEntry(results.Path);
return ToUser(tempUser);
}
return null;
}
/// <summary>
/// Looks for an User using the Domain as datasource
/// </summary>
/// <param name="id"></param>
/// <returns>A matched and filled User, otherwise, null.</returns>
public static User GetUserByEmployeeId(String id)
{
var dirSearch = new DirectorySearcher(GetDirectoryEntry);
dirSearch.Filter = "(&(objectClass=user)(|(ipPhone=*" + id + ")(pager=*" + id + ")))";
var results = dirSearch.FindOne();
if (results != null)
{
var tempUser = new DirectoryEntry(results.Path);
return ToUser(tempUser);
}
return null;
}
/// <summary>
/// Looks for an element by any of his fields.
/// </summary>
/// <param name="name"></param>
/// <param name="userName"></param>
/// <param name="email"></param>
/// <param name="description"></param>
/// <returns></returns>
public static IEnumerable<User> GetUsers(string name, string userName, string email, string description)
{
if (String.IsNullOrEmpty(userName) && String.IsNullOrEmpty(name) && String.IsNullOrEmpty(email) && String.IsNullOrEmpty(description))
return new User[0];
var builder = new StringBuilder("(&(objectClass=user)(&");
if (!String.IsNullOrEmpty(userName))
builder.AppendFormat("({0}={1})", ADUserProperty.LOGINNAME, userName);
if (!String.IsNullOrEmpty(name))
builder.AppendFormat("({0}=*{1}*)", ADUserProperty.NAME, name);
if (!String.IsNullOrEmpty(email))
builder.AppendFormat("({0}={1})", ADUserProperty.EMAILADDRESS, email);
if (!String.IsNullOrEmpty(description))
builder.AppendFormat("({0}=*{1}*)", ADUserProperty.DESCRIPTION, description);
//builder.AppendFormat("({0}={1})", ADUserProperty.USERACCOUNTCONTROL, 512); //¿?
builder.Append("))");
var dirSearch = new DirectorySearcher(GetDirectoryEntry) { Filter = builder.ToString() };
var results = dirSearch.FindAll();
return results.Count > 0 ?
results.OfType<SearchResult>().Select(i => ToUser(i.GetDirectoryEntry())) : new User[0];
}
/// <summary>
/// Exceptions:
/// System.InvalidOperationException:
/// The principal has not yet been associated with a System.DirectoryServices.AccountManagement.PrincipalContext
/// object.This type of principal cannot be inserted in the store.
///
/// System.DirectoryServices.AccountManagement.PrincipalOperationException:
/// An exception occurred when saving changes to the store, or updating the group
/// membership in the store.
///
/// System.DirectoryServices.AccountManagement.PrincipalExistsException:
/// The principal already occurs in the store.
///
/// System.DirectoryServices.AccountManagement.PasswordException:
/// The password does not meet complexity requirements.
/// </summary>
/// <param name="user"></param>
protected static void Save(UserPrincipal user)
{
user.ExpirePasswordNow();
user.Save();
}
public static void Save(User user, string password = TemporalPassword)
{
//This is a easy way to create an User.
using (var userPrincipal = Create())
{
userPrincipal.DisplayName = user.DisplayName;
userPrincipal.EmailAddress = user.EMail;
userPrincipal.VoiceTelephoneNumber = user.Phone;
/*
userPrincipal.GivenName = user.Name;
userPrincipal.MiddleName = user.LastName;
userPrincipal.Description = user.Description;
*/
userPrincipal.UserPrincipalName = user.UserName + LOCAL_DOMAIN;
userPrincipal.SamAccountName = user.UserName;
userPrincipal.Enabled = true;
Save(userPrincipal);
}
// I wait, since sometimes the Active Directory/Server doesn't commit inmediatly.
Task.Delay(TimeSpan.FromSeconds(5)).Wait();
/*
* Update Properties
*/
var dirSearch = new DirectorySearcher(GetDirectoryEntry);
dirSearch.Filter = "(&(objectClass=user)(" + ADUserProperty.LOGINNAME + "=" + user.UserName + "))";
var results = dirSearch.FindOne();
if (results == null) return;
var entry = new DirectoryEntry(results.Path);
entry.Invoke("SetPassword", password);
entry.Properties[ADUserProperty.PAGER].Value = user.EmployeeId.ToString();
entry.Properties[ADUserProperty.FIRSTNAME].Value = user.Name;
entry.Properties[ADUserProperty.LASTNAME].Value = user.LastName;
entry.Properties[ADUserProperty.DESCRIPTION].Value = user.Description;
entry.Properties[ADUserProperty.EMAILADDRESS].Value = user.EMail;
entry.Properties[ADUserProperty.HOMEPHONE].Value = user.Phone;
// This makes the user change the password at the next login
entry.Properties[ADUserProperty.PWDLASTSET].Value = 0;
entry.Properties[ADUserProperty.TITLE].Value = user.Description;
entry.Properties[ADUserProperty.DEPARTMENT].Value = user.Department;
entry.Properties[ADUserProperty.COMPANY].Value = OFFICE_NAME;
//entry.Properties[ADUserProperty.MANAGER].Value = String.Format("CN={0},CN=Users,DC=organization,DC=local", user.Supervisor.Name);
// Attributes (codes) http://www.selfadsi.org/ads-attributes/user-userAccountControl.htm
var val = (int)entry.Properties[ADUserProperty.USERACCOUNTCONTROL].Value;
entry.Properties[ADUserProperty.USERACCOUNTCONTROL].Value = val & ~0x2; // (512 - Active)
entry.CommitChanges();
entry.Close();
}
/// <summary>
///
/// </summary>
/// <param name="id"></param>
/// <returns>Object containing basic data.</returns>
public static Manager GetManagerByEmpId(int id)
{
var user = GetUserByEmployeeId(id + "");
return user != null ? new Manager() { EmployeeId = id, Name = user.DisplayName } : new Manager();
}
private static DirectoryEntry GetDirectoryEntry
{
get
{
var dirEntry = new DirectoryEntry();
return dirEntry;
}
}
private static User ToUser(Principal obj)
{
var dirSearch = new DirectorySearcher(GetDirectoryEntry);
dirSearch.Filter = "(&(objectClass=user)(" + ADUserProperty.LOGINNAME + "=" + obj.SamAccountName + "))";
var results = dirSearch.FindOne();
if (results != null)
{
var tempUser = new DirectoryEntry(results.Path);
return ToUser(tempUser);
}
return null;
}
private static User ToUser(DirectoryEntry directoryEntry)
{
var user = new User();
user.UserName = GetProperty(directoryEntry, ADUserProperty.LOGINNAME);
{
var pager = GetProperty(directoryEntry, ADUserProperty.PAGER);
var ipPhone = GetProperty(directoryEntry, ADUserProperty.EXTENSION);
var empId = String.IsNullOrEmpty(pager) ? ipPhone : pager;
//In my case, the organization uses theses fields for store personal data
empId = empId.Replace("ID", "").Replace(" ", "");
try
{
user.EmployeeId = Int64.Parse(empId);
}
catch { }
}
user.DisplayName = GetProperty(directoryEntry, ADUserProperty.DISPLAYNAME);
user.Name = GetProperty(directoryEntry, ADUserProperty.FIRSTNAME);
user.LastName = GetProperty(directoryEntry, ADUserProperty.LASTNAME);
user.Description = GetProperty(directoryEntry, ADUserProperty.DESCRIPTION);
user.EMail = GetProperty(directoryEntry, ADUserProperty.EMAILADDRESS);
return user;
}
private static String GetProperty(DirectoryEntry userDetail, String propertyName)
{
return userDetail.Properties.Contains(propertyName) ? userDetail.Properties[propertyName][0].ToString() : String.Empty;
}
/// <summary>
/// ActiveDirectory basic's rules or policy on the password.
/// </summary>
/// <param name="text"></param>
/// <returns>true - if valid, otherwise, false.</returns>
public static bool IsValidPassword(string text)
{
return text.Length > 6;
}
}
}
using System;
//Class from: http://www.c-sharpcorner.com/uploadfile/dhananjaycoder/all-operations-on-active-directory-ad-using-C-Sharp/
namespace TestAD.ActiveDirectory
{
class ADUserProperty
{
public const String DESCRIPTION = "description";
public const String OBJECTCLASS = "objectClass";
public const String CONTAINERNAME = "cn";
public const String LASTNAME = "sn";
public const String COUNTRYNOTATION = "c";
public const String CITY = "l";
public const String STATE = "st";
public const String TITLE = "title";
public const String POSTALCODE = "postalCode";
public const String PHYSICALDELIVERYOFFICENAME = "physicalDeliveryOfficeName";
public const String FIRSTNAME = "givenName";
public const String MIDDLENAME = "initials";
public const String DISTINGUISHEDNAME = "distinguishedName";
public const String INSTANCETYPE = "instanceType";
public const String WHENCREATED = "whenCreated";
public const String WHENCHANGED = "whenChanged";
public const String DISPLAYNAME = "displayName";
public const String USNCREATED = "uSNCreated";
public const String MEMBEROF = "memberOf";
public const String USNCHANGED = "uSNChanged";
public const String COUNTRY = "co";
public const String DEPARTMENT = "department";
public const String COMPANY = "company";
public const String STREETADDRESS = "streetAddress";
public const String DIRECTREPORTS = "directReports";
public const String NAME = "name";
public const String OBJECTGUID = "objectGUID";
public const String USERACCOUNTCONTROL = "userAccountControl";
public const String BADPWDCOUNT = "badPwdCount";
public const String CODEPAGE = "codePage";
public const String COUNTRYCODE = "countryCode";
public const String BADPASSWORDTIME = "badPasswordTime";
public const String LASTLOGOFF = "lastLogoff";
public const String LASTLOGON = "lastLogon";
public const String PWDLASTSET = "pwdLastSet";
public const String PRIMARYGROUPID = "primaryGroupID";
public const String OBJECTSID = "objectSid";
public const String ADMINCOUNT = "adminCount";
public const String ACCOUNTEXPIRES = "accountExpires";
public const String LOGONCOUNT = "logonCount";
public const String LOGINNAME = "sAMAccountName";
public const String SAMACCOUNTTYPE = "sAMAccountType";
public const String SHOWINADDRESSBOOK = "showInAddressBook";
public const String LEGACYEXCHANGEDN = "legacyExchangeDN";
public const String USERPRINCIPALNAME = "userPrincipalName";
public const String EXTENSION = "ipPhone";
public const String SERVICEPRINCIPALNAME = "servicePrincipalName";
public const String OBJECTCATEGORY = "objectCategory";
public const String LASTLOGONTIMESTAMP = "lastLogonTimestamp";
public const String EMAILADDRESS = "mail";
public const String MANAGER = "manager";
public const String MOBILE = "mobile";
public const String PAGER = "pager";
public const String FAX = "facsimileTelephoneNumber";
public const String HOMEPHONE = "homePhone";
public const String MSEXCHUSERACCOUNTCONTROL = "msExchUserAccountControl";
public const String MDBUSEDEFAULTS = "mDBUseDefaults";
public const String MSEXCHMAILBOXSECURITYDESCRIPTOR = "msExchMailboxSecurityDescriptor";
public const String HOMEMDB = "homeMDB";
public const String MSEXCHPOLICIESINCLUDED = "msExchPoliciesIncluded";
public const String HOMEMTA = "homeMTA";
public const String MSEXCHRECIPIENTTYPEDETAILS = "msExchRecipientTypeDetails";
public const String MAILNICKNAME = "mailNickname";
public const String MSEXCHHOMESERVERNAME = "msExchHomeServerName";
public const String MSEXCHVERSION = "msExchVersion";
public const String MSEXCHRECIPIENTDISPLAYTYPE = "msExchRecipientDisplayType";
public const String MSEXCHMAILBOXGUID = "msExchMailboxGuid";
public const String NTSECURITYDESCRIPTOR = "nTSecurityDescriptor";
}
}
using System;
namespace TestAD.Entities
{
public class User
{
public Int64 EmployeeId { get; set; }
public String UserName { get; set; }
public String DisplayName { get; set; }
public String Name { get; set; }
public String LastName { get; set; }
public String Description { get; set; }
public String Department { get; set; }
public String EMail { get; set; }
public String Phone { get; set; }
public Manager Supervisor { get; set; }
}
public struct Manager
{
public int EmployeeId { get; set; }
public String Name { get; set; }
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment