Я просмотрел класс DirectoryServices, и мне кажется, что мне нужно, но я не могу найти классы/методы, необходимые для сбора коллекции организационных единиц.
Можете ли вы, ребята, дать какие-то предложения?
Я просмотрел класс DirectoryServices, и мне кажется, что мне нужно, но я не могу найти классы/методы, необходимые для сбора коллекции организационных единиц.
Можете ли вы, ребята, дать какие-то предложения?
Вам нужно использовать соответствующий DirectorySearcher
из System.DirectoryServices
, и вам нужно найти класс organizationalUnit
AD (я бы рекомендовал поиск на основе objectCategory
, который является однозначным и индексированным - намного быстрее чем использование objectClass
) - что-то вроде этого:
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);
}
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);
Я знаю, что эта ветка немного старая, но я недавно создал более эффективный способ маневрирования через DirectoryEntries, чем DirectorySearcher предоставляет и хотел бы поделиться, поскольку это было лучшим результатом в Google. В этом примере реплицируется структура OU на основе начальной заданной начальной точки.
Путь DN, переданный первому конструктору, должен быть в формате "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);
}
}
});
});
}
}
Для создания всего вам нужно сделать следующее:
ADTree Root = null;
Task BuildOUStructure = Task.Factory.StartNew(() =>
{
ADTree = new ADTree("LDAP://ou=test,dc=lab,dc=net");
});
BuildOUStructure.Wait();
Код, предоставленный Джейми, прекрасно работает. Чтобы ответить на вопрос MacGuyver, чтобы использовать расширение Cast, вам нужно включить ссылку на System.Linq в ваш код. Я использую этот код для заполнения TreeView, показывающего OU в моей среде AD:
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);
}
}
});
});
}
}
}
Это простое приложение Windows Forms с TreeView (treeview1) и Button (button1) - надеюсь, это поможет!
Вы просмотрели метод DirectorySearcher?
Это мое решение, и оно работает:
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 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 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;
}