2009-01-31 4 views
50

Ich habe eine C# -Anwendung, die ein Verzeichnis scannt und einige Informationen sammelt. Ich möchte den Kontonamen für jede Datei anzeigen. Ich kann, indem man die SID für das Fileinfo-Objekt auf dem lokalen System dies tun, und dann tun:Wie kann ich von einer SID zu einem Kontoname in C# konvertieren

string GetNameFromSID(SecurityIdentifier sid) 
{ 
    NTAccount ntAccount = (NTAccount)sid.Translate(typeof(NTAccount)); 
    return ntAccount.ToString(); 
} 

Dies ist jedoch nicht in einem Netzwerk für Dateien funktioniert, vermutlich weil die Translate() Funktion funktioniert nur mit lokale Benutzerkonten Ich dachte, vielleicht könnte ich auf der SID eine LDAP-Lookup, so habe ich versucht, die folgenden:

string GetNameFromSID(SecurityIdentifier sid) 
{ 
    string str = "LDAP://<SID=" + sid.Value + ">"; 
    DirectoryEntry dirEntry = new DirectoryEntry(str); 
    return dirEntry.Name; 
} 

Dies scheint, wie es funktionieren wird, dass in dem Zugriff auf „dirEntry.Name“ hängt für einige Sekunden, als wenn es abgeht und das Netzwerk abfragt, aber dann wirft es eine System.Runtime.InteropServices.COMException

Weiß jemand, wie ich den Kontonamen einer beliebigen Datei oder SID bekommen kann? Ich weiß nicht viel über Netzwerk oder LDAP oder so. Es gibt eine Klasse namens DirectorySearcher, die ich vielleicht benutzen soll, aber sie möchte einen Domain-Namen, und ich weiß auch nicht, wie ich das bekommen soll - ich habe nur den Pfad zu dem Verzeichnis, das ich scanne.

Vielen Dank im Voraus.

+0

Gibt es eine bestimmte Nachricht, die die COMException zeigt? –

+0

Es könnte eine Gruppenrichtlinie sein und Ihnen erlauben, den Verzeichnisdienst lokal zu durchlaufen, deshalb erhalten Sie die COM-Ausnahme. Was zeigt die Fehlermeldung? Versuchen Sie, filemon auf dem Netzwerkcomputer auszuführen, warum Sie darauf zugreifen und die Ergebnisse sehen. –

+0

Ich meinte "Gruppenrichtlinie nicht erlaubt ..." –

Antwort

15

Die Translate-Methode des SecurityReference-Objekts funktioniert auf nicht lokalen SIDs, aber nur für Domänenkonten. Für Accounts, die sich lokal auf einem anderen Rechner oder in einem Nicht-Domänen-Setup befinden, müssten Sie die Funktion LookupAccountSid aufrufen, um den spezifischen Rechnernamen anzugeben, auf dem die Suche ausgeführt werden soll.

+2

Ich habe gerade angefangen, etwas Code zu schreiben, um etwas Ähnliches zu tun und fand dies korrekt. P/Invoking LookupAccountSid ist besser als die Verwendung von SecurityIdentifier.Translate(). Ich arbeite in einer Multi-Forest/Domain-Umgebung mit 60.000 Benutzern. –

0

Dieser ist ein Stumper. Sie sind in einer Active Directory-Umgebung richtig? Nur :) Überprüfung

Wie auch immer, statt Bindung mit sid.Value,

string str = "LDAP://<SID=" + sid.Value + ">"; 

Ich würde versuchen, die Byte-Array SID Umwandlung in eine Octet String und binden mit diesem statt.

Es gibt ein nettes Beispiel here auf Seite 78. Dies bringt Sie näher. Um ehrlich zu sein, habe ich noch nie versucht, eine SID zu binden. Aber ich hatte Erfolgsbindung mit der GUID eines Benutzers aber :)

Viel Glück und lassen Sie mich wissen, wie es geht.

1

