devxlogo

NT Server Local Groups

NT Server Local Groups

Question:
I would like to be able to gain access to NT server local groups for enum, member enum, add member, delete member.

We have a lot of servers as well as NT and OS/2 domains. Because of this, there is a need to synchronize users and group memberships across multiple servers.

I have not found anything that will allow me to access a local group on a server from a VB program running on a client. Can you point me in the right direction?

Answer:
None of the NT Unicode network functions are particularly easy to use. In fact, they are a real pain. However, the following code will do what you want:

' ************************************************' In a form' ************************************************Option ExplicitPrivate Sub Command1_Click()On Error Resume Next   Dim p_vntRtn   As Variant   Dim p_lngNum   As Long   Dim p_lngLoop  As Long   Dim p_strGroup As String      p_strGroup = Trim$(Me.List1.List(Me.List1.ListIndex))   If Len(p_strGroup) <= 0 Then      MsgBox "You must select a group first!"      Exit Sub   End If      Me.List2.Clear   p_vntRtn = GetLocalGroupMembers("", p_strGroup)      p_lngNum = UBound(p_vntRtn)   If p_lngNum > 0 Then      For p_lngLoop = 1 To p_lngNum         Me.List2.AddItem p_vntRtn(p_lngLoop)      Next p_lngLoop   End If   End SubPrivate Sub Command2_Click()On Error Resume Next   Dim p_vntRtn   As Variant   Dim p_lngNum   As Long   Dim p_lngLoop  As Long      Me.List1.Clear   p_vntRtn = GetLocalGroups("")      p_lngNum = UBound(p_vntRtn)   If p_lngNum > 0 Then      For p_lngLoop = 1 To p_lngNum         Me.List1.AddItem p_vntRtn(p_lngLoop)      Next p_lngLoop   End If   End SubPrivate Sub Command3_Click()   Dim p_blnRtn   As Boolean   Dim p_strGroup As String   Dim p_strUser  As String      p_strGroup = Trim$(Me.List1.List(Me.List1.ListIndex))   If Len(p_strGroup) <= 0 Then      MsgBox "You must select a group first!"      Exit Sub   End If     p_strUser = Trim$(Me.Text1.Text)   If Len(p_strUser) <= 0 Then      MsgBox "You must add a user name first!"      Exit Sub   End If      p_blnRtn = AddDelUserToLocal(p_strGroup, _                             p_strUser, _                             "", True)End SubPrivate Sub Command4_Click()   Dim p_blnRtn   As Boolean   Dim p_strGroup As String   Dim p_strUser  As String      p_strGroup = Trim$(Me.List1.List(Me.List1.ListIndex))   If Len(p_strGroup) <= 0 Then      MsgBox "You must select a group first!"      Exit Sub   End If     p_strUser = Trim$(Me.Text2.Text)   If Len(p_strUser) <= 0 Then      MsgBox "You must add a user name first!"      Exit Sub   End If      p_blnRtn = AddDelUserToLocal(p_strGroup, _                             p_strUser, _                             "", False)End Sub' ************************************************' In a BAS file' ************************************************Option ExplicitPrivate Const NERR_Success             As Long = 0&Private Const LocalGroupInfo0          As Long = 0&Private Const LocalGroupInfo1          As Long = 1&Private Const LocalGroupMembersInfo0   As Long = 0&Private Const LocalGroupMembersInfo1   As Long = 1&Private Const LocalGroupMembersInfo2   As Long = 2&Private Const LocalGroupMembersInfo3   As Long = 3&Private Const SidTypeUser              As Long = 1&Private Const SidTypeGroup             As Long = 2&Private Const SidTypeDomain            As Long = 3&Private Const SidTypeAlias             As Long = 4&Private Const SidTypeWellKnownGroup    As Long = 5&Private Const SidTypeDeletedAccount    As Long = 6&Private Const SidTypeInvalid           As Long = 7&Private Const SidTypeUnknown           As Long = 8&    Public Declare Sub CopyMem _   Lib "kernel32" Alias "RtlMoveMemory" _   (pTo As Any, _    pFrom As Any, _    ByVal lCount As Long)Private Declare Function lstrlenW _   Lib "kernel32" _   (ByVal psString As Long) As LongPrivate Declare Function NetApiBufferFree _   Lib "netapi32.dll" _   (ByVal p_lngPtrBuffer As Long) As LongPrivate Type LOCALGROUP_INFO_0   PtrGroupName                        As LongEnd TypePrivate Type LOCALGROUP_MEMBERS_INFO_0   PtrSidID                            As LongEnd TypePrivate Type LOCALGROUP_MEMBERS_INFO_1   PtrSidID                            As Long   SidUsage                            As Long   PtrName                             As LongEnd TypePrivate Type LOCALGROUP_MEMBERS_INFO_3   DomainAndName                       As LongEnd TypePrivate Declare Function NetLocalGroupEnum _   Lib "netapi32" _   (ByVal psServer As Long, _    ByVal level As Long, _    pPtrBuffer As Long, _    ByVal prefmaxlen As Long, _    EntriesRead As Long, _    TotalEntries As Long, _    ResumeHandle As Long) As Long Private Declare Function NetLocalGroupGetMembers _   Lib "netapi32" _   (ByVal psServer As Long, _    ByVal psLocalGroupName As Long, _    ByVal level As Long, _    pPtrBuffer As Long, _    ByVal prefmaxlen As Long, _    EntriesRead As Long, _    TotalEntries As Long, _    ResumeHandle As Long) As Long Private Declare Function NetLocalGroupAddMembers _   Lib "netapi32" _   (ByVal psServer As Long, _    ByVal psLocalGroupName As Long, _    ByVal level As Long, _    pPtrBuffer As Long, _    ByVal membercount As Long) As Long    Private Declare Function NetLocalGroupDelMembers _   Lib "netapi32" _   (ByVal psServer As Long, _    ByVal psLocalGroupName As Long, _    ByVal level As Long, _    pPtrBuffer As Long, _    ByVal membercount As Long) As Long    ' ================================================' Get all the memebers of a selected local group' ================================================Public Function GetLocalGroupMembers(ByVal xi_strServerName As String, _                                     ByVal xi_strLocalGroupName As String) As Variant   Dim p_lngRtn                     As Long   Dim p_lngPtrBuffer               As Long   Dim p_lngPtrServerName           As Long   Dim p_lngPtrLocalGroupName       As Long   Dim p_lngPreferredMaxLen         As Long   Dim p_lngEntriesRead             As Long   Dim p_lngTotalEntries            As Long   Dim p_lngResumeHwnd              As Long   Dim p_lngLoop                    As Long   Dim p_lngSidType                 As Long   Dim p_strUserName                As String   Dim p_strSidType                 As String   Dim p_strSID                     As String   Dim p_typLocalGroupMembers1      As LOCALGROUP_MEMBERS_INFO_1   Dim p_alngMemberInfo()           As Long   Dim p_astrMemberInfo()           As String      ' Convert the server name to a pointer   If Len(Trim$(xi_strServerName)) = 0 Then      p_lngPtrServerName = 0&   Else      p_lngPtrServerName = StrPtr(xi_strServerName)   End If      ' Convert the user name to a pointer   If Len(Trim$(p_lngPtrLocalGroupName)) = 0 Then      MsgBox "You must enter a local group name!", vbExclamation, "Input Error"      Exit Function   Else      p_lngPtrLocalGroupName = StrPtr(xi_strLocalGroupName)   End If      p_lngPreferredMaxLen = 4096&   p_lngResumeHwnd = 0&   p_lngRtn = NetLocalGroupGetMembers(p_lngPtrServerName, _                                      p_lngPtrLocalGroupName, _                                      LocalGroupMembersInfo1, _                                      p_lngPtrBuffer, _                                      p_lngPreferredMaxLen, _                                      p_lngEntriesRead, _                                      p_lngTotalEntries, _                                      p_lngResumeHwnd)   If p_lngRtn = NERR_Success Then      ReDim p_alngMemberInfo(0 To (p_lngEntriesRead * 3) - 1) As Long      ReDim p_astrMemberInfo(1 To p_lngEntriesRead) As String            ' This gets the pointers to the structures      CopyMem p_alngMemberInfo(0), _              ByVal p_lngPtrBuffer, _              p_lngEntriesRead * 4 * 3            If p_lngEntriesRead > 0 Then         For p_lngLoop = 0 To p_lngEntriesRead - 1            p_strSidType = TranslateSidUsage(p_alngMemberInfo((p_lngLoop * 3) + 1))            p_strUserName = PointerToStringW(p_alngMemberInfo((p_lngLoop * 3) + 2))            p_astrMemberInfo(p_lngLoop + 1) = p_strUserName & " [" & p_strSidType & "]"         Next p_lngLoop      End If            If p_lngPtrBuffer Then         NetApiBufferFree p_lngPtrBuffer      End If            GetLocalGroupMembers = p_astrMemberInfo   Else      GetLocalGroupMembers = ""   End If   End Function' ================================================' Get all of the local groups' ================================================Public Function GetLocalGroups(ByVal xi_strServerName As String) As Variant   Dim p_lngRtn                     As Long   Dim p_lngLoop                    As Long   Dim p_lngPtrBuffer               As Long   Dim p_lngPtrServerName           As Long   Dim p_lngPreferredMaxLen         As Long   Dim p_lngResumeHwnd              As Long   Dim p_lngEntriesRead             As Long   Dim p_lngTotalEntries            As Long   Dim p_alngGroupInfo()            As Long   Dim p_astrGroupInfo()            As String      ' Convert the server name to a pointer   If Len(Trim$(xi_strServerName)) = 0 Then      p_lngPtrServerName = 0&   Else      p_lngPtrServerName = StrPtr(xi_strServerName)   End If   p_lngPreferredMaxLen = 4096&   p_lngResumeHwnd = 0&   p_lngRtn = NetLocalGroupEnum(p_lngPtrServerName, _                                LocalGroupInfo0, _                                p_lngPtrBuffer, _                                p_lngPreferredMaxLen, _                                p_lngEntriesRead, _                                p_lngTotalEntries, _                                p_lngResumeHwnd)   If p_lngRtn = NERR_Success Then      ReDim p_alngGroupInfo(0 To p_lngEntriesRead - 1) As Long      ReDim p_astrGroupInfo(1 To p_lngEntriesRead) As String            ' This gets the pointers to the structures      CopyMem p_alngGroupInfo(0), _              ByVal p_lngPtrBuffer, _              p_lngEntriesRead * 4            If p_lngEntriesRead > 0 Then         For p_lngLoop = 0 To p_lngEntriesRead - 1            p_astrGroupInfo(p_lngLoop + 1) = PointerToStringW(p_alngGroupInfo(p_lngLoop))         Next p_lngLoop      End If            If p_lngPtrBuffer Then         NetApiBufferFree p_lngPtrBuffer      End If            GetLocalGroups = p_astrGroupInfo   Else      GetLocalGroups = ""   End If   End Function' ================================================' Either add or delete a user from a selected' local group (depends upon xi_blnAddUser)' ================================================Function AddDelUserToLocal(ByVal xi_strGroupName As String, _                           ByVal xi_strUserName As String, _                           ByVal xi_strServerName As String, _                           ByVal xi_blnAddUser As Boolean) As Boolean   Dim p_lngPtrGroupName   As Long   Dim p_lngPtrUserName    As Long   Dim p_lngPtrServerName  As Long   Dim p_lngMemberCount    As Long   Dim p_lngRtn            As Long      ' Convert the server name to a pointer   If Len(Trim$(xi_strServerName)) = 0 Then      p_lngPtrServerName = 0&   Else      p_lngPtrServerName = StrPtr(xi_strServerName)   End If   ' Convert the group name to a pointer   p_lngPtrGroupName = StrPtr(xi_strGroupName)      ' Convert the user name to a pointer   p_lngPtrUserName = StrPtr(xi_strUserName)      ' Add the user   p_lngMemberCount = 1      If xi_blnAddUser = True Then      p_lngRtn = NetLocalGroupAddMembers(p_lngPtrServerName, _                                         p_lngPtrGroupName, _                                         LocalGroupMembersInfo3, _                                         p_lngPtrUserName, _                                         p_lngMemberCount)   Else      p_lngRtn = NetLocalGroupDelMembers(p_lngPtrServerName, _                                         p_lngPtrGroupName, _                                         LocalGroupMembersInfo3, _                                         p_lngPtrUserName, _                                         p_lngMemberCount)   End If      If p_lngRtn = NERR_Success Then      AddDelUserToLocal = True   Else      AddDelUserToLocal = False   End If   End Function' ================================================' Convert the SID type to a text string' ================================================Private Function TranslateSidUsage(ByVal xi_lngSidType As Long) As String   Dim p_strTmp                  As String      Select Case xi_lngSidType      Case SidTypeUser         p_strTmp = "User Account"      Case SidTypeGroup         p_strTmp = "Global Group Account"      Case SidTypeDomain         p_strTmp = "Domain Group Account"      Case SidTypeAlias         p_strTmp = "Alias Account"      Case SidTypeWellKnownGroup         p_strTmp = "Well-known Group Account (ie, Everyone)"      Case SidTypeDeletedAccount         p_strTmp = "Deleted Account"      Case SidTypeInvalid         p_strTmp = "Invalid Account"      Case SidTypeUnknown         p_strTmp = "Account Type Cannot Be Determined"      Case Else         p_strTmp = "Bad Parameter for Sid Usage"   End Select      ' Set the return value   TranslateSidUsage = p_strTmp   End Function' ================================================' Convert a pointer to a string into a string' ================================================Public Function PointerToStringW(ByVal xi_lngPtrToString As Long) As String   Dim p_strText           As String   Dim p_lngLength         As Long   If xi_lngPtrToString Then         p_lngLength = lstrlenW(xi_lngPtrToString)      If p_lngLength > 0 Then         p_strText = Space$(p_lngLength)         CopyMem ByVal StrPtr(p_strText), ByVal xi_lngPtrToString, p_lngLength * 2      End If   End If      PointerToStringW = p_strTextEnd Function' ================================================' Convert a pointer to a string into a string via ' a byte array' ================================================Private Function PointerToStringWByte(ByVal xi_lngPtrToString As Long) As String   Dim p_abytBuffer()      As Byte   Dim p_lngLen            As Long      If xi_lngPtrToString <> 0 Then      p_lngLen = lstrlenW(xi_lngPtrToString) * 2      If p_lngLen Then         ReDim p_abytBuffer(0 To (p_lngLen - 1)) As Byte         CopyMem p_abytBuffer(0), ByVal xi_lngPtrToString, p_lngLen         PointerToStringWByte = p_abytBuffer      End If   End If   End Function

See also  Professionalism Starts in Your Inbox: Keys to Presenting Your Best Self in Email
devxblackblue

About Our Editorial Process

At DevX, we’re dedicated to tech entrepreneurship. Our team closely follows industry shifts, new products, AI breakthroughs, technology trends, and funding announcements. Articles undergo thorough editing to ensure accuracy and clarity, reflecting DevX’s style and supporting entrepreneurs in the tech sphere.

See our full editorial policy.

About Our Journalist