Willkommen auf myCSharp.de! Anmelden | kostenlos registrieren
 | Suche | FAQ

Hauptmenü
myCSharp.de
» Startseite
» Forum
» Suche
» Regeln
» Wie poste ich richtig?

Mitglieder
» Liste / Suche
» Wer ist online?

Ressourcen
» FAQ
» Artikel
» C#-Snippets
» Jobbörse
» Microsoft Docs

Team
» Kontakt
» Cookies
» Spenden
» Datenschutz
» Impressum

  • »
  • Community
  • |
  • Diskussionsforum
Name des lokalen Administrators (Windows)
niceGuy
myCSharp.de - Member



Dabei seit:
Beiträge: 6

Themenstarter:

Name des lokalen Administrators (Windows)

beantworten | zitieren | melden

Hallo Community,

Ich kann mit diesem Code den Namen der lokalen Administratorgruppe herauslesen:


using System.Security.Principal;

String sGroupAdministrators = new SecurityIdentifier(WellKnownSidType.BuiltinAdministratorsSid, null).Translate(typeof(NTAccount)).Value;
sGroupAdministrators = sGroupAdministrators.Substring(sGroupAdministrators.IndexOf('\\') + 1);

Console.WriteLine("Local Administrator Group=" + sGroupAdministrators);

Nun möchte ich den Namen des lokalen Administrators herauslesen. Mit folgendem Code funktioniert das als Applikation, nicht aber, wenn ich ihn als Dienst ausführe:


using System.Security.Principal;

String sLocalAdministratorUser = new SecurityIdentifier(WellKnownSidType.AccountAdministratorSid, WindowsIdentity.GetCurrent().User.AccountDomainSid).Translate(typeof(NTAccount)).Value;
sLocalAdministratorUser = sLocalAdministratorUser.Substring(sLocalAdministratorUser.IndexOf('\\') + 1);

Console.WriteLine("Local Administrator User=" + sLocalAdministratorUser);

Das Problem für mich ist, wie bekomme ich benötigte domainSID für "SecurityIdentifier" heraus, wenn ich den Code als Dienst laufen lasse?

Hat jemand eine Idee?
private Nachricht | Beiträge des Benutzers
Th69
myCSharp.de - Experte

Avatar #avatar-2578.jpg


Dabei seit:
Beiträge: 4.320

beantworten | zitieren | melden

Hallo und willkommen,

sollte WellKnownSidType.BuiltinAdministratorsSid, laut WellKnownSidType, nicht schon dem Administrator-Account entsprechen (und nicht der Administrator-Gruppe)?
private Nachricht | Beiträge des Benutzers
niceGuy
myCSharp.de - Member



Dabei seit:
Beiträge: 6

Themenstarter:

beantworten | zitieren | melden

Hallo Th69,

Darüber bin ich auch schon gestolpert.

AccountAdministratorSid, sollte gemäss Beschreibung die SID der Gruppe sein.
BuiltinAdministratorsSid, sollte gemäss Beschreibung die SID des Benutzers sein.

Mit meinem Code, den ich gepostet habe, passiert aber das genaue Gegenteil!
private Nachricht | Beiträge des Benutzers
Th69
myCSharp.de - Experte

Avatar #avatar-2578.jpg


Dabei seit:
Beiträge: 4.320

beantworten | zitieren | melden

Wenn ich mir die Namen anschaue (bzgl. Einzahl und Mehrzahl), so scheint wohl wirklich die Beschreibung in der (auch englischen) Doku falsch (vertauscht) zu sein.

Du kannst aus einem Dienst heraus (der ja unabhängig von einem aktuell eingeloggten User läuft) WindowsIdentity.GetCurrent() nicht benutzen (dies muß ja auch nicht zwangsläufig dann ein Administrator-Account sein).
Was passiert denn, wenn du den 2. Parameter von SecurityIdentifier(...) auf null setzt?
private Nachricht | Beiträge des Benutzers
niceGuy
myCSharp.de - Member