Ooh, dann ist es möglich, dass der LDAP-Aufruf nicht funktioniert, weil Sie möglicherweise nicht in einer Active Directory-Umgebung sind. Wenn dies der Fall ist, ist jeder Ihrer Computer für seinen eigenen Identitätsspeicher verantwortlich. Und Ihr erstes Codebeispiel funktioniert nicht über das Netzwerk, da der Computer, auf dem Sie Ihren Code ausführen, nicht wissen, wie die SID aufgelöst werden soll, die nur auf dem Remotecomputer sinnvoll ist.

Sie sollten wirklich überprüfen, ob Ihre Maschinen Teil eines Active Directory sind. Sie würden dies während des Anmeldevorgangs wissen. Oder Sie können prüfen, indem Sie mit der rechten Maustaste auf "Arbeitsplatz" klicken, "Eigenschaften" auswählen, den "Computernamen" -Register und dann sehen, ob Ihr Computer Teil einer Domäne ist.

-2

Ich bin ziemlich sicher, dass Sie in der Lage sein wird, von hier aus die akzeptierte Antwort zu verwenden: Determine the LocalSystem account name using C#

Grundsätzlich können Sie eine Instanz der Klasse Security übersetzen NTAccount zu geben, von dem aus Sie den Benutzernamen erhalten können. In Code:

using System.Security.Principal; 

SecurityIdentifier sid = new SecurityIdentifier("S-1-5-18"); 
NTAccount acct = (NTAccount)sid.Translate(typeof(NTAccount)); 
Console.WriteLine(acct.Value); 
+3

Während dies nicht falsch ist, wiederholt es nur den Code, auf den das Plakat bereits hingewiesen hat, funktioniert nicht in seiner Situation. –

1

Großartig. Ich cribbed einige LookupAccountSid() Code von hier:

http://www.pinvoke.net/default.aspx/advapi32.LookupAccountSid

Und das funktionierte, obwohl ich den Host-Namen selbst zu bieten hatte. Im Falle eines UNC-Pfades kann ich einfach die erste Komponente davon nehmen. Wenn es ein zugeordnetes Laufwerk, verwende ich diesen Code den Pfad zu einem einem UNC zu konvertieren:

http://www.wiredprairie.us/blog/index.php/archives/22

Es scheint zu funktionieren, so das ist, wie ich es tun würde, es sei denn, jemand mit einer Situation kommt in die erste Komponente eines UNC-Pfades ist nicht der Hostname ...

Vielen Dank für Ihre Hilfe.

37

Sehen Sie hier für eine gute Antwort:

The best way to resolve display username by SID?

Der Kern ist dieser Bit:

string sid="S-1-5-21-789336058-507921405-854245398-9938"; 
string account = new System.Security.Principal.SecurityIdentifier(sid).Translate(typeof(System.Security.Principal.NTAccount)).ToString(); 

Dieser Ansatz funktioniert für mich für nicht-lokal SID über das aktive Verzeichnis.

+1

Dieser Ansatz funktionierte für mich so wie er ist. –

+1

Danke, es hat mir geholfen, den Benutzernamen des Benutzers von einer vertrauenswürdigen Domäne zu erhalten. –

0

die aktuellen Domain-Adresse:

System.DirectoryServices.ActiveDirectory.Domain.GetCurrentDomain(); 

Holen Sie sich einen Verzeichniseintrag von LDAP- und den Domain-Namen:

DirectoryEntry de = new DirectoryEntry(string.Format("LDAP://{0}", domain)); 

Holen Sie sich das sid von einem ActiveDirectoryMembershipProvider ActiveDirectoryMembershipUser:

ActiveDirectoryMembershipUser user = (ActiveDirectoryMembershipUser)Membership.GetUser(); 
var sid = (SecurityIdentifier)user.ProviderUserKey; 

Get der Benutzername aus dem SecurityIdentifier:

(NTAccount)sid.Translate(typeof(NTAccount)); 

