59

我有一个扫描目录并收集一些信息的 C# 应用程序。我想显示每个文件的帐户名称。我可以通过获取 FileInfo 对象的 SID 在本地系统上执行此操作,然后执行以下操作:

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

但是,这不适用于网络上的文件,大概是因为 Translate() 函数仅适用于本地用户帐户。我想也许我可以对 SID 进行 LDAP 查找,所以我尝试了以下方法:

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 的类,也许我应该使用它,但它需要一个域名,我也不知道如何获得它——我所拥有的只是我正在扫描的目录的路径。

提前致谢。

4

10 回答 10

50

看到这里有一个很好的答案:

通过 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。

于 2009-03-11T23:36:59.803 回答
19

SecurityReference 对象的 Translate 方法确实适用于非本地 SID,但仅适用于域帐户。对于另一台机器本地或非域设置中的帐户,您需要 PInvoke 函数 LookupAccountSid 指定需要执行查找的特定机器名称。

于 2009-02-01T23:24:28.967 回答
7

System.DirectoryServices.AccountManagement.UserPrincipal类 ( msdn link ) 具有FindByIdentity将 SID 转换为 User 对象的静态函数。它应该能够在本地机器或 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.
于 2012-07-19T23:42:11.490 回答
3

在 C# 中,通过以下方式获取用户 SID 并将其分配给字符串变量:

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

您将需要使用字符串,因为解析为 UserName 的能力支持字符串。换句话说,使用var varUser将导致命名空间错误。

string strUserName = new System.Security.Principal.SecurityIdentifier(strUser).Translate(typeof(System.Security.Principal.NTAccount)).ToString();
于 2017-02-19T07:33:49.967 回答
2

您还可以使用这样的代码获取特殊帐户的帐户名称,例如“每个人”,无论用户的语言设置如何,该代码都可以使用:

   SecurityIdentifier everyoneSid = new SecurityIdentifier(WellKnownSidType.WorldSid, null);
   string everyone = everyoneSid.Translate(typeof(System.Security.Principal.NTAccount)).ToString();
于 2015-12-01T05:34:57.333 回答
1

哦,那么 LDAP 调用可能不起作用,因为您可能不在 Active Directory 环境中。如果是这种情况,那么您的每台机器都负责自己的身份存储。而且您的第一个代码示例无法通过网络运行,因为您正在执行代码的机器不知道如何解析仅在远程机器上才有意义的 SID。

你真的应该检查你的机器是否是 Active Directory 的一部分。您会在登录过程中知道这一点。或者您可以通过右键单击“我的电脑”来检查,选择“属性”,“计算机名称”选项卡,然后查看您的计算机是否是域的一部分。

于 2009-02-01T05:50:43.850 回答
1

伟大的。我从这里抄写了一些 LookupAccountSid() 代码:

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

虽然我必须自己提供主机名,但这很有效。在 UNC 路径的情况下,我可以只取它的第一个组件。当它是映射驱动器时,我使用此代码将路径转换为 ​​UNC 路径:

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

它似乎有效,所以我就是这样做的,除非有人想出 UNC 路径的第一个组件不是主机名的情况......

感谢大家的帮助。

于 2009-02-02T02:15:09.730 回答
0

这是一个笨蛋。您在 Active Directory 环境中,对吗?只是检查:)

无论如何,而不是与 sid.Value 绑定,

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

我会尝试将 SID 的字节数组转换为八位字节字符串并与之绑定。

第 78 页有一个很好的例子。会让你更接近。老实说,我以前没有尝试过与 SID 绑定。但是我已经成功绑定了用户的 GUID :)

祝你好运,让我知道情况如何。

于 2009-01-31T19:08:38.267 回答
0

获取当前域:

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

从 ldap 和域名获取目录条目:

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

从 ActiveDirectoryMembershipProvider ActiveDirectoryMembershipUser 获取 sid:

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

从 SecurityIdentifier 获取用户名:

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

使用域目录条目和用户名在活动目录上完成目录搜索:

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

根据活动目录中的数据,您将在输出中得到不同的响应。

这是一个包含我需要的所有用户属性的站点:

于 2009-05-17T22:27:25.073 回答
-4

我很确定您将能够使用此处接受的答案: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);
于 2009-02-01T10:02:31.333 回答