【问题标题】:Convert a username to a SID string in C#/.NET在 C#/.NET 中将用户名转换为 SID 字符串
【发布时间】:2009-06-24 19:58:10
【问题描述】:

有一个关于converting from a SID to an account name的问题;没有相反的方法。

如何将用户名转换为 SID 字符串,例如,找出哪个 HKEY_USERS 子项与给定名称的用户相关?

【问题讨论】:

    标签: c# windows identity sid


    【解决方案1】:

    播客告诉我,当这些问题尚未在 SO 上得到回答时,我应该提出并回答。来了。

    .NET 2.0 及更高版本的简单方法是:

    NTAccount f = new NTAccount("username");
    SecurityIdentifier s = (SecurityIdentifier) f.Translate(typeof(SecurityIdentifier));
    String sidString = s.ToString();
    

    困难的方法,当它不起作用时,也适用于 .NET 1.1:

    [DllImport("advapi32.dll", CharSet=CharSet.Auto, SetLastError=true)]
    public static extern bool LookupAccountName([In,MarshalAs(UnmanagedType.LPTStr)] string systemName, [In,MarshalAs(UnmanagedType.LPTStr)] string accountName, IntPtr sid, ref int cbSid, StringBuilder referencedDomainName, ref int cbReferencedDomainName, out int use);
    
    [DllImport("advapi32.dll", CharSet=CharSet.Auto, SetLastError=true)]
    internal static extern bool ConvertSidToStringSid(IntPtr sid, [In,Out,MarshalAs(UnmanagedType.LPTStr)] ref string pStringSid);
    
    
    /// <summary>The method converts object name (user, group) into SID string.</summary>
    /// <param name="name">Object name in form domain\object_name.</param>
    /// <returns>SID string.</returns>
    public static string GetSid(string name) {
        IntPtr _sid = IntPtr.Zero; //pointer to binary form of SID string.
        int _sidLength = 0;   //size of SID buffer.
        int _domainLength = 0;  //size of domain name buffer.
        int _use;     //type of object.
        StringBuilder _domain = new StringBuilder(); //stringBuilder for domain name.
        int _error = 0;
        string _sidString = "";
    
        //first call of the function only returns the sizes of buffers (SDI, domain name)
        LookupAccountName(null, name, _sid, ref _sidLength, _domain, ref _domainLength, out _use);
        _error = Marshal.GetLastWin32Error();
    
        if (_error != 122) //error 122 (The data area passed to a system call is too small) - normal behaviour.
        {
            throw (new Exception(new Win32Exception(_error).Message));
        } else {
            _domain = new StringBuilder(_domainLength); //allocates memory for domain name
            _sid = Marshal.AllocHGlobal(_sidLength); //allocates memory for SID
            bool _rc = LookupAccountName(null, name, _sid, ref _sidLength, _domain, ref _domainLength, out _use);
    
            if (_rc == false) {
                _error = Marshal.GetLastWin32Error();
                Marshal.FreeHGlobal(_sid);
                throw (new Exception(new Win32Exception(_error).Message));
            } else {
                // converts binary SID into string
                _rc = ConvertSidToStringSid(_sid, ref _sidString);
    
                if (_rc == false) {
                    _error = Marshal.GetLastWin32Error();
                    Marshal.FreeHGlobal(_sid);
                    throw (new Exception(new Win32Exception(_error).Message));
                } else {
                    Marshal.FreeHGlobal(_sid);
                    return _sidString;
                }
            }
        }
    }
    

    【讨论】:

    • 我很好奇为什么我选择 'f' 作为 NTAccount 的变量!
    • "which works when that won't" ...任何指向何时简单方法不起作用的指针,假设我有.NET 2.0?
    • 不是我记得很抱歉。我的意思可能只是 2.0 之前的版本;我希望它归结为相同的 Win32 API 调用。
    • 我的一个客户报告异常:“无法翻译部分或全部身份参考”当我使用第一种方法时,我没有尝试过第二种方法,但我只是在这里留下我的评论任何人都知道。
    • 我收到了System.Security.Principal.IdentityNotMappedException
    【解决方案2】:

    LookupAccountName() 本机方法的优点是可以在远程机器上执行,而 .NET 方法不能远程执行。

    虽然示例没有显示它LookupAccountName(null)

    【讨论】:

      【解决方案3】:
      using System.Security.Principal;
      
      var curUser = WindowsIdentity.GetCurrent().User.Value;
      var otherUser = new WindowsIdentity("kul@mycompany.com").User.Value;
      

      【讨论】:

      • 虽然您的代码可以不言自明,但仅提供代码转储仍然是个坏主意。没有任何解释和代码,只有答案被标记为低质量,可能会被删除。
      • @NawedNabiZada 这是程序员向程序员提出的问题。我们不是作家?。我自己正在寻找这个问题的答案并找到它并决定分享它。在我的示例中,变量名和函数名说明了它们自身的一切!
      • 信不信由你,我评论只是为了让你了解SO的规则。
      【解决方案4】:
      using System;
      using System.Management;
      using System.Windows.Forms;
      
      namespace WMISample
      {
      public class MyWMIQuery
      {
          public static void Main()
          {
              try
              {
                  ManagementObjectSearcher searcher = 
                      new ManagementObjectSearcher("root\\CIMV2", 
                      "SELECT * FROM Win32_UserAccount where name='Galia'"); 
      
                  foreach (ManagementObject queryObj in searcher.Get())
                  {
                      Console.WriteLine("-----------------------------------");
                      Console.WriteLine("Win32_UserAccount instance");
                      Console.WriteLine("-----------------------------------");
                      Console.WriteLine("Name: {0}", queryObj["Name"]);
                      Console.WriteLine("SID: {0}", queryObj["SID"]);
                  }
              }
              catch (ManagementException e)
              {
                  MessageBox.Show("An error occurred while querying for WMI 
                  data: " + e.Message);
              }
            }
          }
      }
      

      /////////远程:

                  ConnectionOptions connection = new ConnectionOptions();
                  connection.Username = userNameBox.Text;
                  connection.Password = passwordBox.Text;
                  connection.Authority = "ntlmdomain:WORKGROUP";
      
                  ManagementScope scope = new ManagementScope(
                      "\\\\ASUS\\root\\CIMV2", connection);
                  scope.Connect();
      
                  ObjectQuery query= new ObjectQuery(
                      "SELECT * FROM Win32_UserAccount"); 
      
                  ManagementObjectSearcher searcher = 
                      new ManagementObjectSearcher(scope, query);
      
                  foreach (ManagementObject queryObj in searcher.Get())
                  {
                      Console.WriteLine("-----------------------------------");
                      Console.WriteLine("Win32_UserAccount instance");
                      Console.WriteLine("-----------------------------------");
                  }
      

      【讨论】:

      • 大概这仅适用于本地用户帐户?
      • 远程电脑几乎一样
      • 嗯,我不知道 WMI 可以用于域的东西,谢谢!
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2010-11-22
      • 2010-12-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-12-22
      • 1970-01-01
      相关资源
      最近更新 更多