简体   繁体   中英

how to get domain user SID which is part of local system group

I have a machine within a domain (no work-group) and I have a local group Test Users and within this group I have added domain users.

domain\\Administrator

domain\\Install

在此处输入图片说明

Now I want to fetch all the users from the group along with their SID . With below code I am able to get all the user name within this group, but how to get SID ?

using (var groupEntry = new DirectoryEntry("WinNT://./Test Users,group"))
            {
                foreach (var member in (IEnumerable)groupEntry.Invoke("Members"))
                {
                    using (var memberEntry = new DirectoryEntry(member))
                    {
                        Console.WriteLine(memberEntry.Name);
                    }
                }
            }

Alternate Solution

You asked if there was another way, for that i am posting a different process for looking up SIDs of accounts. Use Package Manager to get the nuget package: System.DirectoryServices.AccountManagement .

Since MS came about with System.DirectoryServices.AccountManagement , I have coded almost all the AD work with that assembly. Following is the code i wrote up for a different way of looking up SIDs for all members of groups/accounts in local group of a system.

    // Recursively looks up all members and returns All the SIDs of all 'User' or 'local' accounts. 
    // ---> (NOT GROUPS but you can change that if you'd like.)
    private static List<string> GetSidsForAllAccounts(GroupPrincipal grp)
    {
        List<string> listOfSids = new List<string>();
        foreach (var member in grp.Members)
        {
            if (member.StructuralObjectClass != null && member.StructuralObjectClass.ToLower().Equals("group"))
                listOfSids.AddRange(GetSidsForAllAccounts((GroupPrincipal)member));
            else
                listOfSids.Add(member.Sid.ToString());
                // You could also use below to get Name and SID, PIPE delimited.
                // listOfSids.Add($"{member.Name}|{member.Sid.ToString()}");
                // You'll have to cast member to UserPrincipal if you are looking for properties specific to User Account.
        }
        return listOfSids;
    }

Use in main method : You would call the above the following way.

    // Look up the definition of PrincipalContext to use credentials.
    // e.g. new PrincipalContext(ContextType.Machine, "domainName", "user", "pass");
    PrincipalContext local = new PrincipalContext(ContextType.Machine);
    GroupPrincipal grp = GroupPrincipal.FindByIdentity(local, "Administrators");

    List<string> allSids = GetSidsForAllAccounts(grp);
    allSids.ForEach(x => Console.WriteLine(x));

How does this work

  1. PrincipalContext defines where to look up the first group, which in this case is "Local Machine".
  2. Looping through each group uses the PrincipalContext of the group itself when it looks up the details. If the group belongs to Domain, it will look up using the domain context automatically and local machine if its a local machine group.
  3. Recusively go through each group to look up its members until its all User accounts.

To get the SID of the DirectoryEntry, you have to get the extended properties of the user/group. You can get these properties by calling .Properties on the DirectoryEntry. You can access each of the properties by using ["propertyName"].Value but for SID, you have to convert the SID's byte array to string. Below is the convert method from codeproject site and how to use this.

Method to convert Byte to String is taken from here

    private static string ConvertByteToStringSid(Byte[] sidBytes)
        {
            StringBuilder strSid = new StringBuilder();
            strSid.Append("S-");
            try
            {
                // Add SID revision.
                strSid.Append(sidBytes[0].ToString());
                // Next six bytes are SID authority value.
                if (sidBytes[6] != 0 || sidBytes[5] != 0)
                {
                    string strAuth = String.Format
                        ("0x{0:2x}{1:2x}{2:2x}{3:2x}{4:2x}{5:2x}",
                        (Int16)sidBytes[1],
                        (Int16)sidBytes[2],
                        (Int16)sidBytes[3],
                        (Int16)sidBytes[4],
                        (Int16)sidBytes[5],
                        (Int16)sidBytes[6]);
                    strSid.Append("-");
                    strSid.Append(strAuth);
                }
                else
                {
                    Int64 iVal = (Int32)(sidBytes[1]) +
                        (Int32)(sidBytes[2] << 8) +
                        (Int32)(sidBytes[3] << 16) +
                        (Int32)(sidBytes[4] << 24);
                    strSid.Append("-");
                    strSid.Append(iVal.ToString());
                }

                // Get sub authority count...
                int iSubCount = Convert.ToInt32(sidBytes[7]);
                int idxAuth = 0;
                for (int i = 0; i < iSubCount; i++)
                {
                    idxAuth = 8 + i * 4;
                    UInt32 iSubAuth = BitConverter.ToUInt32(sidBytes, idxAuth);
                    strSid.Append("-");
                    strSid.Append(iSubAuth.ToString());
                }
            }
            catch (Exception ex)
            {

                return "";
            }
            return strSid.ToString();
        }

This is how you use that method and get the SID of the DirectoryEntry entity.

    var coll = memberEntry.Properties;
    object obVal = coll["objectSid"].Value;
    object userSID;
    if (null != obVal)
    {
        userSID = ConvertByteToStringSid((Byte[])obVal);
    }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM