如何在 C# 中从 SID 转换为帐户名
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/499053/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How can I convert from a SID to an account name in C#
提问by
I have a C# application that scans a directory and gathers some information. I would like to display the account name for each file. I can do this on the local system by getting the SID for the FileInfo object, and then doing:
我有一个 C# 应用程序,它扫描目录并收集一些信息。我想显示每个文件的帐户名。我可以通过获取 FileInfo 对象的 SID 在本地系统上执行此操作,然后执行以下操作:
string GetNameFromSID( SecurityIdentifier sid )
{
NTAccount ntAccount = (NTAccount)sid.Translate( typeof( NTAccount ) );
return ntAccount.ToString();
}
However, this does not work for files on a network, presumably because the Translate() function only works with local user accounts. I thought maybe I could do an LDAP lookup on the SID, so I tried the following:
但是,这不适用于网络上的文件,大概是因为 Translate() 函数仅适用于本地用户帐户。我想也许我可以对 SID 进行 LDAP 查找,所以我尝试了以下操作:
string GetNameFromSID( SecurityIdentifier sid )
{
string str = "LDAP://<SID=" + sid.Value + ">";
DirectoryEntry dirEntry = new DirectoryEntry( str );
return dirEntry.Name;
}
This seems like it will work, in that the access to "dirEntry.Name" hangs for a few seconds, as if it is going off and querying the network, but then it throws a System.Runtime.InteropServices.COMException
这似乎会起作用,因为对“dirEntry.Name”的访问会挂起几秒钟,就好像它正在关闭并查询网络一样,但随后它会抛出 System.Runtime.InteropServices.COMException
Does anyone know how I can get the account name of an arbitrary file or SID? I don't know much about networking or LDAP or anything. There's a class called DirectorySearcher that maybe I'm supposed to use, but it wants a domain name, and I don't know how to get that either - all I have is the path to the directory I'm scanning.
有谁知道如何获取任意文件或 SID 的帐户名?我不太了解网络或 LDAP 或任何东西。有一个名为 DirectorySearcher 的类,也许我应该使用它,但它需要一个域名,但我也不知道如何获取它 - 我所拥有的只是我正在扫描的目录的路径。
Thanks in advance.
提前致谢。
采纳答案by Stephen Martin
The SecurityReference object's Translate method does work on non-local SIDs but only for domain accounts. For accounts local to another machine or in a non-domain setup you would need to PInvoke the function LookupAccountSid specifying the specific machine name on which the look up needs to be performed.
SecurityReference 对象的 Translate 方法确实适用于非本地 SID,但仅适用于域帐户。对于另一台机器的本地帐户或非域设置,您需要调用函数 LookupAccountSid 指定需要执行查找的特定机器名称。
回答by barneytron
This one is a stumper. You are in an Active Directory environment right? Just checking:)
这是一个树桩。您在 Active Directory 环境中,对吗?只是检查:)
Anyhow, instead of binding with sid.Value,
无论如何,而不是与 sid.Value 绑定,
string str = "LDAP://<SID=" + sid.Value + ">";
I would try converting the SID's byte array to an Octet Stringand bind with that instead.
我会尝试将 SID 的字节数组转换为八位字节字符串并与之绑定。
There is a sweet example hereon 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 :)
有一个甜蜜的例子在这里78页这将让你更接近。老实说,我之前没有尝试过使用 SID 进行绑定。但是我已经成功绑定了用户的 GUID :)
Good luck and let me know how it goes.
祝你好运,让我知道进展如何。
回答by barneytron
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.
哦,那么 LDAP 调用可能不起作用,因为您可能不在 Active Directory 环境中。如果是这种情况,那么您的每台机器都负责自己的身份存储。并且您的第一个代码示例无法通过网络运行,因为您正在执行代码的机器不知道如何解析仅在远程机器上有意义的 SID。
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.
您确实应该检查您的机器是否是 Active Directory 的一部分。您会在登录过程中知道这一点。或者您可以通过右键单击“我的电脑”,选择“属性”,“计算机名称”选项卡,然后查看您的计算机是否是域的一部分。
回答by driis
I am quite sure you will be able to use the accepted answer from here: Determine the LocalSystem account name using C#
我很确定您将能够使用这里接受的答案:使用 C# 确定 LocalSystem 帐户名
Basically, you can translate an instance of the SecurityIdentifier class to type NTAccount, from which you can get the user name. In code:
基本上,您可以将 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);
回答by Stephen Martin
Great. I cribbed some LookupAccountSid() code from here:
伟大的。我从这里抄录了一些 LookupAccountSid() 代码:
http://www.pinvoke.net/default.aspx/advapi32.LookupAccountSid
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:
虽然我必须自己提供主机名,但这确实有效。在 UNC 路径的情况下,我可以只使用它的第一个组件。当它是映射驱动器时,我使用此代码将路径转换为 UNC 路径:
http://www.wiredprairie.us/blog/index.php/archives/22
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...
它似乎有效,所以我就是这样做的,除非有人想出一种情况,即 UNC 路径的第一个组成部分不是主机名......
Thank you all for your help.
谢谢大家的帮助。
回答by Chris
See here for a good answer:
在这里看到一个很好的答案:
The best way to resolve display username by SID?
The gist of it is this 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();
This approach works for me for non-local SID's over the active directory.
这种方法适用于活动目录上的非本地 SID。
回答by Chris
Get the current domain:
获取当前域:
System.DirectoryServices.ActiveDirectory.Domain.GetCurrentDomain();
Get a directory entry from ldap and the domain name:
从 ldap 和域名获取目录条目:
DirectoryEntry de = new DirectoryEntry(string.Format("LDAP://{0}", domain));
Get the sid from an ActiveDirectoryMembershipProvider ActiveDirectoryMembershipUser:
从 ActiveDirectoryMembershipProvider ActiveDirectoryMembershipUser 获取 sid:
ActiveDirectoryMembershipUser user = (ActiveDirectoryMembershipUser)Membership.GetUser();
var sid = (SecurityIdentifier)user.ProviderUserKey;
Get the username from the SecurityIdentifier:
从 SecurityIdentifier 中获取用户名:
(NTAccount)sid.Translate(typeof(NTAccount));
Get directory search done on an activedirectory with the domain directory entry and username:
使用域目录条目和用户名在 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/>";
}
}
}
Depending on the data in your active directory, you will get a varied response in the output.
根据活动目录中的数据,您将在输出中得到不同的响应。
回答by Bakanekobrain
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.
System.DirectoryServices.AccountManagement.UserPrincipal
类 ( msdn 链接) 具有FindByIdentity
将 SID 转换为用户对象的静态函数。它应该能够在本地计算机或 LDAP/Active Directory 服务器上工作。我只对活动目录使用过它。
Here is an example that I have used in IIS:
这是我在 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.
回答by jm.
You can also get account name of special accounts like "Everyone" with code like this that will work regardless of user's language settings:
您还可以使用这样的代码获取特殊帐户的帐户名称,例如“Everyone”,无论用户的语言设置如何,都可以使用:
SecurityIdentifier everyoneSid = new SecurityIdentifier(WellKnownSidType.WorldSid, null);
string everyone = everyoneSid.Translate(typeof(System.Security.Principal.NTAccount)).ToString();
回答by J Weezy
In C#, get the user SID and assign it to a string variable through:
在 C# 中,通过以下方式获取用户 SID 并将其分配给字符串变量:
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.
您将需要使用字符串,因为解析用户名的能力支持字符串。换句话说,使用 var varUser 将导致命名空间错误。
string strUserName = new System.Security.Principal.SecurityIdentifier(strUser).Translate(typeof(System.Security.Principal.NTAccount)).ToString();