DevTrain

Autor: Tobi Ulm

ADSI mit .net

Aufgrund einiger Anfragen zum Thema Active Directory in meinen .net Schulungen, habe ich mich entschlossen einen kurzen Artikel zum Thema abzuliefern. Dabei werde ich zwei Möglichkeiten aufzeigen, die benutzt werden können.
ADSI
 ADSI ist ein Interface welches ab Windows NT 4 bei den Windows Betriebssystemen zur Verfügung steht. ADSI muss jedoch bei Windows NT 4 nachträglich manuell installiert werden. Diese Sammlung von Interfaces die Microsoft anbietet, hilft Entwicklern und damit auch Administratoren verschiedenste Netzwerkdienste aufzulisten und zu managen. Dabei unterstützt ADSI verschiedene Netzwerkarten durch verschiedene ADSI Provider.
Service provider                                                                          Pfad
Windows NT version 5.0, Windows 2000, oder Windows XP     WinNT://pfad
Lightweight Directory Access Protocol (LDAP)                            LDAP://pfad
Novell NetWare Directory Service                                               NDS://pfad
Novell Netware 3.x                                                                      NWCOMPAT://pfad
Für die Entwickler ist jedoch wichtig dass man mit ADSI Anwendungen erzeugen kann, welche es ermöglichen zum Beispiel Datenbanken zu sichern, Drucker und Benutzer zu verwalten. Ich werde mich in diesem Artikel nur auf Active Directory beschränken und nicht auf Novell & Co eingehen. Active Directory wird dabei im Code als Baumstruktur repräsentiert der Eigenschaften zu Verfügung stellt die ausgelesen oder editiert werden können.

Active Directory mit den System.DirectoryServices
Objekte die benutzt werden:
 - DirectoryEntry
 Die DirectoryEntry Klasse  entspricht einem Knoten oder Objekt in der Active Directory Hierarchie. Bei Verwendung dieses Objektes und einigen Hilfsklassen ist es uns möglich durch den Active Directory Baum zu navigieren, Knoten zu erzeugen, zu löschen, umzubenennen oder zu verschieben. .
 - DirectorySearcher
 Die DirectorySearcher Klasse wird benutzt um Suchanfragen gegen die Active Directory Hierarchie zu machen. LDAP ist dabei der einzige ADSI Provider mit dem dieses möglich ist.  Bei Verwendung des DirectorySearcher Objektes bekommen Sie Objektinstanzen von SearchResult zurück.
Der Namespace System.DirectoryServices ist der Ausgangspunkt für einen einfachen Zugriff auf ADSI aus managed Code heraus.  In Beispiel Nummer 1 verwende ich ein visuelles DirectoryEntry Objekt aus der Werkzeugleiste Komponenten von Visual Studio .NET und setze die Pfadeigenschaft auf einen ADSI Providerstring mit WinNT:meinrechner um Informationen über meinen Rechner auszulesen. Dabei bekommen wird die oberste Ebene des Verzeichniss Eintrages. Mit einer simplen foreach Iteration gehen wir durch alle Child Knoten und filtern auf Benutzer, Gruppen und Dienste. Die Funktion AddPathAndProperties fügt dabei die Children Knoten an den Entsprechenden Knoten im Formularbaum und liest die jeweiligen Eigenschaften des Child Knotens aus.
Beispiel 1 (Form1.cs):
 
private void Form1_Load(object sender, System.EventArgs e) {
 this.Text += " mit Active Directory Path: " + entryPC.Path.ToString();
 TreeNode users = new TreeNode("Benutzer");
 TreeNode groups = new TreeNode("Gruppen");
 TreeNode services = new TreeNode("Dienste");
 tviewPC.Nodes.AddRange(new TreeNode[] {users, groups, services});
 foreach(DirectoryEntry child in entryPC.Children) {
  TreeNode newChild = new TreeNode(child.Name);
  switch(child.SchemaClassName) {
   case "User":
    users.Nodes.Add(newChild);
    break;
   case "Group":
    groups.Nodes.Add(newChild);
    break;
   case "Service":
    services.Nodes.Add(newChild);
    break;
  }
  AddPathAndProperties(newChild, child);
 }
}
private void AddPathAndProperties(TreeNode node, DirectoryEntry entry) {
 node.Nodes.Add(new TreeNode("Pfad: " + entry.Path));
 TreeNode propertyNode = new TreeNode("Eigenschaften");
 node.Nodes.Add(propertyNode);
 foreach(string propertyName in entry.Properties.PropertyNames) {
  string oneNode = propertyName + ": " + entry.Properties[propertyName][0].ToString();
  propertyNode.Nodes.Add(new TreeNode(oneNode));
 }
}
 
Um einen Wert zu ändern setzen Sie einfach die Eigenschaft auf den entsprechenden Wert und rufen die Funktion CommitChanges() auf um die Veränderungen zu speichern.
entry.Properties[propertyName][0] = newValue;
entry.CommitChanges();

Anmerkung: In grossen Active Directory Systemen dauert die Veränderung seine Zeit bis die Daten repliziert wurden!

In Beispiel 2 (Form2.cs) verwende ich anstelle eines WinNT: Connectionstrings einen LDAP String und den damit verbundenen LDAP Provider. Die Iteration durch die Ergebnismenge [entry] ist eine einfache Ausgabe der Children LDAP Strings in eine ListBox  die Sie anstelle von @?LDAP://NameDerDomäne? eingeben können.

