' IsMember9.vbs
' VBScript program demonstrating the use of Function IsMember.
'
' ----------------------------------------------------------------------
' Copyright (c) 2004 Richard L. Mueller
' Hilltop Lab web site - http://www.rlmueller.net
' Version 1.0 - April 22, 2004
' Version 1.1 - June 3, 2004 - Bug fix.
' Version 1.2 - April 5, 2007 - Retrieve NetBIOS name of domain from
'               wshNetwork. Document global variables.
' Version 1.3 - July 31, 2007 - Escape any "/" characters in DN's.
' Version 1.4 - August 3, 2008 - Skip local implicit groups.
' A VBScript program demonstrating how to test for membership in a local
' group on the computer. The function reveals direct membership in the
' local group, membership by local group nesting, membership in the
' local group due to membership in a domain group that is a member of
' the local group, and membership due to domain group nesting.
'
' You have a royalty-free right to use, modify, reproduce, and
' distribute this script file in any way you find useful, provided that
' you agree that the copyright owner above has no warranty, obligations,
' or liability for such use.

Option Explicit

Dim objNetwork, strNTUser, objLocalGroup, objUser

' These attributes must be declared in the main program,
' so they are global in scope.
Dim objTrans, strUserDN, strComputer, strNetBIOSDomain

' Constants for the NameTranslate object.
Const ADS_NAME_INITTYPE_GC = 3
Const ADS_NAME_TYPE_NT4 = 3
Const ADS_NAME_TYPE_1779 = 1

' Determine domain user NT name and netBIOS name of the local computer
' and the domain.
Set objNetwork = CreateObject("Wscript.Network")
strNTUser = objNetwork.UserName
strComputer = objNetwork.ComputerName
strNetBIOSDomain = objNetwork.UserDomain
Set objNetwork = Nothing

' Bind to local Administrators group.
Set objLocalGroup = GetObject("WinNT://" & strComputer _
    & "/Administrators,group")

' Bind to the domain user object.
Set objUser = GetObject("WinNT://" & strNetBIOSDomain _
    & "/" & strNTUser & ",user")

' Check for membership in local group.
If (IsMember(objLocalGroup, objUser) = True) Then
    Wscript.Echo "User " & strNTUser _
        & " is a member of the local group " & objLocalGroup.Name
Else
    Wscript.Echo "User " & strNTUser _
        & " is NOT a member of the local group " & objLocalGroup.Name
End If

Function IsMember(ByVal objGroup, ByVal objDomainUser)
    ' Function to determine if objDomainUser is a member
    ' of local group objGroup. The variable strComputer has
    ' global scope.

    Dim objMember

    ' Enumerate direct members of objGroup.
    For each objMember In objGroup.Members
        ' Test if objDomainUser is objMember.
        If (LCase(objMember.AdsPath) = LCase(objDomainUser.AdsPath)) Then
            IsMember = True
            Exit Function
        End If
        ' Test if objMember is a group.
        If (LCase(objMember.Class) = "group") Then
            ' Test if objMember is a local group.
            If (InStr(LCase(objMember.AdsPath), "/" _
                    & LCase(strComputer) & "/") > 0) Then
                ' Call function recursively to check if objDomainUser is a
                ' member of local group objMember.
                IsMember = IsMember(objMember, objDomainUser)
                If (IsMember = True) Then
                    Exit Function
                End If
            ElseIf (InStr(LCase(objMember.AdsPath), _
                    "/nt authority/") > 0) Then
                ' objMember is local implicit group (special identity).
                ' Membership cannot be enumerated.
            Else
                ' objMember is a domain group. Check membership with a function
                ' that uses the LDAP provider, so that nested group membership
                ' is revealed. objMember is bound with the WinNT provider.
                IsMember = IsDomainMember(objMember, objDomainUser, True)
                If (IsMember = True) Then
                    Exit Function
                End If
            End If
        End If
    Next
    IsMember = False
End Function

Function IsDomainMember(ByVal objDomainGroup, ByVal objDomainUser, ByVal blnNT)
    ' Function to determine if objDomainUser is a member
    ' of domain group objDomainGroup. blnNT is True if objDomainGroup
    ' was bound with WinNT, False if bound with LDAP.
    ' The variables objTrans, strUserDN, and strNetBIOSDomain have global scope.

    Dim arrstrNTNames(1), arrstrDNSNames
    Dim strGroupDN, objGroup, objMember

    ' Check if this function called before.
    If (IsEmpty(objTrans) = True) Then
        ' Setup NameTranslate to convert NT names of group and user
        ' to Distinguished Names required by the LDAP provider.
        Set objTrans = CreateObject("NameTranslate")
        objTrans.Init ADS_NAME_INITTYPE_GC, ""
        arrstrNTNames(0) = strNetBIOSDomain & "\" & objDomainGroup.Name
        arrstrNTNames(1) = strNetBIOSDomain & "\" & objDomainUser.Name
        objTrans.SetEx ADS_NAME_TYPE_NT4, arrstrNTNames
        arrstrDNSNames = objTrans.GetEx(ADS_NAME_TYPE_1779)
        strGroupDN = arrstrDNSNames(0)
        strUserDN = arrstrDNSNames(1)
        ' Escape any forward slash characters, "/", with the backslash
        ' escape character. All other characters that should be escaped are.
        strGroupDN = Replace(strGroupDN, "/", "\/")
        strUserDN = Replace(strUserDN, "/", "\/")
    Else
        ' NameTranslate already setup. Check if objDomainGroup
        ' bound with WinNT.
        If (blnNT = True) Then
            ' Convert objDomainGroup NT name to Distinguished Name
            ' required by the LDAP provider.
            objTrans.Set ADS_NAME_TYPE_NT4, strNetBIOSDomain _
                & "\" & objDomainGroup.Name
            strGroupDN = objTrans.Get(ADS_NAME_TYPE_1779)
            ' Escape any forward slash characters, "/", with the backslash
            ' escape character. All other characters that should be escaped are.
            strGroupDN = Replace(strGroupDN, "/", "\/")
        Else
            ' objDomainGroup bound with LDAP. Retrieve Distinguished Name.
            strGroupDN = objDomainGroup.distinguishedName
            ' Escape any forward slash characters, "/", with the backslash
            ' escape character. All other characters that should be escaped are.
            strGroupDN = Replace(strGroupDN, "/", "\/")
        End If
    End If
    ' Bind to group with the LDAP provider, if required.
    If (blnNT = True) Then
        Set objGroup = GetObject("LDAP://" & strGroupDN)
    Else
        Set objGroup = objDomainGroup
    End If
    ' Enumerate direct members of objDomainGroup (bound with LDAP).
    For Each objMember In objGroup.Members
        ' Check if objMember is objDomainUser (strUserDN).
        If (LCase(objMember.distinguishedName) = LCase(strUserDN)) Then
            IsDomainMember = True
            Exit Function
        End If
        ' Check if objMember is a group.
        If (LCase(objMember.Class) = "group") Then
            ' Call function recursively. objMember bound with LDAP.
            IsDomainMember = IsDomainMember(objMember, objDomainUser, False)
            If (IsDomainMember = True) Then
                Exit Function
            End If
        End If
    Next
    IsDomainMember = False

End Function