Platform SDK: Active Directory, ADSI, and Directory Services

Example Code for Enumerating Groups

[C++]

The following code fragment contains a function that enumerates all objects of a specified class (such as group) and displays the members contained in each object on a member server or a computer running Windows NT Workstation/Windows 2000 Professional:

////////////////////////////////////////////////////////////////////////////////////////////////////
/*  ListMembersWithWinNtProvider()    - Uses the WinNT provider to list children based on a filter
                                        Returns S_OK on success   
 
    Parameters
 
    LPWSTR pwszComputer     - Computer to list
    LPWSTR pwszClass        - Filter for listing
    LPWSTR pwszUSER = NULL  - User Name for ADsOpenObject() binding- If NOT passed - Bind Though ADsGetObject()
    LPWSTR pwszPASS = NULL  - Password for ADsOpenObject() binding- If NOT passed - Bind Though ADsGetObject()
 
*/
HRESULT ListMembersWithWinNtProvider(LPWSTR pwszComputer,LPWSTR pwszClass, LPWSTR pwszUSER = NULL, LPWSTR pwszPASS = NULL)
{
    HRESULT hr;
    LPWSTR  pwszBindingString = NULL;
 
    IADsContainer * pIADsCont = NULL;
 
    // Allocate a String for Binding.. This should definitely be big enough..
    pwszBindingString = new WCHAR[(wcslen(gbsComputer) *2) + 20];
    
    swprintf(pwszBindingString,L"WinNT://%s,computer",pwszComputer);
 
    // Make sure either NO user is passed - or BOTH user and password are passed
    assert(!pwszUSER || (pwszUSER && pwszPASS));
 
    // Bind to the container passed 
    // If USER and PASS passed in, use ADsOpenObject()
    if (pwszUSER)
        hr = ADsOpenObject( pwszBindingString,
                            pwszUSER, 
                            pwszPASS, 
                            ADS_SECURE_AUTHENTICATION,
                            IID_IADsContainer, 
                            (void**) &pIADsCont);
    else
        hr = ADsGetObject( pwszBindingString, IID_IADsContainer,(void **)&pIADsCont);
 
    if (SUCCEEDED(hr))
    {
        VARIANT vFilter;
        VariantInit(&vFilter);
        LPWSTR pwszFilter = pwszClass;
 
        // Build a Variant of array type, using the filter passed
        hr = ADsBuildVarArrayStr(&pwszFilter, 1, &vFilter);
 
        if (SUCCEEDED(hr))
        {
            // Set the filter for the results of the Enum
            hr = pIADsCont->put_Filter(vFilter);
 
            if (SUCCEEDED(hr))
            {
                IEnumVARIANT * pEnumVariant = NULL; // Ptr to the IEnumVariant Interface
                VARIANT Variant;                    // Variant for retrieving data
                ULONG   ulElementsFetched;          // Number of elements fetched
 
                // Builds an enumerator interface- this will be used 
                // to enumerate the objects contained in the IADsContainer 
                hr = ADsBuildEnumerator(pIADsCont,&pEnumVariant);
                // While no errors- Loop through and print the data
                while (SUCCEEDED(hr) && hr != S_FALSE) 
                {
 
                    // Object comes back as a VARIANT holding an IDispatch *
                    hr = ADsEnumerateNext(pEnumVariant,1,&Variant,&ulElementsFetched);
 
                    if (hr != S_FALSE) 
                    { 
                        assert(HAS_BIT_STYLE(Variant.vt,VT_DISPATCH));
 
                        IDispatch *pDispatch = NULL;
                        IADs *pIADs= NULL;
                        pDispatch = Variant.pdispVal;
 
                        // QI the Variant's IDispatch * for the IADs interface
                        hr = pDispatch->QueryInterface(IID_IADs,(VOID **) &pIADs) ;
 
                        if (SUCCEEDED(hr))
                        {
                            // Print some information about the object
                            BSTR bsResult;
 
                            pIADs->get_Name(&bsResult); 
                            wprintf(L" NAME: %s\n",(LPOLESTR) bsResult);
                            SysFreeString(bsResult);
 
 
                            pIADs->get_ADsPath(&bsResult); 
                            wprintf(L" ADSPATH: %s\n",(LPOLESTR) bsResult);
                            SysFreeString(bsResult);
 
                            puts("------------------------------------------------------");
                            pIADs->Release();
                            pIADs = NULL;
                        }
                    }
                }
 
                // Since the hr from iteration was lost, free 
                // the interface if the ptr is != NULL
                if (pEnumVariant)
                {
                    pEnumVariant->Release();
                    pEnumVariant = NULL;
                }
                VariantClear(&Variant);
            }
        }
        VariantClear(&vFilter);
    }
 
    delete [] pwszBindingString;
    pwszBindingString = NULL;
 
    return hr;
}
[Visual Basic]

