PHP function that gets the members of an Active Directory group, and returns the Users’ attributes as an array.
This is an improved version of the snippet posted on 2/10/2011
The Function
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 |
<?php
function get_members($group=FALSE,$inclusive=FALSE) {
// Active Directory server
$ldap_host = "ad.domain";
// Active Directory DN
$ldap_dn = "CN=Users,DC=ad,DC=domain";
// Domain, for purposes of constructing $user
$ldap_usr_dom = "@".$ldap_host;
// Active Directory user
$user = "jdoe";
$password = "password1234!";
// User attributes we want to keep
// List of User Object properties:
// http://www.dotnetactivedirectory.com/Understanding_LDAP_Active_Directory_User_Object_Properties.html
$keep = array(
"samaccountname",
"distinguishedname"
);
// Connect to AD
$ldap = ldap_connect($ldap_host) or die("Could not connect to LDAP");
ldap_bind($ldap,$user.$ldap_usr_dom,$password) or die("Could not bind to LDAP");
// Begin building query
if($group) $query = "(&"; else $query = "";
$query .= "(&(objectClass=user)(objectCategory=person))";
// Filter by memberOf, if group is set
if(is_array($group)) {
// Looking for a members amongst multiple groups
if($inclusive) {
// Inclusive - get users that are in any of the groups
// Add OR operator
$query .= "(|";
} else {
// Exclusive - only get users that are in all of the groups
// Add AND operator
$query .= "(&";
}
// Append each group
foreach($group as $g) $query .= "(memberOf=CN=$g,$ldap_dn)";
$query .= ")";
} elseif($group) {
// Just looking for membership of one group
$query .= "(memberOf=CN=$group,$ldap_dn)";
}
// Close query
if($group) $query .= ")"; else $query .= "";
// Uncomment to output queries onto page for debugging
// print_r($query);
// Search AD
$results = ldap_search($ldap,$ldap_dn,$query);
$entries = ldap_get_entries($ldap, $results);
// Remove first entry (it's always blank)
array_shift($entries);
$output = array(); // Declare the output array
$i = 0; // Counter
// Build output array
foreach($entries as $u) {
foreach($keep as $x) {
// Check for attribute
if(isset($u[$x][0])) $attrval = $u[$x][0]; else $attrval = NULL;
// Append attribute to output array
$output[$i][$x] = $attrval;
}
$i++;
}
return $output;
}
// Example Output
print_r(get_members()); // Gets all users in OU 'Users'
print_r(get_members("Test Group")); // Gets all members of 'Test Group'
print_r(get_members(
array("Test Group","Test Group 2")
)); // EXCLUSIVE: Gets only members that belong to BOTH 'Test Group' AND 'Test Group 2'
print_r(get_members(
array("Test Group","Test Group 2"),TRUE
)); // INCLUSIVE: Gets members that belong to EITHER 'Test Group' OR 'Test Group 2'
?> |
Example Output
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
Array
(
[0] => Array
(
[samaccountname] => sam
[distinguishedname] => CN=sam,CN=Users,DC=ad,DC=domain
)
[1] => Array
(
[samaccountname] => jdoe
[distinguishedname] => CN=John Doe,CN=Users,DC=ad,DC=domain
)
) |
Congrats, works like a charm!
Thanks.
this works great, and has saved me a lot of time, thanks!
I don’t suppose there is a way to search for multiple groups at a time?
Lachlan,
I have updated the original post with a newer version of the function that allows you to specify multiple groups
That should work for you
Thanks for that Sam… unfortunately, it does not work.
when using it without specifying any groups, it works fine, but if I specify a group (exactly as provided in the example), I get the following errors:
array_shift() expects parameter 1 to be array, null given in C:\inetpub\wwwroot\test.php on line 68
Invalid argument supplied for foreach() in C:\inetpub\wwwroot\test.php on line 74
the only change I made to your code when testing was I changed username/password/domain details (obviously) and changed the attributes it searches for. I even tried setting them back to as above, but to no avail.
I have not been able to reproduce the error
Can you paste your code?
http://paste.samjlevy.com/p
And paste the generated URL here
Remember to blank out your AD information if it is sensitive
Here is the URL: http://paste.samjlevy.com/v/4f84d55ad5438
thanks!
The error was occurring when a ‘keep’ attribute was not found for a user (for example: a user had no telephone number value)
I have fixed the original post, the tweaked code is:
$i = 0; // Counter // Build output array foreach($entries as $u) { foreach($keep as $x) { // Check for attribute if(isset($u[$x][0])) $attrval = $u[$x][0]; else $attrval = NULL; // Append attribute to output array $output[$i][$x] = $attrval; } $i++; }Hey Sam
Excellent code work. I build an application for a business in Denmark, where they must have 2 different logins. Admin and User login. I do not quite know how to solve this problem other than to make 2 different OU’s. but if I change:
$ ldap_dn = “CN = Users, DC = domain, DC = com”;
to another “CN” than “Users” it comes with errors.
hope you can help :)
Can you paste the errors?
Warning: ldap_search() [function.ldap-search]: Search: No such object in C:\wamp\www\authenticate.php on line 62
Warning: ldap_get_entries() expects parameter 2 to be resource, boolean given in C:\wamp\www\authenticate.php on line 63
Warning: array_shift() expects parameter 1 to be array, null given in C:\wamp\www\authenticate.php on line 66
Warning: Invalid argument supplied for foreach() in C:\wamp\www\authenticate.php on line 72
If I use “CN=Users” I receive the correct arrays, from the OU=Users in AD.
Your $ldap_dn must be incorrectly using CN instead of OU
Right click on the object in AD Users & Computers, then go to the Object tab
If it says ‘Object class: Container’, then use CN=XXX
If it says ‘Object class: Organizational Unit’, then use OU=XXX
The Users object is actually a Container and not an OU, this might be the cause of your confusion
Thanks a lot. It work by changing the CN to OU.
The code worked well, however I did find two issues, 1 I resolved and the other I still have not fully.
1. The AD setup I was searching through was setup with groups in 1 OU and the users in a separate OU, both at the same level. I added a 2nd $ldap_dn variable with the OU of the Users and then passed that variable into the $results =(ldap_search($ldap,$ldap_dn2, $query);
2. The other issue I am having is caused by users being setup with the searched group as their primary group. When you set them up this way, AD does not add the user to the member attribute of the group. I am still looking for the best solution to this issue, other than the obvious, just add them all back to the default users as their primary group. Any Ideas?
Thanks for the great function.
David,
What you need to do is add primaryGroupID=x to the LDAP query string
To make it work, you could do this–
Replace the foreach under ‘Append each group’ with:
// Append each group foreach($group as $g) { if(is_numeric($g)) $query .= "(primaryGroupID=$g)"; else $query .= "(memberOf=CN=$g,$ldap_dn)"; }And replace the line under ‘Just looking for membership of one group’ with:
The code we added will detect if you are using a number instead of a string, and will then check for users that have that number as their primaryGroupID.
The caveat being you have to use the ID of the group and not the CN, but you can mix it with CN’s since our code checks for numerics:
print_r(get_members(513)); // Gets all users that have primaryGroupID = 513 print_r(get_members(array("Test Group",513))); // EXCLUSIVE: Gets only members that belong to 'Test Group' AND that have primaryGroupID = 513 print_r(get_members(array("Test Group",513),TRUE)); // INCLUSIVE: Gets members that belong to 'Test Group' OR that have primaryGroupID = 513513 is the ‘Domain Users’ group
It’s a bit of a hack, but it should get you in the right direction
The proper way to do it would probably be to have 2 LDAP queries run: one that looks up the group ID for each/single passed group, and the other would search against both the memberOf with the CN and the primaryGroupID with the ID