Entwickler-Ecke

Sonstiges (.NET) - AD-Benutzer zu lokaler Gruppe hinzufügen


FrederikR - Mo 04.07.11 14:39
Titel: AD-Benutzer zu lokaler Gruppe hinzufügen
Hallo,

mit PowerShell kann ich mit folgendem Befehl einen Benutzer aus dem Acitve Directory einer lokalen Gruppe hinzufügen:


Quelltext
1:
([ADSI]"WinNT://$client/Administratoren,group").add("WinNT://$Domain/$accname,user")                    


Wie mach ich dies in C#? Folgendes klappt nicht:

Quelltext
1:
2:
3:
4:
DirectoryEntry localMachine = new DirectoryEntry("WinNT://" + domain + "/" + client + ",Computer");
DirectoryEntry localGroup = localMachine.Children.Find("Administratoren", "group")

localGroup.Properties["member"].Add("WinNT://" + domain + "/" + accname);



Moderiert von user profile iconTh69: Topic aus Datenbanken (inkl. ADO.NET) verschoben am Di 05.07.2011 um 19:55


FrederikR - Di 05.07.11 10:10

Ist das hier das falsche Unterforum? Wäre für Hilfe echt dankbar! Oder weiß einfach niemand eine Antwort?


Eudaimonie - Di 05.07.11 10:57

Auf Codeproject gibts ne Seite "Everything in AD with C#"..
Damit solltest du weiter kommen.
http://www.codeproject.com/KB/system/everythingInAD.aspx


Trashkid2000 - Di 05.07.11 11:12

Hallo,

also erstmal ist es schon das falsche Unterforum, oder was hat das Thema mit Datenbanken zu tun?
Aber so sollte es schon gehen:

C#-Quelltext
1:
2:
3:
DirectoryEntry localMachine = new DirectoryEntry("WinNT://" + Environment.MachineName + ",computer");
DirectoryEntry localGroup = localMachine.Children.Find("Administratoren""group");
localGroup.Invoke("Add""LDAP://CN=John Doe,CN=Users,DC=Fabrikam,DC=com");
WinNT:// -- lokales System
LDAP:// -- Domäne
LG


FrederikR - Di 05.07.11 13:17

user profile iconEudaimonie hat folgendes geschrieben Zum zitierten Posting springen:
Auf Codeproject gibts ne Seite "Everything in AD with C#"..
Damit solltest du weiter kommen.
http://www.codeproject.com/KB/system/everythingInAD.aspx

Hätte ich vllt dazu schreiben sollen, aber daher hatte ich alles bisherige, was mich aber eben nicht weitergebracht hat.
Dort wird auf lokale Gruppen eingegangen.

user profile iconTrashkid2000 hat folgendes geschrieben Zum zitierten Posting springen:
Hallo,
also erstmal ist es schon das falsche Unterforum, oder was hat das Thema mit Datenbanken zu tun?

Mag das dann jemand ins richtige Forum verschieben?

user profile iconTrashkid2000 hat folgendes geschrieben Zum zitierten Posting springen:

Aber so sollte es schon gehen:

C#-Quelltext
1:
2:
3:
DirectoryEntry localMachine = new DirectoryEntry("WinNT://" + Environment.MachineName + ",computer");
DirectoryEntry localGroup = localMachine.Children.Find("Administratoren""group");
localGroup.Invoke("Add""LDAP://CN=John Doe,CN=Users,DC=Fabrikam,DC=com");
WinNT:// -- lokales System
LDAP:// -- Domäne
LG


Vielen Dank, sah vielversprechend aus, hat aber leider nicht geklappt. Irgendwo hatte ich glaube ich mal was davon gelesen, dass "WinNT://" und "LDAP://" nicht kombiniert werden dürfen.
Ein einfaches Ersetzen von "LDAP://" mit "WinNT://" bringt keinen Erfolg.

