Reputation: 256581
If i wanted to pull information about a user from Active Directory in .NET, i could use the DirectorySearcher
class.
For example, to find the e-mail address of a user i would call:
public String GetUserEmailAddress(String accountName)
{
DirectorySearcher searcher = new DirectorySearcher();
searcher.Filter = String.Format("(&(objectCategory=user)(sAMAccountName={0}))", accountName);
searcher.PropertiesToLoad.Add("mail");
SearchResult searchResult = searcher.FindOne();
return searchResult.Properties["mail"][0];
}
What is the native way to query the Active Directory?
Note:
We can even extend our function to allow querying of any generic arbitrary information:
public Object GetUserAttribute(String accountName, String propertyName)
{
DirectorySearcher searcher = new DirectorySearcher();
searcher.Filter = String.Format("(&(objectCategory=user)(sAMAccountName={0}))", accountName);
searcher.PropertiesToLoad.Add(propertyName);
SearchResult searchResult = searcher.FindOne();
return searchResult.Properties[propertyName][0];
}
AD has all kinds of information that you can pass as propertyName
. For example:
displayName
(Display-Name): The display name for an object. This is usually the combination of the users first name, middle initial, and last name. (e.g. Ian A. Boyd)mail
(E-mail-Addresses): The list of email addresses for a contact. (e.g. [email protected])cn
(Common-Name): The name that represents an object. Used to perform searches.name
(RDN): The Relative Distinguished Name of an object. (e.g. Ian Boyd)sn
(Surname): This attribute contains the family or last name for a user.givenName
(Given-Name): Contains the given name (first name) of the user.sAMAccountName
(SAM-Account-Name): The logon name used to support clients and servers running older versions of the operating system, such as Windows NT 4.0, Windows 95, Windows 98, and LAN Manager. This attribute must be less than 20 characters to support older clients.objectGUID
(Object-Guid): The unique identifier for an object. (e.g. {3BF66482-3561-49a8-84A6-771C70532F25})employeeID
(Employee-ID): The ID of an employee.
/// "description" (Description): Contains the description to display for an object. This value is treated as single-valued by the system.Upvotes: 0
Views: 6032
Reputation: 754220
A first step would be to check out the article series An ADSI primer on Windows IT Pro. It gives a fairly good overview of the basics of ADSI and the IADs
interfaces and how to use them (from VBScript, I believe).
A second step in Delphi would be to import the Active_Ds
type library - this should generate an ActiveDs_TLB.pas
file that contains the basic types, interfaces, methods to deal with Active Directory from a native language, using ADSI.
To access the native functions, you need to use a so called function import for each of the functions you want - here the code for just one - ADsGetObject
:
type
TADsGetObject = function(aPathName: PWideChar; const aRIID: TGUID; out aObject): HResult; safecall;
var
ADsGetObject : TADsGetObject = nil;
initialization
hActiveDS := LoadLibrary(PChar('ActiveDS.dll')); // don't localize
if (hActiveDS = 0) then
raise Exception.Create(rc_CannotLoadActiveDS);
LoadProcAddress(hActiveDS, 'ADsGetObject', @ADsGetObject);
Once you've created those functions from the external library, you can go about calling them - something like this:
var
hr : HRESULT;
oIADs : IADs;
wsTemp : WideString;
begin
wsTemp := 'LDAP://cn=IanBoyd,cn=Users,dc=YourCompany,dc=com';
// try to bind to the ADSI object using the "sanitized" path
hr := ADsGetObject(PWideChar(wsTemp), IID_IADs, oIADs);
if Succeeded(hr) then begin
// successful - now retrieve all properties into property cache
try
oIADs.GetInfo;
except
on EOleSysError do begin
Exit;
end;
end;
// get the object's GUID
wsTemp := oIADs.GUID;
// do more stuff here.....
Next, also see my ADSI Delphi Tips & Tricks page - so of the info is outdated, though (like the link to The Delphi Magazine's collection CD - that doesn't seem to be available anymore).
Searching ADSI with native code is quite involved - that would definitely go beyond the scope of such a posting. I did write a fairly extensive article on that - including sample code - which is available upon request from me (send me an e-mail to my address in my profile).
Upvotes: 1
Reputation: 256581
marc_s's deleted answer proved to be the most useful; but here's the answer to the question in pseudo-code:
public GetUserEmailAddress(String accountName): String;
{
//Get the distinguished name of the current domain
String dn = GetDefaultDistinguishedName(); //e.g. "dc=stackoverflow,dc=com"
//Construct the ldap table name (e.g. "LDAP://dc=stackoverflow,dc=com")
String ldapTableName := "LDAP://"+dc;
//ADO connection string
String connectionString := "Provider=ADsDSOObject;Mode=Read;Bind Flags=0;ADSI Flag=-2147483648";
//The sql query to execute
String sql :=
"SELECT mail"+CRLF+
"FROM "+QuotedStr(ldapTableName)+CRLF+
"WHERE objectClass = "+QuotedStr("user")+CRLF+
"AND sAMAccountName = "+QuotedStr(userName);
ADOConnection conn := new ADOConnection(connectionString);
try
Recordset rs := conn.Execute(sql);
try
if (rs.Eof)
return "";
return rs["mail"].Value;
finally
rs.Free;
end;
finally
conn.Free;
end;
}
The real secret is talking to "the domain", and not any particular server:
//get the distinguished name of the current domain
public GetDefaultDistinguishedName(): string;
{
String path := "LDAP://rootDSE";
IADs ads;
ADsGetObject(PWideChar(path), IADs, out ads);
//e.g. on the "stackoverflow.com" domain, returns "DC=stackoverflow,DC=com"
return (String)ads.Get("defaultNamingContext");
}
Note: Any code is released into the public domain. No attribution required.
Upvotes: 1
Reputation: 72612
The native programming is LDAP you can use it in .NET with System.DirectoryServices.Protocols (S.DS.P).
Edited
If you are interested in how to interrogate active directory from native code, you may have a look to LDAP C-Binding API as discribed in RFC 1823 specifies, Microsoft support it, see MS Strategy for Lightweight Directory Access Protocol (LDAP). You'll find the using and reference manuals of the Microsoft API in Lightweight Directory Access Protocol.
You'll find here a way to find Active Directory on the network without providing any information but a correct DNS server. You can use domain DNS name in ldap_open
function, doing this way you don't have to know a Domain server adress.
Upvotes: 0