2015-11-25 4 views
1

Есть ли способ получить в C# список локальных групп и пользователей, когда Windows-машина не является членом AD и поиск LDAP не может быть использован?Как получить список локальных групп компьютеров/пользователей, когда машина не находится в активной директории?

ответ

1

Вы можете использовать P/Invoke для вызова native network management 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 strutures. Если вы запрашиваете дополнительную информацию, вам нужно будет сделать более сложный «синтаксический анализ».

Аналогично вы можете получить местные названия группы:

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

отлично работает, спасибо! – boboes

+0

Мартин, у вас есть также «NetLocalGroupGetMembers»? Попробуйте запустить пример в pinvoke, но не работает. Благодаря! – boboes

+0

@boboes: Это должно быть просто, за исключением случаев, когда я пытаюсь получить непредвиденную ошибку. Имя группы не может быть найдено_ (2220). Я не знаю, почему, и я хотел бы понять причину этой проблемы. Тем не менее, он должен будет дождаться позже. –