An anderer Stelle hab ich noch gefunden, dass man den Aufruf wie folgt machen muss, aber auch das bringt mir einen Fehler.

Quelltext
1:
group.Invoke("Add", new string[]{user.Path});                    


Jetzt ist meine Überlegung, wie man den Pfad "LDAP://CN=John Doe,CN=Users,DC=Fabrikam,DC=com" in "WinNT://..."-Format darstellt?


Trashkid2000 - Di 05.07.11 13:53

So muss es aber gehen:

C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
using (DirectoryEntry localMachine = new DirectoryEntry("WinNT://" + Environment.MachineName + ",computer"))
{
   using (DirectoryEntry localGroup = localMachine.Children.Find("Administratoren""group"))
   {
      localGroup.Invoke("Add"string.Format("WinNT://{0}/{1},user""domainname""username"));
      localGroup.CommitChanges();
   }
}
Kann es leider neicht testen, da ich hier auf Arbeit zwar in einer Domäne bin, aber keine local Admin, und zu Hause bin ich zwar local Admin, habe aber keine Domäne :P
Wenn es scheitert, schaue mal bitte, was in der InnerException steht.
LG


FrederikR - Di 05.07.11 14:04

Vielen Dank, dass du dich meinem Problem annimmst.

Also das sieht glaube ich schon besser aus. Es konnt allerdings eine "UnauthorizedAccessException" (Zugriff verweigert).
Ich benutze zur Authorisierung am lokalen Client (der in der Domäne ist) die gleichen Credentials, wie für die Domäne selbst.
Muss ich den Benutzernamen in einem anderen Format übergeben?


Trashkid2000 - Di 05.07.11 15:38

user profile iconFrederikR hat folgendes geschrieben Zum zitierten Posting springen:
[...] Es konnt allerdings eine "UnauthorizedAccessException" (Zugriff verweigert)[...]
Na immerhin, dann kann es ja nicht mehr an so vielen Dingen liegen...
user profile iconFrederikR hat folgendes geschrieben Zum zitierten Posting springen:
[...] Ich benutze zur Authorisierung am lokalen Client (der in der Domäne ist) die gleichen Credentials, wie für die Domäne selbst.
Muss ich den Benutzernamen in einem anderen Format übergeben?
Naja, wenn Du Dich mit deinem Account (also schon den Domänenaccount) am System anmeldest, und dann unter diesem Account den Code ausführst müsste es (vorrausgesetzt, Du bist lokaler Admin oder hast sonst irgendwie die Berechtigung, an der Benutzerverwaltung rumzuspielen) eigentlich schon klappen.
Oder wo übergibst Du Deine Benutzerdaten sonst noch, ausser als bei der Anmeldung von Windows?


FrederikR - Mi 06.07.11 11:10

user profile iconTrashkid2000 hat folgendes geschrieben Zum zitierten Posting springen:
Naja, wenn Du Dich mit deinem Account (also schon den Domänenaccount) am System anmeldest, und dann unter diesem Account den Code ausführst müsste es (vorrausgesetzt, Du bist lokaler Admin oder hast sonst irgendwie die Berechtigung, an der Benutzerverwaltung rumzuspielen) eigentlich schon klappen.
Oder wo übergibst Du Deine Benutzerdaten sonst noch, ausser als bei der Anmeldung von Windows?

Ich melde mich nicht als Domänen-Admin an Windows an. Das ist auch Voraussetzung des Programms.
Ich übergebe die Credentials des berechtigten Users hier:

Quelltext
1:
using (DirectoryEntry localMachine = new DirectoryEntry("WinNT://" + Environment.MachineName + ",computer",username,password))                    


Trashkid2000 - Do 07.07.11 22:34

Hallo,
hast Du denn das Problem nun schon zum laufen gebracht?

Habe es einfach mal ausprobiert (ohne Dömäne, nur mit einen Dummyuser)
user profile iconFrederikR hat folgendes geschrieben Zum zitierten Posting springen:

