Benutzer AD-Gruppen filtern Batch
Hey zusammen,
für ein kleines Projekt muss ich zum Entwickeln einer Applikation die Gruppenmitgliedschaften im AD eines Benutzers abfragen. Wenn der Benutzer Mitglied von bestimmten Gruppen ist, bekommt er je nach Gruppe bestimmte Möglichkeiten in der Applikation zum bearbeiten von Dokumenten.
Die App programmiere ich in C# / WPF. Gibt es eine Möglichkeit, dort zu Beginn des Programms eine Abfrage zu starten, zu welchen Gruppen der ausführende Benutzer im AD gehört?
Bestimmt gibt es dafür eine einfache Möglichkeit mit irgendwelchen .NET Eigenschaften, die ich leider nur nicht kenne...
Ich habe aber herausgefunden, dass man in einem C# Programm auch die Möglichkeit hat, CMD Befehle auszuführen und deren Ergebnis in einem String zu erhalten.
Dieser Befehl speichert mir den Benutzernamen in der Variable user ab.
Wie genau das funktioniert habe ich noch nicht ganz verstanden mit den Tokens, aber es ist wohl so, dass ich die 1. Zahl, die ich im Token angebe (hier 2) der Teil ist, welcher in der Definierten Variable (hier %a) gespeichert wird. Alle weiteren würden wohl in fortlaufenden Tokens gespeichert werden? (also %b, %c, %d etc., sollte ich tokens=2,3,4-8,9* angeben)
Lange Rede kurzer Sinn, ich erhalte durch whoami das Ergebnis: DOMAIN\username, welches ich an "\" splitte und nur den 2. Teil in "user" speichere.
Der Befehl gibt mir nun einen Haufen von Informationen zu dem AD-User (ich schätze einfach mal AD Informationen) zurück. Darunter auch "Globale Gruppenmitgliedschaften", die Gruppen, in welcher der AD-Benutzer Mitglied ist.
Diese möchte ich nun auf bestimmte Gruppen prüfen. Das Ergebnis kann entweder "null" sein, da der Benutzer kein Mitglied einer der benötigten Gruppen ist, eine der Gruppen oder auch mehrere Gruppen...
Wie genau kann ich diese Gruppen filtern, um beispielsweise nur die Gruppen zu erhalten, welche mit "E-" beginnen, also E mit Bindestrich?
Wenn das möglich ist, dann würde ich gerne diese Gruppennamen in einer Variable speichern.
Die Gruppen sind immer in einer Zeile mit mehreren Leerzeichen, dann einem * gefolgt von den Gruppennamen. Ich gehe davon aus, dass sich das mit eben derselben Vorgehensweise lösen lässt:
Der net user befehl gibt einige für mich uninteressanten Zeilen zurück gefolgt von:
Globale Gruppenmitliedschaften ::::::::::: *Gruppenname1
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: *Gruppenname2
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: *Gruppenname3
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: *Gruppenname4
(Die ::::: wegdenken, habe ich eingefügt da die Leerzeichen hier einfach getrimmt werden :\ also ::::: eigentlich = whitespace
Diese möchte ich in temp speichern, falls der Gruppenname mit "E-" beginnt.
Vielen lieben Dank schonmal im Voraus,
Micha
für ein kleines Projekt muss ich zum Entwickeln einer Applikation die Gruppenmitgliedschaften im AD eines Benutzers abfragen. Wenn der Benutzer Mitglied von bestimmten Gruppen ist, bekommt er je nach Gruppe bestimmte Möglichkeiten in der Applikation zum bearbeiten von Dokumenten.
Die App programmiere ich in C# / WPF. Gibt es eine Möglichkeit, dort zu Beginn des Programms eine Abfrage zu starten, zu welchen Gruppen der ausführende Benutzer im AD gehört?
Bestimmt gibt es dafür eine einfache Möglichkeit mit irgendwelchen .NET Eigenschaften, die ich leider nur nicht kenne...
Ich habe aber herausgefunden, dass man in einem C# Programm auch die Möglichkeit hat, CMD Befehle auszuführen und deren Ergebnis in einem String zu erhalten.
FOR /f "tokens=2 delims=\" %a IN ('whoami') DO SET user=%a
Wie genau das funktioniert habe ich noch nicht ganz verstanden mit den Tokens, aber es ist wohl so, dass ich die 1. Zahl, die ich im Token angebe (hier 2) der Teil ist, welcher in der Definierten Variable (hier %a) gespeichert wird. Alle weiteren würden wohl in fortlaufenden Tokens gespeichert werden? (also %b, %c, %d etc., sollte ich tokens=2,3,4-8,9* angeben)
Lange Rede kurzer Sinn, ich erhalte durch whoami das Ergebnis: DOMAIN\username, welches ich an "\" splitte und nur den 2. Teil in "user" speichere.
NET USER /domain "%user%"
Diese möchte ich nun auf bestimmte Gruppen prüfen. Das Ergebnis kann entweder "null" sein, da der Benutzer kein Mitglied einer der benötigten Gruppen ist, eine der Gruppen oder auch mehrere Gruppen...
Wie genau kann ich diese Gruppen filtern, um beispielsweise nur die Gruppen zu erhalten, welche mit "E-" beginnen, also E mit Bindestrich?
Wenn das möglich ist, dann würde ich gerne diese Gruppennamen in einer Variable speichern.
Die Gruppen sind immer in einer Zeile mit mehreren Leerzeichen, dann einem * gefolgt von den Gruppennamen. Ich gehe davon aus, dass sich das mit eben derselben Vorgehensweise lösen lässt:
SET temp=
FOR /f "tokens=?? delims=??" %a IN ('NET USER /domain "%user%"') DO SET temp=%temp% , %a%b%c
Der net user befehl gibt einige für mich uninteressanten Zeilen zurück gefolgt von:
Globale Gruppenmitliedschaften ::::::::::: *Gruppenname1
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: *Gruppenname2
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: *Gruppenname3
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: *Gruppenname4
(Die ::::: wegdenken, habe ich eingefügt da die Leerzeichen hier einfach getrimmt werden :\ also ::::: eigentlich = whitespace
Diese möchte ich in temp speichern, falls der Gruppenname mit "E-" beginnt.
Vielen lieben Dank schonmal im Voraus,
Micha
Please also mark the comments that contributed to the solution of the article
Content-ID: 6710125018
Url: https://administrator.de/contentid/6710125018
Printed on: September 14, 2024 at 11:09 o'clock
27 Comments
Latest comment
Hi,
Gleich der erste Link in meiner Google-Suche:
https://dotnet-snippets.de/snippet/activedirectory-gruppen-eines-benutze ...
Gleich der erste Link in meiner Google-Suche:
https://dotnet-snippets.de/snippet/activedirectory-gruppen-eines-benutze ...
🤷♂️🤣 Fragen kostet ja nichts.
Alles gut. Google ist ja auch immer so eine Sache. Du bist aber in ein anderes Fettnäpfchen getreten: Batch. Manche machen da schon zu, da man vieles mit PowerShell erledigt. Geht soweit, dass PS Execute in Batch verschachtelt wird, um die Leute dahin zu bringen.
Nativ mit C# ist natürlich bei MS das Mittel der Wahl.
Wenn du aber eh schon in C# unterwegs bist wirst du auch mit PS zurecht kommen und damit Lücken schließen können, die in C# zu einer gewissen Zeit vlt. zuviel Aufwand machen.
Zitat von @Crusher79:
Alles gut. Google ist ja auch immer so eine Sache. Du bist aber in ein anderes Fettnäpfchen getreten: Batch. Manche machen da schon zu, da man vieles mit PowerShell erledigt.
Alles gut. Google ist ja auch immer so eine Sache. Du bist aber in ein anderes Fettnäpfchen getreten: Batch. Manche machen da schon zu, da man vieles mit PowerShell erledigt.
Igittigitt... Wenn ich Batch schon höre.. 🤣🤣
Na! Ganz nutzlos ist es ja nicht.
Zitat von @Crusher79:
Ja stimmt. Arbeite auch mit allen. Nur du weisst selber das wir hier zig Anfragen bezüglich Auslesen oder Manipulation von System Eigenschaften haben. Das ist mit Bacht halt nich so elegant, als wie wenn ich gleich Objekte zurück bekomme und übergeben kann
Ja stimmt. Arbeite auch mit allen. Nur du weisst selber das wir hier zig Anfragen bezüglich Auslesen oder Manipulation von System Eigenschaften haben. Das ist mit Bacht halt nich so elegant, als wie wenn ich gleich Objekte zurück bekomme und übergeben kann
Ja richtig! Wenn die die Daten weiterverarbeiten werden sollen ist Batch genau das verkehrte, da die einfach als Text daherkommen.
PS in C# finde ich allerdings nicht so smooth, C# in PS ist aber ganz geil. Ausgenommen C# CmdLets ...manchmal 🤷♂️😅
Ja stimmt. Die Grenzen verwischen sich. Interessant ist vor allem das man DLLs in PowerShell einbinden kann.
Hab mit < 10 Zeilen Barcode Scanner in Script aufgenommen. Einschl. slice des Bildes und Übergabe des Ausschnitts an die DLL.
Manche rümpfen jetzt starkt die Nase: hab auch Bock mal wieder was mit Magic XPA zu machen. 4 GL. Zumindest in puncto Geschwindigkeit beim proggen unschlagbar. Auch wenn etwas umständlich. Und auch C# Snippets kann man direkt eingeben und damit arbeiten.
Irgendwie schweifen wir ab
Hab mit < 10 Zeilen Barcode Scanner in Script aufgenommen. Einschl. slice des Bildes und Übergabe des Ausschnitts an die DLL.
Manche rümpfen jetzt starkt die Nase: hab auch Bock mal wieder was mit Magic XPA zu machen. 4 GL. Zumindest in puncto Geschwindigkeit beim proggen unschlagbar. Auch wenn etwas umständlich. Und auch C# Snippets kann man direkt eingeben und damit arbeiten.
Irgendwie schweifen wir ab
Easy ...
Oder PowerShell ohne Abhängigkeiten
in ne Batch eingebaut
usw.
1001 possibilities ...
Cheers briggs
dsquery user -samid %username% | dsget user -memberof
[adsisearcher]::new("(SamAccountName=$env:Username)","memberOf").FindOne() | %{$_.Properties['memberof']}
@echo off
PowerShell -EP Bypass -C "[adsisearcher]::new(\"(SamAccountName=$env:Username)\",'memberOf').FindOne() | foreach{$_.Properties['memberof']}"
1001 possibilities ...
Cheers briggs
Zitat von @michi.wtr:
Also ich wollte gerade mal ausprobieren, das Ganze mit System.DirectoryServices anzuschauen, leider aber habe ich diesen namespace wohl nicht. Muss man dafür etwas herunterladen oder importieren zuerst? Nicht dass man hierfür die Windows Capability für AD aktiviert haben muss....
Was meinst du aktuell? Das Thema an sich? Das Beispiel das ich dir gepostet habe? Ich habe mir das jetzt nicht groß angesehen, aber du hast bestimmt bemerkt, dass du ein paar Assemblies einbinden musst:Also ich wollte gerade mal ausprobieren, das Ganze mit System.DirectoryServices anzuschauen, leider aber habe ich diesen namespace wohl nicht. Muss man dafür etwas herunterladen oder importieren zuerst? Nicht dass man hierfür die Windows Capability für AD aktiviert haben muss....
using System.DirectoryServices;
using System.DirectoryServices.ActiveDirectory;
Ja mit PowerShell wäre es mir sowieso am liebsten, aber da ich auch dort glaube ich erst das Modul für AD bräuchte.
Das ist richtig, aber es lässt sich ja zur Laufzeit problemlos nachladen. Siehe dazu (unteres Drittel):https://www.imanami.com/get-aduser-not-recognized/#:~:text=Error%3A%20Ge ....
Irgendwie kann man das glaube ich auch ohne Modul mit Klassen, CimClassen oder so machen, jedoch kenne ich mich da noch gar nicht aus.
Da wäre eventuell dieser Artikel hilfreich:https://devblogs.microsoft.com/powershell-community/how-do-i-discover-ch ...
Aber dachte wenn es so einfach mit net user geht dann tu ich mir lieber das an, da der Befehl auch zu 100% auf allen Clients später auch funktioniert.
Wie gesagt! Da bekommst du halt einen String zurück mit ganz viel Schrott drinnen. Den erst mal programmatikalisch aufzudröseln und die wichtigen Infos zu filtern ist buggy und aufwändig.Zitat von @mayho33:
Ja richtig! Wenn die die Daten weiterverarbeiten werden sollen ist Batch genau das verkehrte, da die einfach als Text daherkommen.
Ja richtig! Wenn die die Daten weiterverarbeiten werden sollen ist Batch genau das verkehrte, da die einfach als Text daherkommen.
Natürlich ist es dann auch sinnvoller die Ausgabe von net user als String mit C# zu verarbeiten...
hat mich nur interessiert wie es denn mit Batch funktionieren würde.
Dazu kann ich nur folgendes sagen: Es funktioniert beschissen 😂😂🤦♂️Zitat von @6247018886:
Oder PowerShell ohne Abhängigkeiten
in ne Batch eingebaut
dsquery user -samid %username% | dsget user -memberof
[adsisearcher]::new("(SamAccountName=$env:Username)","memberOf").FindOne() | %{$_.Properties['memberof']}
@echo off
PowerShell -EP Bypass -C "[adsisearcher]::new(\"(SamAccountName=$env:Username)\",'memberOf').FindOne() | foreach{$_.Properties['memberof']}"
Smoooooth ! 👍👍
Zitat von @michi.wtr:
Also ich wollte gerade mal ausprobieren, das Ganze mit System.DirectoryServices anzuschauen, leider aber habe ich diesen namespace wohl nicht. Muss man dafür etwas herunterladen oder importieren zuerst? Nicht dass man hierfür die Windows Capability für AD aktiviert haben muss....
Also ich wollte gerade mal ausprobieren, das Ganze mit System.DirectoryServices anzuschauen, leider aber habe ich diesen namespace wohl nicht. Muss man dafür etwas herunterladen oder importieren zuerst? Nicht dass man hierfür die Windows Capability für AD aktiviert haben muss....
Ich habe etwas Erfahrung hiermit, da ich für unsere IT eine eigene AD-Benutzerverwaltung programmiert habe (inkl. an unser System angepasstes Erstellen neuer Benutzer etc).
Du musst deinem Projekt einen Verweis zu System.DirectoryServices.AccountManagement hinzufügen.
Dazu im Menü auf Projekt -> Verweis hinzufügen und dann unter Assemblys System.DirectoryServices.AccountManagement anhaken und OK drücken.
Hier eine Funktion zum abrufen der Gruppen eines Users:
public List<GroupPrincipal> GetGroups(string userName)
{
List<GroupPrincipal> result = new List<GroupPrincipal>();
PrincipalContext yourDomain = new PrincipalContext(ContextType.Domain);
UserPrincipal user = UserPrincipal.FindByIdentity(yourDomain, userName);
if (user != null)
{
PrincipalSearchResult<Principal> groups = user.GetAuthorizationGroups();
foreach (Principal p in groups)
{
if (null != p.DistinguishedName )
{
result.Add((GroupPrincipal)p);
}
}
}
return result;
}
}
Zitat von @michi.wtr:
Ah okay, denke das wird es sein
Zitat von @Crusher79:
NuGet Console:
Fertig.
NuGet Console:
NuGet\Install-Package System.DirectoryServices -Version 4.0.0
Fertig.
Ah okay, denke das wird es sein
Jup.
Bei den Snippets muss man immer aufpassen. Oft fehlt da was. Google hilft meist.
using System.DirectoryServices missing
missing, not found - liefert da meist schnell Hilfe
dsquery ist teil des AD RSAT-Pakets
Naja auch bei Forms müssen die Dateien ja erst eröffnet werden. Also mal Button Event belegen.
GetGroupsOfMember("NAME");
Darf nicht leer sein! Name ist der Benutzername.
Mit dem Result mache ich hier natürlichnichts! Wenn du Breakpoint auf
setzt siehst du aber das Ergebnis!
GetGroupsOfMember("NAME");
Darf nicht leer sein! Name ist der Benutzername.
Mit dem Result mache ich hier natürlichnichts! Wenn du Breakpoint auf
return groups;
setzt siehst du aber das Ergebnis!
using System.DirectoryServices;
using System.DirectoryServices.ActiveDirectory;
namespace AD_Test_Forms
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
/// <summary>
/// Ermittelt alle Gruppen die ein bestimmter User gehört.
/// </summary>
/// <param name="username">
/// Windows-NT-Anmeldename des Benutzers für welchen die Gruppenzugehörigkeit ermittelt werden soll
/// </param>
/// <returns>
/// eine Liste mit den Gruppennamen
/// </returns>
private List<String> GetGroupsOfMember(string username)
{
List<string> groups = new List<string>();
// Objekt für AD-Abfrage erzeugen
using (DirectorySearcher searcher = new DirectorySearcher(new DirectoryEntry(string.Empty)))
{
// nach Kriterium filtern - hier nach Gruppe mit einem best. Namen (Inhalt von 'username')
searcher.Filter = string.Concat(string.Format(@"(&(ObjectClass=user)(sAMAccountName={0}))", username));
// Anfrage mit gesetzteen Filter ausführen und Ergebnisse durch iterieren
foreach (SearchResult result in searcher.FindAll())
{
// Eigenschaft 'MemberOf' des AD-Knotenpunktes 'result' durch iterieren
foreach (var group in result.Properties["MemberOf"])
{
// cast von 'group' zum Datentyp 'string' sollte nicht möglich sein, wird 'groupResult' 'null'
string groupResult = group as string;
if (groupResult != null)
{
// CN aus dem Pfad extrahieren und zur Liste hinzufügen
groups.Add(groupResult.Substring(3, groupResult.IndexOf(',') - 3));
}
}
}
}
// sollte nichts ermittelt worden sein, "- kein Eintrag gefunden -" in Liste einfügen
if (groups.Count < 1)
groups.Add("- kein Eintrag gefunden -");
return groups;
}
private void button1_Click(object sender, EventArgs e)
{
GetGroupsOfMember("NAME");
}
}
}
Da gefällt mir meine Funktion besser
public List<GroupPrincipal> GetGroups(string userName)
{
List<GroupPrincipal> result = new List<GroupPrincipal>();
PrincipalContext yourDomain = new PrincipalContext(ContextType.Domain);
UserPrincipal user = UserPrincipal.FindByIdentity(yourDomain, userName);
if (user != null)
{
PrincipalSearchResult<Principal> groups = user.GetAuthorizationGroups();
foreach (Principal p in groups)
{
if (null != p.DistinguishedName )
{
result.Add((GroupPrincipal)p);
}
}
}
return result;
}
}
Naja hab nur mal das Snippet von oben aufgenommen
Aber du weisst ja auch, es kommt auf die Umgebung an. Konsolen-Anwendung oder GUI. private ... kann man ja nicht irgendwo hin pflanzen.
War noch mal als kurz Hinweise gedacht, was z.B. nach Button-Event ausgelöst werden kann.
Klar gibt es schönere.
Zitat von @3063370895:
Da gefällt mir meine Funktion besser
Da gefällt mir meine Funktion besser
Wichtig zu wissen: hier werden auch nested groups mit aufgelistet.