The following code enumerates all groups and displays the members contained in each group on a member server or a computer running Windows NT Workstation/Windows 2000 Professional:

'Example: Enumerating all local groups on member server or Windows NT Workstation/Windows 2000 Professional
Dim IADsCont As IADsContainer
Dim Group As IADsGroup
 
 
sComputer = InputBox("This script lists the groups on a member server or workstation." & vbCrLf & vbCrLf & "Specify the computer name:")
 
If sComputer = "" Then
  MsgBox "No computer name was specified. You must specify a computer name."
  Exit Sub
End If
 
'''''''''''''''''''''''''''''''''''''''
'Bind to the computer
'''''''''''''''''''''''''''''''''''''''
'Note that this sample uses the caller's security context.
'To specify a user account other than the user account under which 
'which your application is running, use IADsOpenDSObject.
Set IADsCont = GetObject("WinNT://" & sComputer & ",computer")
If (Err.Number <> 0) Then
   BailOnFailure Err.Number, "on GetObject method"
End If
 
'''''''''''''''''''''''''''''''''''''''
'Filter to view only group objects
'''''''''''''''''''''''''''''''''''''''
IADsCont.Filter = Array("group")
If (Err.Number <> 0) Then
   BailOnFailure Err.Number, "on IADsContainer::Filter method"
End If
 
strText = ""
intIndex = 0
intNumDisplay = 0
cmember = 0
'Maximum number of groups to list on a msgbox.
MAX_DISPLAY = 10
 
'''''''''''''''''''''''''''''''''''''''
'Get each group and display its name and its members
'''''''''''''''''''''''''''''''''''''''
For Each Group In IADsCont
    intIndex = intIndex + 1
    'Get the name
    strText = strText & vbCrLf & Right("  " & intIndex, 4) & " " & Group.Name
 
    intNumDisplay = intNumDisplay + 1
    'Get the members object
    Set memberList = Group.members
    If (Err.Number <> 0) Then
       BailOnFailure Err.Number, "on IADsGroup::members method"
    End If
 
    'Get the enumerate the members of the group from the members object
    For Each member In memberList
      If cmember = 0 Then
    strText = strText & vbCrLf & "       " & "Members:"
      End If
      strText = strText & vbCrLf & "       " & member.Name & " (" & member.Class & ")"
      cmember = cmember + 1
    Next
    If cmember = 0 Then
      strText = strText & vbCrLf & "       " & "No members"
    End If
    'Display in msgbox if there are MAX_DISPLAY groups to display
    If intNumDisplay >= MAX_DISPLAY Then
        Call show_groups(strText, sComputer)
        strText = ""
        intNumDisplay = 0
    End If
    'Reset the count of members within the current group
    cmember = 0
Next
Call show_groups(strText, sComputer)
 
 
'''''''''''''''''''''''''''''''''''''''
'Display subroutines
'''''''''''''''''''''''''''''''''''''''
Sub show_groups(strText, strName)
    MsgBox strText, vbInformation, "Groups on " & strName
End Sub
 
Sub BailOnFailure(ErrNum, ErrText)    strText = "Error 0x" & Hex(ErrNum) & " " & ErrText
    MsgBox strText, vbInformation, "ADSI Error"
    WScript.Quit
End Sub