Ich melde mich nicht als Domänen-Admin an Windows an. Das ist auch Voraussetzung des Programms.
Ich übergebe die Credentials des berechtigten Users hier:

Quelltext
1:
using (DirectoryEntry localMachine = new DirectoryEntry("WinNT://" + Environment.MachineName + ",computer",username,password))                    

Habe es genau so mal probiert. Allerdings ohne Domäne, sondern nur mit lokalem Dummyuser. Dabei habe ich meine lokalen Admin-Credentials übergeben. Ausführung des Programms unter des Context des Dummyusers:
Ergebnis: Zugriff verweigert. Trotz gültiger Angaben.

Ausführung unter den Admin-Context (ausführen als...):
Ergebnis: alles i.O. und Dummyuser wurde auch zu den Admins hinzugefügt.

Ehrlich, keine Ahnung, was da falsch ist, oder wie man die Benutzerdaten übergeben muss.
Sorry.


FrederikR - Fr 08.07.11 08:52

Hmm das ist ja ärgerlich. Vielen Dank für deine Mühe! Hat mir vielleicht trotzdem weitergeholfen.


Trashkid2000 - Fr 08.07.11 21:55

Hallo,
OMG, ich bin echt dumm!
Die Credentials, die bei der Instanziierung des DirectoryEntry übergeben werden, werden nur benötigt, wenn man sich an der Domäne anmelden muss. Also wenn der Rechner, von dem das Programm ausgeführt wird, nicht in der Domäne ist. Sorry dafür.

Also ganz falscher Weg. Der richtige Weg heißt Impersonifikation. Es muss nämlich Code unter einen anderen Benutzercontext ausgeführt werden (wenn der Benutzer, der das Programm ausführt nicht in der Admin- Gruppe ist).

Bei Codeproject gibt es dafür eine schöne, schlanke Klasse (Impersonator), die das "LogonUser" gut abnimmt. Hier mal der Link: http://www.codeproject.com/KB/cs/zetaimpersonator.aspx
So, nun mal der Code dafür: Also, ich prüfe erstmal, ob der User, unter dessen Context das Programm ausgeführt wird, in der Admin Gruppe ist. Wenn nicht, wird impersonifiziert, sonst ist das ja nicht nötig.
Naja, und dann klappt das schon so:

C#-Quelltext
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:
WindowsPrincipal principal = new WindowsPrincipal(WindowsIdentity.GetCurrent());
bool isAdmin = principal.IsInRole(WindowsBuiltInRole.Administrator);

Console.WriteLine(string.Format("Logged in as {0}", isAdmin ? "Administrator" : "User"));

Impersonator impersonator = null;
if (!isAdmin)
{
  Console.WriteLine("Start Impersonation");
  impersonator = new Impersonator("AdminUsername""Domainname""Password");
}
try
{
  using (DirectoryEntry localMachine = new DirectoryEntry("WinNT://" + Environment.MachineName + ",computer"))
  {
    using (DirectoryEntry localGroup = localMachine.Children.Find("Administratoren""group"))
    {
      localGroup.Invoke("Add"string.Format("WinNT://{0}/{1},user""domainname""username"));
      localGroup.CommitChanges();
    }
  }
  Console.WriteLine("Successfully added");
}
catch (Exception ex)
{
  Console.WriteLine(ex.Message);
}
finally
{
  if (!isAdmin && impersonator != null)
  {
    impersonator.Dispose();
    Console.WriteLine("End Impersonation");
  }
}
Console.ReadKey();
Ob Du bei der Instanziierung des Impersonators den Domainnamen mit anbegeb musst, weiß ich nicht. Wenn nicht, ist er null.
LG, Marko


FrederikR - Fr 15.07.11 10:52

Oh danke! Hab grad erst gesehen, dass du noch was geschrieben hast. Wenn ich nochmal Zeit finde, muss ich das unbedingt ausprobieren. Danke!