如何在S#中将SID转换为帐户名称?

时间:2009-01-31 15:56:52

标签: c# sid

我有一个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 < / p>

有谁知道如何获取任意文件或SID的帐户名称?我对网络或LDAP或其他任何东西都不太了解。有一个名为DirectorySearcher的类,我可能会使用它,但它想要一个域名,我不知道如何得到它 - 我所拥有的只是我正在扫描的目录的路径。

提前致谢。

10 个答案:

答案 0 :(得分:38)

请看这里寻找一个好的答案:

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 :(得分:17)

SecurityReference对象的Translate方法适用于非本地SID,但仅适用于域帐户。对于其他计算机本地帐户或非域设置,您需要PInvoke函数LookupAccountSid,指定需要执行查找的特定计算机名称。

答案 2 :(得分:5)

System.DirectoryServices.AccountManagement.UserPrincipal class(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.

答案 3 :(得分:3)

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

<h1 class="test">Hi!</h1>

<script>
  x = document.getElementsByClassName('test')

  x[0].style.position = 'relative'; // Changed the position property to relative.
  x[0].style.top = '500px'; // Must be wrapped in quotes, and append the measurement unit in the value in this case the 'px'.

</script>

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

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

答案 4 :(得分:1)

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

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

答案 5 :(得分:1)

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

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

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

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

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

谢谢大家的帮助。

答案 6 :(得分:1)

您还可以使用此类代码获取特殊帐户的帐户名称,例如“Everyone”,无论用户的语言设置如何都可以使用

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

答案 7 :(得分:0)

这个是个傻瓜。您处于Active Directory环境中吗?只需检查:)

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

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

我会尝试将SID的字节数组转换为Octet String并与之绑定。

第78页有一个甜蜜的例子here。这会让你更接近。说实话,我之前没有尝试过绑定SID。但是我已经成功绑定了用户的GUID :)

祝你好运,让我知道它是怎么回事。

答案 8 :(得分: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));

使用域目录条目和用户名

在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:

答案 9 :(得分:-3)

我很确定您可以使用此处接受的答案: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);