2009-01-31 5 views
50

У меня есть приложение C#, которое сканирует каталог и собирает некоторую информацию. Я хотел бы отобразить имя учетной записи для каждого файла. Я могу сделать это на локальной системе, получая SID для объекта FileInfo, а затем делать:Как я могу конвертировать из SID в имя учетной записи в C#

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

Однако, это не работает для файлов в сети, по-видимому, потому что функция Перевести() работает только с локальные учетные записи пользователей. Я подумал, что я мог бы сделать поиск LDAP на SID, поэтому я попытался следующее:

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

Это кажется, что он будет работать, в том, что доступ к «dirEntry.Name» зависает на несколько секунд, как если он отключается и запрашивает сеть, но затем он генерирует System.Runtime.InteropServices.COMException

Кто-нибудь знает, как я могу получить имя учетной записи для произвольного файла или SID? Я мало знаю о сети или LDAP или что-то еще. Есть класс под названием DirectorySearcher, который, возможно, я должен использовать, но он хочет имя домена, и я не знаю, как это получить - все, что у меня есть, - путь к каталогу, который я просматриваю.

Заранее спасибо.

+0

Есть ли специальное сообщение, которое показывает COMException? –

+0

Это может быть групповая политика, позволяющая выполнять локальную службу каталогов, поэтому вы получаете исключение COM. Что показывает сообщение об ошибке? Попробуйте запустить filemon на сетевой машине, почему вы обращаетесь к ней и видите результаты. –

+0

Я имел в виду «групповая политика, не позволяющая ...» –

ответ

15

Метод перевода объекта SecurityReference работает на нелокальных SID, но только для учетных записей домена. Для локальных учетных записей на другом компьютере или в настройке, отличной от домена, вам необходимо выполнить PInvoke функцию LookupAccountSid, определяющую конкретное имя машины, на котором должен выполняться поиск.

+2

Я только что начал писать код, чтобы сделать что-то подобное, и нашел, что это правильно. P/Invoking LookupAccountSid лучше, чем использование SecurityIdentifier.Translate(). Я работаю в среде с несколькими лесами/доменами с пользователями 60k +. –

0

Это один из них. Вы находитесь в среде Active Directory правильно? Просто проверяю :)

Во всяком случае, вместо того, чтобы связываться с sid.Value,

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

Я хотел бы попробовать преобразовать массив байтов в Сида к Octet String и связать с этим вместо этого.

Наслаждайтесь примером here на странице 78. Это поможет вам ближе. Честно говоря, я раньше не пытался связываться с SID. Но у меня была успешная привязка с GUID пользователя, хотя :)

Удачи и дайте мне знать, как это происходит.

1

Ой, возможно, что вызов LDAP не работает, потому что вы не можете находиться в среде Active Directory. Если это так, то каждая из ваших машин несет ответственность за свой собственный хранилище. И ваш первый пример кода не работает по сети, потому что машина, на которой вы выполняете свой код, не знает, как разрешить SID, который имеет смысл только на удаленной машине.

Вы действительно должны проверить, являются ли ваши машины частью Active Directory. Вы узнали бы это во время процесса входа в систему. Или вы можете проверить, щелкнув правой кнопкой мыши на «Мой компьютер», выберите «Свойства», вкладку «Имя компьютера», а затем посмотрите, является ли ваш компьютер частью домена.

-2

Я совершенно уверен, что вы будете иметь возможность использовать принятый ответ здесь: Determine the LocalSystem account name using C#

В принципе, вы можете перевести экземпляр класса SecurityIdentifier к типу NTAccount, из которого вы можете получить имя пользователя. В коде:

using System.Security.Principal; 

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

Хотя это неверно, он просто повторяет код, который уже указал указанный плакат, не работает в его ситуации. –

1

Отлично. Я списан код LookupAccountSid() отсюда:

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

И это сработало, хотя я должен был предоставить хозяин имя себя. В случае UNC-пути я могу просто взять первый его компонент. Когда это подключенный диск, я использую этот код, чтобы преобразовать путь к UNC один:

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

Это похоже на работу, так что, как я буду это делать, если кто-то приходит с ситуацией в который первым компонентом пути UNC не является именем хоста ...

Благодарим вас за помощь.

37

Смотрите здесь хороший ответ:

The best way to resolve display username by SID?

Суть его заключается в следующем бит:

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(); 

Этот подход работает для меня нелокального SID окончено активной директории.

+1

Этот подход работал для меня как есть. –

+1

Спасибо, это помогло мне получить имя пользователя пользователя из доверенного домена. –

0

Получить текущий домен:

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

Получить записи каталога из LDAP и имя домена:

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

Получить SID из ActiveDirectoryMembershipProvider ActiveDirectoryMembershipUser:

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

Получить имя пользователя из SecurityIdentifier:

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

поиск Получить каталог сделано на ActiveDirectory с записью каталога домена и имя пользователя:

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/>"; 
       } 
      } 
     } 

В зависимости от данных в вашем активном каталоге, вы получите разнообразный отклик на выходе.

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

5

System.DirectoryServices.AccountManagement.UserPrincipal класс (msdn link) имеет статическую функцию FindByIdentity для преобразования SID к объекту пользователя. Он должен работать как с локальной машиной, так и с сервером LDAP/Active Directory. Я использовал его только для активного каталога.

Вот пример, который я использовал в IIS:

// 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

Это правильный способ запроса иностранных доменов. P/Invoke не требуется. –

1

Вы также можете получить имя учетной записи специальных счетов типа «Все» с кодом, как это, который будет работать независимо от языковых настроек пользователя:

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

Вы только что спасли мне жизнь! – lukiller

1

в C#, получить пользователь SID и присвоить его переменной строкового через:

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

Вам понадобится использовать строку, потому что возможность разрешения имени пользователя поддерживает строку. Другими словами, использование var varUser приведет к ошибке пространства имен.

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