问题
I've looked into the DirectoryServices class and it seems to be what I need, but I can't seem to find the classes/methods needed to fetch a collection of Organizational Units.
Can you guys give some suggestions?
回答1:
You need to use an appropriate DirectorySearcher
from System.DirectoryServices
, and you need to search for the organizationalUnit
AD class (I would recommend searching based on the objectCategory
which is single-valued and indexed - much faster than using objectClass
) - something like this:
List<string> orgUnits = new List<string>();
DirectoryEntry startingPoint = new DirectoryEntry("LDAP://DC=YourCompany,DC=com");
DirectorySearcher searcher = new DirectorySearcher(startingPoint);
searcher.Filter = "(objectCategory=organizationalUnit)";
foreach (SearchResult res in searcher.FindAll())
{
orgUnits.Add(res.Path);
}
回答2:
List<PlayerBO> source = new List<PlayerBO>();
DirectoryEntry root = new DirectoryEntry("LDAP://app.shgbit.com");
DirectoryEntry gbvision = root.Children.Find("OU=UMP");
DirectorySearcher searcher = new DirectorySearcher(gbvision);
searcher.Filter = "(objectClass=computer)";
int index = 1;
foreach (SearchResult each in searcher.FindAll())
{
var box = each.GetDirectoryEntry();
source.Add(new PlayerBO { Id = index++, Name = box.Properties["name"].Value.ToString(), Description = box.Properties["description"].Value.ToString() });
}
ListViewAD.ItemsSource = new SelectableSource<PlayerBO>(source);
回答3:
I know this thread is a little old, but I recently created a more efficient way of maneuvering through DirectoryEntries than the DirectorySearcher provides and wanted to share since this was the top result on Google. This example replicates the OU structure based on an initially specified starting point.
The DN path passed to the first constructor should be in the format "LDAP://OU=StartingOU,DC=test,DC=com"
using System.DirectoryServices;
using System.Threading.Tasks;
public class ADTree
{
DirectoryEntry rootOU = null;
string rootDN = string.Empty;
List<ADTree> childOUs = new List<ADTree>();
public DirectoryEntry RootOU
{
get { return rootOU; }
set { rootOU = value; }
}
public string RootDN
{
get { return rootDN; }
set { rootDN = value; }
}
public List<ADTree> ChildOUs
{
get { return childOUs; }
set { childOUs = value; }
}
public ADTree(string dn)
{
RootOU = new DirectoryEntry(dn);
RootDN = dn;
BuildADTree().Wait();
}
public ADTree(DirectoryEntry root)
{
RootOU = root;
RootDN = root.Path;
BuildADTree().Wait();
}
private Task BuildADTree()
{
return Task.Factory.StartNew(() =>
{
object locker = new object();
Parallel.ForEach(RootOU.Children.Cast<DirectoryEntry>().AsEnumerable(), child =>
{
if (child.SchemaClassname.Equals("organizationalUnit"))
{
ADTree ChildTree = new ADTree(child);
lock (locker)
{
ChildOUs.Add(ChildTree);
}
}
});
});
}
}
To build, all you need to do is the following:
ADTree Root = null;
Task BuildOUStructure = Task.Factory.StartNew(() =>
{
ADTree = new ADTree("LDAP://ou=test,dc=lab,dc=net");
});
BuildOUStructure.Wait();
回答4:
The code provided by Jamie works nicely. To answer MacGuyver's question, in order to use the Cast extension, you need to include a reference to System.Linq in your code. I'm using this code to populate a TreeView showing the OUs in my AD environment:
using System;
using System.Data;
using System.Linq;
using System.Windows.Forms;
using System.Threading.Tasks;
using System.DirectoryServices;
using System.Collections.Generic;
using System.DirectoryServices.ActiveDirectory;
namespace WindowsFormsApp8
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
treeView1.Nodes.Clear();
string top = string.Format("LDAP://DC={0}", Domain.GetCurrentDomain().Name.Replace(".", ",DC="));
ADTree tree = null;
Task BuildOUStructure = Task.Factory.StartNew(() =>
{
tree = new ADTree(top);
});
BuildOUStructure.Wait();
foreach(ADTree t in tree.ChildOUs)
{
TreeNode node = new TreeNode(t.RootOU.Path);
treeView1.Nodes.Add(node);
if(t.ChildOUs.Count > 0)
{
AddChildren(node, t);
}
}
}
private void AddChildren(TreeNode parent, ADTree tree)
{
foreach(ADTree t in tree.ChildOUs)
{
TreeNode node = new TreeNode(t.RootOU.Path);
parent.Nodes.Add(node);
if(t.ChildOUs.Count > 0)
{
AddChildren(node, t);
}
}
}
}
public class ADTree
{
DirectoryEntry rootOU = null;
string rootDN = string.Empty;
List<ADTree> childOUs = new List<ADTree>();
public DirectoryEntry RootOU
{
get { return rootOU; }
set { rootOU = value; }
}
public string RootDN
{
get { return rootDN; }
set { rootDN = value; }
}
public List<ADTree> ChildOUs
{
get { return childOUs; }
set { childOUs = value; }
}
public ADTree(string dn)
{
RootOU = new DirectoryEntry(dn);
RootDN = dn;
BuildADTree().Wait();
}
public ADTree(DirectoryEntry root)
{
RootOU = root;
RootDN = root.Path;
BuildADTree().Wait();
}
private Task BuildADTree()
{
return Task.Factory.StartNew(() =>
{
object locker = new object();
Parallel.ForEach(RootOU.Children.Cast<DirectoryEntry>().AsEnumerable(), child =>
{
if (child.SchemaClassName.Equals("organizationalUnit"))
{
ADTree ChildTree = new ADTree(child);
lock (locker)
{
ChildOUs.Add(ChildTree);
}
}
});
});
}
}
}
This is on a simple Windows Forms app with a TreeView (treeview1) and a Button (button1) - hope it helps!
回答5:
Have you looked at the DirectorySearcher method?
Here are some examples at MSDN and bytes.com.
回答6:
This is my solution and it's working:
List<string> DisplayedOU = new List<string>();
int step = 0;
string span = "<span style='margin-left:6px;'> -- </span>";
private void getOU2()
{
string strRet = "";
DirectoryEntry domainRoot = new DirectoryEntry("LDAP://uch.ac/OU=ALL,DC=uch,DC=ac", "user", "pass");
// set up directory searcher based on default naming context entry
DirectorySearcher ouSearcher = new DirectorySearcher(domainRoot);
// SearchScope: OneLevel = only immediate subordinates (top-level OUs);
// subtree = all OU's in the whole domain (can take **LONG** time!)
ouSearcher.SearchScope = SearchScope.Subtree;
// ouSearcher.SearchScope = SearchScope.Subtree;
// define properties to load - here I just get the "OU" attribute, the name of the OU
ouSearcher.PropertiesToLoad.Add("ou");
// define filter - only select organizational units
ouSearcher.Filter = "(objectCategory=organizationalUnit)";
int cnt = 0;
foreach (SearchResult deResult in ouSearcher.FindAll())
{
string temp = deResult.Properties["ou"][0].ToString();
strRet += FindSubOU(deResult.Properties["adspath"][0].ToString(), cnt);
}
Literal1.Text = strRet;
}
private string FindSubOU(string OU_Path, int cnt)
{
string strRet = "";
DirectoryEntry domainRoot = new DirectoryEntry(OU_Path, "user", "pass");
// set up directory searcher based on default naming context entry
DirectorySearcher ouSearcher = new DirectorySearcher(domainRoot);
// SearchScope: OneLevel = only immediate subordinates (top-level OUs);
// subtree = all OU's in the whole domain (can take **LONG** time!)
ouSearcher.SearchScope = SearchScope.Subtree;
// ouSearcher.SearchScope = SearchScope.Subtree;
// define properties to load - here I just get the "OU" attribute, the name of the OU
ouSearcher.PropertiesToLoad.Add("ou");
// define filter - only select organizational units
ouSearcher.Filter = "(objectCategory=organizationalUnit)";
//adspath
// do search and iterate over results
foreach (SearchResult deResult in ouSearcher.FindAll())
{
string temp = deResult.Properties["ou"][0].ToString();
if (!DisplayedOU.Contains(deResult.Properties["ou"][0].ToString()))
{
string strPerfix = "";
for (int i = 0; i < step; i++)
strPerfix += span;
strRet += strPerfix + ++cnt + ". " + deResult.Properties["ou"][0].ToString() + " ----> " + deResult.Properties["adspath"][0].ToString() + "<br />";
DisplayedOU.Add(deResult.Properties["ou"][0].ToString());
step++;
strRet += FindSubOU(deResult.Properties["adspath"][0].ToString(), cnt);
step--;
}
}
return strRet;
}
来源:https://stackoverflow.com/questions/5347096/how-can-i-get-a-list-of-organizational-units-from-active-directory