Question

J'ai une application C # qui analyse un répertoire et rassemble des informations. Je voudrais afficher le nom du compte pour chaque fichier. Je peux le faire sur le système local en obtenant le SID de l’objet FileInfo, puis en faisant:

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

Toutefois, cela ne fonctionne pas pour les fichiers d'un réseau, probablement parce que la fonction Translate () ne fonctionne qu'avec les comptes d'utilisateurs locaux. Je pensais que je pourrais peut-être effectuer une recherche LDAP sur le SID. J'ai donc essayé ce qui suit:

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

Cela semble fonctionner, dans la mesure où l'accès à & "dirEntry.Name &"; se bloque pendant quelques secondes, comme s'il se déconnectait et interrogeait le réseau, mais il lançait alors une exception System.Runtime.InteropServices.COM

Est-ce que quelqu'un sait comment obtenir le nom de compte d'un fichier arbitraire ou d'un SID? Je ne connais pas grand chose au sujet des réseaux, de LDAP ou de quoi que ce soit. Peut-être que je suis supposé utiliser une classe appelée DirectorySearcher, mais elle veut un nom de domaine, et je ne sais pas comment l'obtenir non plus - tout ce que j'ai est le chemin du répertoire que je suis en train de scanner.

Merci d'avance.

Était-ce utile?

La solution

La méthode de conversion de l'objet SecurityReference fonctionne sur les SID non locaux mais uniquement pour les comptes de domaine. Pour les comptes locaux sur une autre machine ou dans une configuration ne faisant pas partie d'un domaine, vous devez invoquer la fonction LookupAccountSid en spécifiant le nom spécifique de la machine sur laquelle la recherche doit être effectuée.

Autres conseils

Voir ici pour une bonne réponse:

Le meilleur moyen de résoudre le nom d'utilisateur d'affichage par SID?

L’essentiel est le suivant:

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

Cette approche fonctionne pour moi pour les SID non locaux via Active Directory.

System.DirectoryServices.AccountManagement.UserPrincipal class (msdn link) has a static function FindByIdentity to convert an SID to a User object. It should be able to work both against the local machine or an LDAP/Active Directory server. I have only used it against active directory.

Here is an example that I have used in 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.

In C#, get the user SID and assign it to a string variable through:

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

You will need to use string because the ability to resolve to the UserName supports string. In other words, using var varUser will result in a namespace error.

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

Ooh, then it's possible that the LDAP call is not working because you might not be in an Active Directory environment. If this is the case, then each of your machines is responsible for its own identity store. And your first code sample is not working across the network because the machine on which you are executing your code does not know how to resolve the SID that only makes sense on the remote machine.

You really should check if your machines are a part of an Active Directory. You would know this during the logon process. Or you can check by right clicking on "My Computer", select "Properties", the "Computer Name" tab, then see if your computer is part of a domain.

Great. I cribbed some LookupAccountSid() code from here:

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

And that worked, though I had to provide the host name myself. In the case of a UNC path I can just take the first component of it. When it's a mapped drive, I use this code to convert the path to a UNC one:

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

It seems to work, so that's how I'll do it, unless someone comes up with a situation in which the first component of a UNC path isn't the host name...

Thank you all for your help.

You can also get account name of special accounts like "Everyone" with code like this that will work regardless of user's language settings:

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

This one is a stumper. You are in an Active Directory environment right? Just checking:)

Anyhow, instead of binding with sid.Value,

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

I would try converting the SID's byte array to an Octet String and bind with that instead.

There is a sweet example here on page 78. This will get you closer. To be honest, I've not tried binding with a SID before. But I've had success binding with a user's GUID though :)

Good luck and let me know how it goes.

Get the current domain:

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

Get a directory entry from ldap and the domain name:

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

Get the sid from an ActiveDirectoryMembershipProvider ActiveDirectoryMembershipUser:

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

Get the username from the SecurityIdentifier:

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

Get directory search done on an activedirectory with the domain directory entry and username:

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

Depending on the data in your active directory, you will get a varied response in the output.

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

I am quite sure you will be able to use the accepted answer from here: Determine the LocalSystem account name using C#

Basically, you can translate an instance of the SecurityIdentifier class to type NTAccount, from which you can get the user name. 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);
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top