Dabei seit:
Beiträge: 6

Themenstarter:

beantworten | zitieren | melden

Wenn ich es mit null versuche:


String sLocalAdministratorUser = new SecurityIdentifier(WellKnownSidType.AccountAdministratorSid, null).Translate(typeof(NTAccount)).Value;
sLocalAdministratorUser = sLocalAdministratorUser.Substring(sLocalAdministratorUser.IndexOf('\\') + 1);
Console.WriteLine("Local Administrator User=" + sLocalAdministratorUser);

Ergibt dies als Resultat:
Fehler
The domainSid parameter must be specified for creating well-known SID of type AccountAdministratorSid. (Parameter 'domainSid')


Und das verwirrt mich, denn ich möchte ja den lokalen Administrator Account. Also ohne Domäne.
Dieser Beitrag wurde 1 mal editiert, zum letzten Mal von niceGuy am .
private Nachricht | Beiträge des Benutzers
Abt
myCSharp.de - Team

Avatar #avatar-4119.png


Dabei seit:
Beiträge: 15.757

beantworten | zitieren | melden

In der Doku von SecurityIdentifier steht, dass die Angabe von domainSid erforderlich ist, wenn u.a. AccountAdministratorSid angefragt wird, was Du tust.
Dass Null also zu dem Fehler führt ist nachvollziehbar.

Ansonsten stimm ich Th69 zu, WindowsIdentity.GetCurrent() kannst Du aus dem Server nicht benutzen, wenn dieser nicht mit einer Identität konfiguriert wurde - was hier wohl der Fall ist. Es ist leider nicht ersichtlich, von was von einem Service Du sprichst (Registrierter Windows Service? IIS? ...?); aber eigentlich kannst Du an allen Stellen einen Benutzer konfigurieren, in dessen Context die App ausgeführt wird.

Was soll das ganze eigentlich werden?


sLocalAdministratorUser = sLocalAdministratorUser.Substring(sLocalAdministratorUser.IndexOf('\\') + 1);
Ist übrigens auch nicht 100% safe, denn es gibt zwei potentielle Formate:
- Domain\User
- User@Domain

PS: string statt String ist die sicherere Schreibweise (gilt auch für die anderen Varianten wie Int32 etc..).
Im Gegensatz zu Früher ist die klare Empfehlung nur noch die aliase (also die type keywords) zu verwenden.
private Nachricht | Beiträge des Benutzers
Palladin007
myCSharp.de - Member

Avatar #avatar-4140.png


Dabei seit:
Beiträge: 1.761
Herkunft: Düsseldorf

beantworten | zitieren | melden

Zitat von Abt
PS: string statt String ist die sicherere Schreibweise (gilt auch für die anderen Varianten wie Int32 etc..).
Im Gegensatz zu Früher ist die klare Empfehlung nur noch die aliase (also die type keywords) zu verwenden.
Warum sicherer?
Ist doch beides äquivalent zueinander?
private Nachricht | Beiträge des Benutzers
Abt
myCSharp.de - Team

Avatar #avatar-4119.png


Dabei seit:
Beiträge: 15.757

beantworten | zitieren | melden

In der Runtime ja, während der Entwicklung nein.

Während string ein reserviertes Keyword ist, kannst Du String einfach als Klasse überschreiben.
Hat in der Vergangenheit auch zu Angriffsvektor-Möglichkeiten geführt. Ist daher nicht einfach nur eine Stil-Sache, sondern Frage der Code-Sicherheit.

String wurde damals wegen VB eingeführt, um Code leichter portieren zu können; nicht für die generelle Verwendung als string gedacht.
String als Variable verletzt auch die Coding Conventions (nicht die statischen Methoden).
private Nachricht | Beiträge des Benutzers
niceGuy
myCSharp.de - Member



Dabei seit:
Beiträge: 6

Themenstarter:

beantworten | zitieren | melden

