NetLocalGroupGetMembers
takes a server/machine name and group name, returning in bufptr all
members of the group. Valid data levels are:
-
LOCALGROUP_MEMBERS_INFO_0, which returns just the SID of the user,
-
LOCALGROUP_MEMBERS_INFO_1 which returns the SID, SID usage and user
name,
-
LOCALGROUP_MEMBERS_INFO_2 which returns the SID, SID usage and user
domain\name, or
-
LOCALGROUP_MEMBERS_INFO_3 which returns the user domain\name alone.
All four levels are defined in the code below, and following the demo any
of the three can be substituted for the LOCALGROUP_MEMBERS_INFO_2 used in
this demo.
On Windows NT+ no special group membership is required to successfully execute
the NetLocalGroupGetMembers function. On Windows 2000/XP, if you call this function on a Windows 2000/XP domain controller running Active
Directory, access is allowed or denied based on the access-control list (ACL) for the securable object. The default ACL permits all
authenticated users and members of the "Pre-Windows 2000 compatible access" group to view the information. By default, the
"Pre-Windows 2000 compatible access" group includes Everyone as a member. This enables anonymous access to the information if the
system allows anonymous access.
Called on
an XP domain controller running Active Directory, access is allowed or
denied based on the ACL for the securable object. Like Windows 2000, to
enable anonymous access, the user Anonymous must be a member of the
"Pre-Windows 2000 compatible access" group since anonymous tokens do
not include the Everyone group SID by default.
If you call this function on a Windows 2000/XP member server or workstation, all authenticated users can view the information. Anonymous access
is also permitted if the RestrictAnonymous policy setting allows anonymous access.
|
Option Explicit
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Copyright ©1996-2011 VBnet/Randy Birch, All Rights Reserved.
' Some pages may also contain other copyrights by the author.
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Distribution: You can freely use this code in your own
' applications, but you may not reproduce
' or publish this code on any web site,
' online service, or distribute as source
' on any media without express permission.
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'Windows type used to call the Net API
Private Const MAX_PREFERRED_LENGTH As Long = -1
Private Const NERR_SUCCESS As Long = 0&
Private Const ERROR_MORE_DATA As Long = 234&
Private Declare Sub CopyMemory Lib "kernel32" _
Alias "RtlMoveMemory" _
(Destination As Any, _
Source As Any, _
ByVal length As Long)
Private Declare Function NetApiBufferFree Lib "netapi32.dll" _
(ByVal lbufptrer As Long) As Long
Private Declare Function lstrlenW Lib "kernel32" _
(ByVal lpString As Long) As Long
Private Declare Function lstrcpynW Lib "kernel32" _
(ByVal lpString1 As Long, _
ByVal lpString2 As Long, _
ByVal iMaxLength As Long) As Long
Private Declare Function NetLocalGroupEnum Lib "netapi32" _
(servername As Byte, _
ByVal Level As Long, _
buff As Long, _
ByVal buffsize As Long, _
entriesread As Long, _
totalentries As Long, _
resumehandle As Long) As Long
Private Declare Function NetLocalGroupGetMembers Lib "netapi32.dll" _
(bServerName As Byte, _
szLocalGroupName As Byte, _
ByVal dwLevel As Long, _
lbufptr As Long, _
ByVal dwPrefLen As Long, _
dwEntriesRead As Long, _
dwTotalEntries As Long, _
dwResume As Long) As Long
Private Type LOCALGROUP_INFO_0
lgrpi1_name As Long
End Type
Private Type LOCALGROUP_MEMBERS_INFO_0
lgrmi0_sid As Long
End Type
Private Type LOCALGROUP_MEMBERS_INFO_1
lgrmi1_sid As Long
lgrmi1_sidusage As Long
lgrmi1_name As Long
End Type
Private Type LOCALGROUP_MEMBERS_INFO_2
lgrmi2_sid As Long
lgrmi2_sidusage As Long
lgrmi2_domainandname As Long
End Type
Private Type LOCALGROUP_MEMBERS_INFO_3
lgrmi3_domainandname As Long
End Type
Private Sub Form_Load()
Dim bServer() As Byte
'retrieves local groups. Pass a remote
'workstation or server name (format \\servername)
'to load groups from a specific server.
bServer = vbNullChar
Label1.Caption = GetLocalGroups(bServer, List1) & " local groups"
End Sub
Private Sub List1_Click()
Dim bServer() As Byte
Dim bGroup() As Byte
Dim cnt As Long
If List1.ListIndex > -1 Then
List2.Clear
bServer = "vbnetdev" & vbNullChar
bGroup = List1.List(List1.ListIndex) & vbNullChar
cnt = GetLocalGroupMembers(bServer, bGroup, List2)
Label2.Caption = CStr(cnt) & _
" members in " & _
List1.List(List1.ListIndex)
End If
End Sub
Private Function GetLocalGroupMembers(bServer() As Byte, _
bGroup() As Byte, _
lst As ListBox) As Long
Dim bufptr As Long
Dim entriesread As Long
Dim totalentries As Long
Dim success As Long
Dim resumehandle As Long
Dim nStructSize As Long
Dim cnt As Long
Dim lgmi2 As LOCALGROUP_MEMBERS_INFO_2
nStructSize = Len(lgmi2)
'if the type is changed above, be sure
'to change the third parameter in
'NetLocalGroupGetMembers to reflect
'the level requested.
success = NetLocalGroupGetMembers(bServer(0), _
bGroup(0), _
2, _
bufptr, _
MAX_PREFERRED_LENGTH, _
entriesread, _
totalentries, _
resumehandle)
If success = NERR_SUCCESS And _
success <> ERROR_MORE_DATA Then
For cnt = 0 To entriesread - 1
'get one chunk of data and cast
'into an LOCALGROUP_MEMBERS_INFO_2 type,
'and add the group member to a list
CopyMemory lgmi2, _
ByVal bufptr + (nStructSize * cnt), _
nStructSize
lst.AddItem GetPointerToByteStringW(lgmi2.lgrmi2_domainandname)
Next cnt
Else
MsgBox "Error calling NetLocalGroupGetMembers: " & success
End If
'NetApiBufferFree must be called regardless of
'the success of the NetLocalGroupGetMembers call
Call NetApiBufferFree(bufptr)
GetLocalGroupMembers = entriesread
End Function
Private Function GetLocalGroups(bServer() As Byte, _
lst As ListBox) As Long
Dim bufptr As Long
Dim entriesread As Long
Dim totalentries As Long
Dim success As Long
Dim resumehandle As Long
Dim nStructSize As Long
Dim cnt As Long
Dim lgis As LOCALGROUP_INFO_0
nStructSize = Len(lgis)
success = NetLocalGroupEnum(bServer(0), _
0, bufptr, _
MAX_PREFERRED_LENGTH, _
entriesread, _
totalentries, _
resumehandle)
If success = NERR_SUCCESS And _
success <> ERROR_MORE_DATA Then
For cnt = 0 To entriesread - 1
'get one chunk of data and cast
'into an LOCALGROUP_INFO_0 type, and
'add the group name to a list
CopyMemory lgis, ByVal bufptr + (nStructSize * cnt), nStructSize
lst.AddItem GetPointerToByteStringW(lgis.lgrpi1_name)
Next
End If
'NetApiBufferFree must be called regardless of
'the success of the NetLocalGroupEnum call
Call NetApiBufferFree(bufptr)
GetLocalGroups = entriesread
End Function
Public Function GetPointerToByteStringW(ByVal dwData As Long) As String
Dim tmp() As Byte
Dim tmplen As Long
If dwData <> 0 Then
tmplen = lstrlenW(dwData) * 2
If tmplen <> 0 Then
ReDim tmp(0 To (tmplen - 1)) As Byte
CopyMemory tmp(0), ByVal dwData, tmplen
GetPointerToByteStringW = tmp
End If
End If
End Function
|