You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.NET Core 2.1中获取管理员组成员SID的兼容方案求助

在.NET Core 2.1中获取管理员组成员SID的解决方案

你遇到的这个问题确实挺头疼的——.NET Core 2.1里的DirectoryEntry.Invoke方法不支持IDispatch相关操作,所以调用WinNT组的Members方法会抛出System.PlatformNotSupportedException: IDispatch and IDispatchEx are not supported异常,而这个问题直到.NET Core 3.0才被官方修复。如果没办法升级框架版本,咱们可以用P/Invoke调用Windows原生API的方式来实现需求,这是最可靠的替代方案。

先看看你原来的实现代码:

private IList<byte[]> GetAdministratorsMembersSIDs() 
{ 
    IList<byte[]> adminMembers = new List<byte[]>(); 
    SecurityIdentifier id = new SecurityIdentifier(administratorsSid); 
    string name = id.Translate(typeof(NTAccount)).Value.Split('\\')[1]; 
    using (DirectoryEntry adminGroupEntry = new DirectoryEntry(string.Format("WinNT://./{0},group", name))) 
    { 
        foreach (object member in (IEnumerable)adminGroupEntry.Invoke("Members")) 
        { 
            using (DirectoryEntry memberEntry = new DirectoryEntry(member)) 
            { 
                adminMembers.Add((byte[])memberEntry.InvokeGet("objectSid")); 
            } 
        } 
    } 
    return adminMembers; 
}

替代方案:使用Windows原生API实现

我们可以调用Windows的NetLocalGroupGetMembersAPI来获取本地管理员组的成员SID,完全绕过.NET Core 2.1的DirectoryEntry限制,具体代码实现如下:

using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Security.Principal;

public class LocalGroupHelper
{
    // Windows API常量定义
    private const int MAX_PREFERRED_LENGTH = -1;
    private const int NERR_Success = 0;
    private const int LOCALGROUP_MEMBERS_INFO_3 = 3;

    // 存储成员SID信息的结构体
    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
    private struct LOCALGROUP_MEMBERS_INFO_3
    {
        public IntPtr lgrmi3_sid;
        public int lgrmi3_sidusage;
    }

    // P/Invoke声明:获取本地组成员
    [DllImport("netapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
    private static extern int NetLocalGroupGetMembers(
        string servername,
        string groupname,
        int level,
        out IntPtr bufptr,
        int prefmaxlen,
        out int entriesread,
        out int totalentries,
        IntPtr resumehandle);

    // P/Invoke声明:释放API分配的内存
    [DllImport("netapi32.dll", SetLastError = true)]
    private static extern int NetApiBufferFree(IntPtr buffer);

    public static IList<byte[]> GetAdministratorsMembersSIDs()
    {
        var adminSids = new List<byte[]>();
        // 管理员组默认名称,也可以保留你原来通过SID转换名称的逻辑
        string adminGroupName = "Administrators";

        IntPtr bufPtr = IntPtr.Zero;
        try
        {
            int entriesRead;
            int totalEntries;
            // 调用API获取管理员组成员
            int result = NetLocalGroupGetMembers(
                null, // 本地机器
                adminGroupName,
                LOCALGROUP_MEMBERS_INFO_3,
                out bufPtr,
                MAX_PREFERRED_LENGTH,
                out entriesRead,
                out totalEntries,
                IntPtr.Zero);

            if (result != NERR_Success)
            {
                throw new System.ComponentModel.Win32Exception(result);
            }

            // 遍历所有成员,提取SID并转换为字节数组
            int structSize = Marshal.SizeOf(typeof(LOCALGROUP_MEMBERS_INFO_3));
            IntPtr currentPtr = bufPtr;
            for (int i = 0; i < entriesRead; i++)
            {
                var memberInfo = (LOCALGROUP_MEMBERS_INFO_3)Marshal.PtrToStructure(currentPtr, typeof(LOCALGROUP_MEMBERS_INFO_3));
                var sid = new SecurityIdentifier(memberInfo.lgrmi3_sid);
                byte[] sidBytes = new byte[sid.BinaryLength];
                sid.GetBinaryForm(sidBytes, 0);
                
                adminSids.Add(sidBytes);
                currentPtr += structSize;
            }
        }
        finally
        {
            // 必须释放API分配的内存,避免泄漏
            if (bufPtr != IntPtr.Zero)
            {
                NetApiBufferFree(bufPtr);
            }
        }

        return adminSids;
    }
}

代码说明

  • 这个方案直接调用Windows原生API,完全避开了.NET Core 2.1中DirectoryEntry的平台支持限制;
  • 使用LOCALGROUP_MEMBERS_INFO_3级别获取成员的SID指针,再通过SecurityIdentifier类转换为字节数组,和你原来的返回格式完全一致;
  • 最后一定要调用NetApiBufferFree释放API分配的内存,避免内存泄漏。

另外,如果你的环境允许升级到.NET Core 3.0及以上版本,那直接使用你原来的代码就可以正常运行了,因为官方已经修复了这个平台支持问题。

内容的提问来源于stack exchange,提问作者Marco Ferrari

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 08:15:53