在 C#/.NET 中将用户名转换为 SID 字符串

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1040623/
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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-06 06:45:30  来源:igfitidea点击:

Convert a username to a SID string in C#/.NET

c#windowsidentitysid

提问by crb

There's a question about converting from a SID to an account name; there isn't one for the other way around.

有一个关于从 SID 转换为帐户名的问题;没有一个相反的。

How do you convert a username to a SID string, for example, to find out which HKEY_USERS subkey relates to a user of a given name?

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

采纳答案by crb

The podcast tells me I should ask, and answer, questions when they're not answered on SO already. Here goes.

播客告诉我,我应该在 SO 上尚未回答的问题上提出并回答问题。开始。

The easy way, with .NET 2.0 and up, is this:

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

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

The hard way, which works when that won't, and works on .NET 1.1 also:

困难的方法,当它不起作用时,也适用于 .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;
            }
        }
    }
}

回答by crb

The LookupAccountName()native method has the advantage of being able to be executed on a remote machine whereas the .NET methods can't be executed remotely.

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

Though the example doesn't show it LookupAccountName(null)<- this is the remote system to execute on.

尽管示例没有显示它LookupAccountName(null)<- 这是要在其上执行的远程系统。

回答by Danil

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);
        }
      }
    }
}