//LDAP Pfad auf den entsprechenden LDAP Node setzen
DirectoryEntry entry = new DirectoryEntry(@"LDAP://NameDerDomäne");
this.Text += "Active Directory Path: " + entry.Path.ToString();
//Erzeugen eines DirectorySearchers der der den LDAP Node repräsentiert
System.DirectoryServices.DirectorySearcher mySearcher = new System.DirectoryServices.DirectorySearcher(entry);
//Iteration durch die Ergebnismennge
foreach(DirectoryEntry objChildDE in entry.Children){
 listBox1.Items.Add(objChildDE.Path);
}

Auf das SearchResult Objekt mySearcher wird nun ein Filter angesetz um einen Eintrag, bzw. ein SearchResult Objekt im entry Objekt zu finden das auf sn=Ulm passt. Dies ist mein Konto in der ActiveDirectory Struktur.

mySearcher.Filter= ("(sn=Ulm)");
foreach(System.DirectoryServices.SearchResult dssr in mySearcher.FindAll()) {
 listBox1.Items.Add(dssr.Path.ToString());
 foreach(string strPropertyName in dssr.Properties.PropertyNames) {
  listBox1.Items.Add(strPropertyName + ": " + dssr.Properties[strPropertyName][0].ToString());
 }
}

Der Unterschied zu Beispiel 1 ist, dass wir uns auf eine Domäne verbunden haben und nicht auf einen einzigen Computer.

Active Directory über API Calls und InterOp
Eine weitere Möglichkeit um auf solche Netzwerkdienstinformationen zuzugreifen ist die Verwendung der Active Directory Type Library activeds.tlb.  Dabei muss erwähnt werden dass es sich hierbei um die ?hardcore? Methode handelt, denn es werden Funktionen aus den System Bibliotheken verwendet. Ich gehe davon aus, dass der Leser bereits weiss wie man (n oder frau) einen DLL Import nach .net macht. Ausserdem ist dieses Beispiel erst ab Windows 2000 ausführbar.

Importieren der COM TLB activeds.tlb:
 Tlbimp.exe  /silent activeds.tlb /out:ActiveDIS.dll

In der bereits importieren Komponente ( in diesem Beispiel heisst diese dann ActiveDIS.dll ) gibt es eine Vielzahl an Interfaces die die Entsprechenden Knoten im Verzeichnisdienst darstellen. Im Quellcode verwenden wird die Interfaces

IADsComputer   stellt den Computer dar
IADsService   stellt die Dienste dar
IADsGroup  stellt die Gruppen dar
IADsUser  stellt die Benutzer dar


Weitere Interfaces die Sie verwenden können sind zum Beispiel
- IADsDomain
- IADsPrinterQueue 
- IADsFileShare
- IADsFileService
Setzen Sie im Objektbrowser von Visual Studio .NET (STRG+ALT+J oder F2) einen Verweis auf die ActiveDIS.dll und sehen Sie sich die vielen Interfaces an die ausserdem zur Verfügung stehen. Sie können den Quellcode des Beispiels jederzeit erweitern.

Das Beispiel ist so aufgebaut, dass eine globale Klasse die Grundlage bildet MTNode. MTNode ist vom Type einer TreeNode Klasse abgeleitet und bietet dessen Standardfunktionalitäten sowie Erweiterungen für die Verwendung von ActiveDirectoryInterfaces und Speicherung der  Eigenschaften eines ADSI Nodes. Danach folgt in der Objekthierarchie die Grundlage für die jeweiligen IADs****** Abfragen.  Diese Klassen heissen ComputerNode, ServiceNode, GroupNode, UserNode, sind von MTNode abgeleitet und wurden um die Eigenschaften erweitert die die Daten des jeweiligen ADSI Nodes repräsentieren. Diese Eigenschaften werden durch die Methode QueryInformation() befüllt. Die Klassen die dann im eigentlichen Programm benutzt werden sind die letzte Ebene der Objekthierarchie und heissen MServiceNode, MGroupNode und MUserNode.

ComputerNode CNode = new ComputerNode("Arbeitsplatz", sCompName.ToString(), Comp);
CNode.ImageIndex = 0;
CNode.SelectedImageIndex = 1;
CNode.QueryInformation();
CNode.AddContentsToSibling(GrpBox);
InfoTree.Nodes.Add(CNode);
MServiceNode sNode = new MServiceNode("Dienste", Comp);
sNode.ImageIndex = 2;
sNode.SelectedImageIndex = 3;
sNode.QueryInformation();
CNode.Nodes.Add(sNode);
MUserNode uNode = new MUserNode("Benutzer", Comp);
uNode.QueryInformation();
CNode.Nodes.Add(uNode);
MGroupNode gNode = new MGroupNode("Gruppen", Comp);
gNode.QueryInformation();
CNode.Nodes.Add(gNode);

Wie Sie sehen gibt es kein MComputerNode, da das Beispiel beschränkt wurde und nur die Informationen des lokalen Computers auszulesen, für den der ADSI Pfad gilt (WinNT://**********).
Ein Wort zu der GUID: Die Funktion ADsGetObject will  eine eindeutige GUID haben, um das korrekte Interface auf den Rechner ansprechen zu können, in diesem Fall das Interface IADsComputer!
Um sich als ein anderer User am Verzeichnisdienst anmelden zu können suchen Sie bitte im Plattform SDK von Microsoft nach dem Stichwort [ ADsOpenObject ].

Erfasst am: 14.11.2002 - Artikel-URL: http://www.devtrain.de/news.aspx?artnr=806
© Copyright 2003 ppedv AG - http://www.ppedv.de