Get Verzeichnissuche auf einem ActiveDirectory- mit dem Domain-Verzeichniseintrag und Benutzername gemacht:

DirectorySearcher search = new DirectorySearcher(entry); 
     search.Filter = string.Format("(SAMAccountName={0})", username); 
     search.PropertiesToLoad.Add("Name"); 
     search.PropertiesToLoad.Add("displayName"); 
     search.PropertiesToLoad.Add("company"); 
     search.PropertiesToLoad.Add("homePhone"); 
     search.PropertiesToLoad.Add("mail"); 
     search.PropertiesToLoad.Add("givenName"); 
     search.PropertiesToLoad.Add("lastLogon"); 
     search.PropertiesToLoad.Add("userPrincipalName"); 
     search.PropertiesToLoad.Add("st"); 
     search.PropertiesToLoad.Add("sn"); 
     search.PropertiesToLoad.Add("telephoneNumber"); 
     search.PropertiesToLoad.Add("postalCode"); 
     SearchResult result = search.FindOne(); 
     if (result != null) 
     { 
      foreach (string key in result.Properties.PropertyNames) 
      { 
       // Each property contains a collection of its own 
       // that may contain multiple values 
       foreach (Object propValue in result.Properties[key]) 
       { 
        outputString += key + " = " + propValue + ".<br/>"; 
       } 
      } 
     } 

Abhängig von den Daten in Ihrem Active Directory finden Sie eine abwechslungsreiche Antwort in der Ausgabe erhalten.

Here is a site that has all the user properties I needed:

5

System.DirectoryServices.AccountManagement.UserPrincipal Klasse (msdn link) hat eine statische Funktion FindByIdentity einen SID in ein User-Objekt zu konvertieren. Es sollte in der Lage sein, sowohl gegen den lokalen Rechner als auch gegen einen LDAP/Active Directory Server zu arbeiten. Ich habe es nur gegen Active Directory verwendet.Hier

ist ein Beispiel, das ich in IIS verwendet haben:

// Set the search context to a specific domain in active directory 
var searchContext = new PrincipalContext(ContextType.Domain, "YOURDOMAIN", "OU=SomeOU,DC=YourCompany,DC=com"); 
// get the currently logged in user from IIS 
MembershipUser aspUser = Membership.GetUser(); 
// get the SID of the user (stored in the SecurityIdentifier class) 
var sid = aspUser.ProviderUserKey as System.Security.Principal.SecurityIdentifier; 
// get the ActiveDirectory user object using the SID (sid.Value returns the SID in string form) 
var adUser = UserPrincipal.FindByIdentity(searchContext, IdentityType.Sid, sid.Value); 
// do stuff to user, look up group membership, etc. 
+1

Dies ist der richtige Weg, um fremde Domains abzufragen. P/Invoke ist nicht erforderlich. –

1

Sie können auch Kontonamen von Sonderkonten wie „Jeder“ mit Code wie diese erhalten, die ungeachtet der Benutzerspracheinstellungen funktioniert:

SecurityIdentifier everyoneSid = new SecurityIdentifier(WellKnownSidType.WorldSid, null); 
    string everyone = everyoneSid.Translate(typeof(System.Security.Principal.NTAccount)).ToString(); 
+0

Sie haben gerade mein Leben gerettet! – lukiller

1

In C#, erhalten die Benutzer-SID und zuweisen zu einem String-Variable durch:

string strUser = System.Security.Principal.WindowsIdentity.GetCurrent().User.ToString(); 

Sie müssen die Zeichenfolge verwenden, da die Fähigkeit, den Benutzernamen aufzulösen, die Zeichenfolge unterstützt. Mit anderen Worten, die Verwendung von var varUser führt zu einem Namespace-Fehler.

string strUserName = new System.Security.Principal.SecurityIdentifier(strUser).Translate(typeof(System.Security.Principal.NTAccount)).ToString(); 
Verwandte Themen