当机器不在active directory中时,如何获取本地机器组/用户的列表

本文关键字:机器 获取 列表 用户 active directory 中时 何获取 | 更新日期: 2023-09-27 18:24:17

当windows机器不是AD成员并且无法使用LDAP搜索时,有没有办法在C#中获取本地组和用户的列表?

当机器不在active directory中时,如何获取本地机器组/用户的列表

您可以使用p/Invoke调用本地网络管理API来获取本地用户和组名:

static class NativeMethods {
  [DllImport("netapi32.dll")]
  public static extern void NetApiBufferFree(IntPtr bufptr);
  [DllImport("netapi32.dll")]
  public static extern UInt32 NetUserEnum([MarshalAs(UnmanagedType.LPWStr)] String servername, UInt32 level, UInt32 filter, ref IntPtr bufptr, UInt32 prefmaxlen, ref UInt32 entriesread, ref UInt32 totalentries, IntPtr resumehandle);
  [DllImport("netapi32.dll")]
  public static extern UInt32 NetLocalGroupEnum([MarshalAs(UnmanagedType.LPWStr)] String servername, UInt32 level, ref IntPtr bufptr, UInt32 prefmaxlen, ref UInt32 entriesread, ref UInt32 totalentries, IntPtr resumehandle);
  [DllImport("Netapi32.dll")]
  public extern static UInt32 NetLocalGroupGetMembers([MarshalAs(UnmanagedType.LPWStr)] String servername, [MarshalAs(UnmanagedType.LPWStr)] String localgroupname, UInt32 level, ref IntPtr bufptr, UInt32 prefmaxlen, ref UInt32 entriesread, ref UInt32 totalentries, IntPtr resumehandle);
}

API允许您获取有关用户的各种信息。如果你只想要名字,你可以使用这个功能:

IEnumerable<String> GetUserNames() {
  var buffer = IntPtr.Zero;
  try {
    UInt32 entriesRead = 0;
    UInt32 totalEntries = 0;
    var result = NativeMethods.NetUserEnum(null, 0, 0, ref buffer, UInt32.MaxValue, ref entriesRead, ref totalEntries, IntPtr.Zero);
    if (result != 0)
      throw new Win32Exception((Int32) result);
    var userNames = Enumerable
      .Range(0, (Int32) entriesRead)
      .Select(
        i => {
          var userInfo = Marshal.ReadIntPtr(buffer, i*IntPtr.Size);
          var userName = Marshal.PtrToStringAuto(userInfo);
          return userName;
        }
      )
      .ToList();
    return userNames;
  }
  finally {
    NativeMethods.NetApiBufferFree(buffer);
  }
}

LINQ语句用于"解析"包含USER_INFO_0结构的缓冲区。如果您正在查询其他信息,则必须进行更详细的"解析"。

同样,您可以获得本地组名:

IEnumerable<String> GetLocalGroupNames() {
  var buffer = IntPtr.Zero;
  try {
    UInt32 entriesRead = 0;
    UInt32 totalEntries = 0;
    var result = NativeMethods.NetLocalGroupEnum(null, 0, ref buffer, UInt32.MaxValue, ref entriesRead, ref totalEntries, IntPtr.Zero);
    if (result != 0)
      throw new Win32Exception((Int32) result);
    var localGroupNames = Enumerable
      .Range(0, (Int32) entriesRead)
      .Select(
        i => {
          var localGroupInfo = Marshal.ReadIntPtr(buffer, i*IntPtr.Size);
          var groupName = Marshal.PtrToStringAuto(localGroupInfo);
          return groupName;
        }
      )
      .ToList();
    return localGroupNames;
  }
  finally {
    NativeMethods.NetApiBufferFree(buffer);
  }
}

缓冲区中的结构是LOCALGROUP_INFO_0,布局与USER_INFO_0结构相同,因此"解析"代码是相同的。

最后,以下是如何使用LOCALGROUP_MEMBERS_INFO_3结构获得组成员身份:

IEnumerable<String> GetLocalGroupUsers(String localGroupName) {
  var buffer = IntPtr.Zero;
  try {
    UInt32 entriesRead = 0;
    UInt32 totalEntries = 0;
    var result = NativeMethods.NetLocalGroupGetMembers(null, localGroupName, 3, ref buffer, UInt32.MaxValue, ref entriesRead, ref totalEntries, IntPtr.Zero);
    if (result != 0)
      throw new Win32Exception((Int32) result);
    var userNames = Enumerable
      .Range(0, (Int32) entriesRead)
      .Select(
        i => {
          var membersInfo = Marshal.ReadIntPtr(buffer, i*IntPtr.Size);
          var userName = Marshal.PtrToStringAuto(membersInfo );
          return userName;
        }
      )
      .ToList();
    return userNames;
  }
  finally {
    NativeMethods.NetApiBufferFree(buffer);
  }
}