Visual Basic Network Services
NetLocalGroupGetMembers: Enumerate Local Groups and Members
     
Posted:   Tuesday February 26, 2002
Updated:   Monday December 26, 2011
     
Applies to:   VB4-32, VB5, VB6
Developed with:   VB6, Windows XP
OS restrictions:   Windows NT4 / Windows 2000, Windows XP
Author:   VBnet - Randy Birch
     

Related:  

NetLocalGroupEnum: Enumerate Local Groups and Descriptions
     
 Prerequisites
Network connection to a domain controller, and/or one of the operating systems listed above.

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.

 BAS Module Code
None.

 Form Code
To a form, add two list boxes (List1 and List2) and two labels (Label1, Label2). Add the following code:

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
 Comments

 
 

PayPal Link
Make payments with PayPal - it's fast, free and secure!

 
 
 
 

Copyright 1996-2011 VBnet and Randy Birch. All Rights Reserved.
Terms of Use  |  Your Privacy

 

Hit Counter