Zitat von Abt
Es ist leider nicht ersichtlich, von was von einem Service Du sprichst (Registrierter Windows Service? IIS? ...?);
...
aber eigentlich kannst Du an allen Stellen einen Benutzer konfigurieren, in dessen Context die App ausgeführt wird.
Ein registrierter Windows Dienst der ganz normal mit SYSTEM Rechten laufen soll
Zitat von Abt


sLocalAdministratorUser = sLocalAdministratorUser.Substring(sLocalAdministratorUser.IndexOf('\\') + 1);
Ist übrigens auch nicht 100% safe, denn es gibt zwei potentielle Formate:
- Domain\User
- User@Domain
Das muss ich anschauen, wenn ich den Dienst auf einem Domänenmitglied laufen lasse.
Zitat von Abt
PS: string statt String ist die sicherere Schreibweise (gilt auch für die anderen Varianten wie Int32 etc..).
Im Gegensatz zu Früher ist die klare Empfehlung nur noch die aliase (also die type keywords) zu verwenden.
Oh, Danke, das werde ich beherzigen!

Zurück zu meinem Anliegen:
Es muss doch möglich sein, den Namen des lokalen Administrator Kontos in Erfahrung zu bringen?
private Nachricht | Beiträge des Benutzers
Abt
myCSharp.de - Team

Avatar #avatar-4119.png


Dabei seit:
Beiträge: 15.757

beantworten | zitieren | melden

Zitat von niceGuy
Ein registrierter Windows Dienst der ganz normal mit SYSTEM Rechten laufen soll
Du meinst hoffentlich nicht NT AUTHORITY \ SYSTEM.

Willst Du quasi den Output von PowerShell Get-LocalGroupMember -Group "Administrators"?
Den Quellcode dazu kann man sich ja anschauen, was die machen.

Edit: müsste dem Code entsprechen


using System.DirectoryServices.AccountManagement;
using (PrincipalContext ctx = new PrincipalContext(ContextType.Machine))
using (GroupPrincipal grp = GroupPrincipal.FindByIdentity(ctx, IdentityType.Name, "Administrators"))
{
    if (grp is not null)
    {
        foreach (Principal p in grp.GetMembers(recursive: true))
        {
            Console.WriteLine(p.Name);
        }
    }
}
Liefert bei mir gleiches Ergebnis wie PowerShell, beide lokalen Admin Account Names.

Ansonsten stimmt halt Dein Konzept schon nicht.
Es gibt fix kein einzelnes Konto mit dem Namen Administrator, sondern nur eine Gruppe Administrators.
Und darin können beliebig viele User sein. Du musst also immer über Gruppen gehen bei einem Role-based Authorization Konzept, wie es Windows bzw. (Azure) Active Directory hat.
private Nachricht | Beiträge des Benutzers
niceGuy
myCSharp.de - Member



Dabei seit:
Beiträge: 6

Themenstarter:

beantworten | zitieren | melden

Da die SID des lokalen Administrator Accounts immer mit "S-1-5-21-" beginnt und mit "-500" endet, kann ich den Namen des Kontos hiermit lesen:


string sLocalAdministratorUser = "";

ManagementScope scope = new(@"\\.\root\CIMV2");
scope.Connect();

ObjectQuery query = new("SELECT Name from Win32_UserAccount WHERE SID LIKE 'S-1-5-21%-500'");
ManagementObjectSearcher searcher = new(scope, query);

ManagementObjectCollection results = searcher.Get();

foreach (var item in results)
{
	sLocalAdministratorUser = item["Name"].ToString();
	break;
}

Console.WriteLine("Local Administrator User=" + sLocalAdministratorUser);

Bezüglich der absoluten Aussage immer:
How Can I Determine if the Local Administrator Account has been Renamed on a Computer?

Was ich noch nicht begriffen habe ist, wie ich direkt auf das erste und einzige item zugreifen kann, statt über eine abgebrochene foreach Schlaufe.
private Nachricht | Beiträge des Benutzers
Abt
myCSharp.de - Team

Avatar #avatar-4119.png


Dabei seit:
Beiträge: 15.757

