[英]How can I convert from a SID to an account name in C#
我有一个扫描目录并收集一些信息的 C# 应用程序。 我想显示每个文件的帐户名称。 我可以通过获取 FileInfo object 的 SID 在本地系统上执行此操作,然后执行以下操作:
string GetNameFromSID( SecurityIdentifier sid )
{
NTAccount ntAccount = (NTAccount)sid.Translate( typeof( NTAccount ) );
return ntAccount.ToString();
}
但是,这不适用于 a.network 上的文件,大概是因为 Translate() function 仅适用于本地用户帐户。 我想也许我可以对 SID 进行 LDAP 查找,所以我尝试了以下操作:
string GetNameFromSID( SecurityIdentifier sid )
{
string str = "LDAP://<SID=" + sid.Value + ">";
DirectoryEntry dirEntry = new DirectoryEntry( str );
return dirEntry.Name;
}
这似乎会起作用,因为对“dirEntry.Name”的访问会挂起几秒钟,就好像它正在关闭并查询.network,但随后它会抛出 System.Runtime.InteropServices.COMException
有谁知道如何获取任意文件或 SID 的帐户名? 我不太了解.networking 或 LDAP 或任何东西。 有一个名为 DirectorySearcher 的 class,也许我应该使用它,但它需要一个域名,我也不知道如何获得它——我所拥有的只是我正在扫描的目录的路径。
在这里看到一个很好的答案:
它的要点是:
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。
SecurityReference 对象的 Translate 方法确实适用于非本地 SID,但仅适用于域帐户。 对于另一台机器的本地帐户或非域设置,您需要调用函数 LookupAccountSid 指定需要执行查找的特定机器名称。
System.DirectoryServices.AccountManagement.UserPrincipal
类( msdn 链接)有一个静态函数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.
在 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();
您还可以使用这样的代码获取特殊帐户的帐户名称,例如“Everyone”,无论用户的语言设置如何,都可以使用:
SecurityIdentifier everyoneSid = new SecurityIdentifier(WellKnownSidType.WorldSid, null);
string everyone = everyoneSid.Translate(typeof(System.Security.Principal.NTAccount)).ToString();
哦,那么 LDAP 调用可能不起作用,因为您可能不在 Active Directory 环境中。 如果是这种情况,那么您的每台机器都负责自己的身份存储。 并且您的第一个代码示例无法通过网络运行,因为您正在执行代码的机器不知道如何解析仅在远程机器上有意义的 SID。
您确实应该检查您的机器是否是 Active Directory 的一部分。 您会在登录过程中知道这一点。 或者您可以通过右键单击“我的电脑”,选择“属性”,“计算机名称”选项卡,然后查看您的计算机是否是域的一部分。
太好了。 我从这里抄录了一些 LookupAccountSid() 代码:
http://www.pinvoke.net/default.aspx/advapi32.LookupAccountSid
虽然我必须自己提供主机名,但这确实有效。 在 UNC 路径的情况下,我可以只使用它的第一个组件。 当它是映射驱动器时,我使用此代码将路径转换为 UNC 路径:
http://www.wiredprairie.us/blog/index.php/archives/22
它似乎有效,所以我就是这样做的,除非有人想出一种情况,即 UNC 路径的第一个组成部分不是主机名......
谢谢大家的帮助。
对于所有 Windows 开发人员,答案是LookupAccountSid
LookupAccountSid(null, Sid, username, userSize, domainName, domainSize, sidType);
获取当前域:
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/>";
}
}
}
根据活动目录中的数据,您将在输出中得到不同的响应。
我很确定您将能够使用这里接受的答案: 使用 C# 确定 LocalSystem 帐户名
基本上,您可以将 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);
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.