beantworten | zitieren | melden

Weil der Gedanke
Zitat
Was ich noch nicht begriffen habe ist, wie ich direkt auf das erste und einzige item zugreifen kann, statt über eine abgebrochene foreach Schlaufe.
nicht korrekt ist.

Weil
Zitat von Abt
Ansonsten stimmt halt Dein Konzept schon nicht.
Es gibt fix kein einzelnes Konto mit dem Namen Administrator, sondern nur eine Gruppe Administrators.
Und darin können beliebig viele User sein.
Du musst also *immer* mit mehreren Treffern rechnen. Gibt keine Garantie, dass es nur "ein einziges, erstes Item" ist.
Darüber hinaus machst Du auf umständliche Art und Weise (nun via WMI), was Du eben auch mit dem System.DirectoryServices.AccountManagement Namespace direkt machen kannst.

Aber wie gesagt; Deine Grundvorgehen ist falsch, weil
Zitat
bei einem Role-based Authorization Konzept, wie es Windows bzw. (Azure) Active Directory hat

PS: Nicht eine Admingruppe auf meiner Rechner endet mit 500.
private Nachricht | Beiträge des Benutzers
niceGuy
myCSharp.de - Member



Dabei seit:
Beiträge: 6

Themenstarter:

beantworten | zitieren | melden

Zitat von Abt
Aber wie gesagt; Deine Grundvorgehen ist falsch, weil
Zitat
bei einem Role-based Authorization Konzept, wie es Windows bzw. (Azure) Active Directory hat

Viele Dank für Deine Ausführungen.

Vermutlich schreiben wir aneinander vorbei:
Ich benötige den aktuellen Namen des lokalen Administrator Kontos.
--> Das Originale, echte welches Microsoft vorgesehen hat.
Kein zusätzlich in die lokale Administratorgruppe hinzugefügtes Benutzerkonto.

Das wäre in meinem Fall dieses Konto welches ebenfalls in der lokalen Admingruppe ist:
S-1-5-21-nnnnnnnnnn-nnnnnnnnnn-nnnnnnnnnn-1001
--> Diese SID (und weitere Mitglieder der lokalen Admingruppe) endet mit etwas anderem als -500

Ich orientiere mich dabei an folgendem devblog Eintrag und gehe davon aus, dass der Autor über die benötigten internen Informationen bei Microsoft verfügt:
https://devblogs.microsoft.com/scripting/how-can-i-determine-if-the-local-administrator-account-has-been-renamed-on-a-computer

Vermutlich wird es noch weitere Wege geben. Für den Moment habe ich eine Lösung die sprachenunabhängig und domänenunabhängig mir den lokalen Administrator nennt.
private Nachricht | Beiträge des Benutzers
Abt
myCSharp.de - Team

Avatar #avatar-4119.png


Dabei seit:
Beiträge: 15.757

beantworten | zitieren | melden

Hab ich verstanden; trotzdem interessiert es die Windows Schnittstelle nicht was Du logisch (ein Item) brauchst, wenn die Technik eben mit einer Liste arbeitet.
Entsprechend sind die Windows und .NET Schnittstellen. Wenn die Liste in Deiner Logik eben immer nur ein Treffer hat, dann musst Du das technisch umsetzen; zB mit Linq FirstOrDefault oder SingleOrDefault etc...

Der Blogartikel, den Du verlinkst, ist 17 Jahre alt. Ich würde nun nicht unbedingt viel drauf wetten, dass das heute noch so ist.
Beim Windows Accountmanagement hat sich enorm viel getan seit 2015.

Wie Du schon selbst bemerkt hast, endet die Administratorsgruppe nicht zwangsläufig mit 500, obwohl es so im Artikel steht.
Es gibt kein verlässliches Merkmal, das den ersten lokalen Admin-User eindeutig kennzeichnet.

Und wie gesagt: kannst auch komplett auf WMI verzichten und einfach typsicher den PrincipalSearcher nehmen.
private Nachricht | Beiträge des Benutzers