home *** CD-ROM | disk | FTP | other *** search
/ io Programmo 27 / IOPROG_27.ISO / SOFT / ADSDK.ZIP / Samples / ActiveDir / IsMemberEx / vc / main.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1999-01-13  |  52.6 KB  |  1,223 lines

  1.  
  2. #define INC_OLE2
  3. #define UNICODE 1
  4. #define _WIN32_DCOM
  5.  
  6. #include "stdafx.h"
  7. #include <afxtempl.h>
  8.  
  9. #ifdef _DEBUG
  10. #define new DEBUG_NEW
  11. #undef THIS_FILE
  12. static char THIS_FILE[] = __FILE__;
  13. #endif
  14.  
  15. #include <stdio.h>
  16. #include <stdlib.h>
  17. #include <string.h>
  18. #include <malloc.h>
  19. #include <winldap.h>
  20.  
  21. #include <activeds.h>
  22. #include <assert.h>
  23.  
  24. #include "ADSIhelpers.h"
  25.  
  26.  
  27.  
  28.  
  29. ////////////////////////////////////////////////////////////////////////////////////////////////////
  30. // String for usage information
  31. WCHAR * pwszUsage = L"Checks to see if a member is in a group\n"
  32.                     L"Usage:\n"
  33.                     L"IsMember\n"
  34.                     L"        <*> Checks passed LDAP path  for Group Membership<*>\n"
  35.                     L"            /GROUP \n" 
  36.                     L"             This is the LDAP path for the group to check\n"
  37.                     L"            /MEMBER \n" 
  38.                     L"              LDAP Path of the object to check membership\n\n"
  39.                     L"            /RECURSE \n"
  40.                     L"              Recursively scan for membership\n" 
  41.                     L"            /VERBOSE\n"
  42.                     L"              Prints out detailed information as \n"
  43.                     L"              the program is processing\n\n"
  44.                     L"        <*> OPTIONAL Binding Information <*>\n"
  45.                     L"           /USER <User name used for binding to the DC>\n"
  46.                     L"           /PASS <Password used for binding to the DC>\n"
  47.                     L"           (If these are passed, binding is done with ADsOpenObject())\n"
  48.                     L"\n";
  49.  
  50.  
  51. /* Sample command line:
  52.  
  53. /LDAP "LDAP://nttest.microsoft.com/CN=UGExercise Sample Container,dc=nttest,dc=microsoft,dc=com" /UNAME BOB /SAMNAME BOB /USER Administrator /PASS "" /RECURSE /VERBOSE
  54.  
  55. */
  56.  
  57. ////////////////////////////////////////////////////////////////////////////////////////////////////
  58. // Module level global variables
  59.  
  60. BSTR gbsGroup     = NULL; // <Group to check> This is the LDAP path for the group to check
  61.  
  62. BSTR gbsMember    = NULL; // <Member to check> 
  63.     
  64. BSTR gbsUSER      = NULL; // <User name used for binding to the DC>
  65.                         // If this is NON-NULL, then binding with occurr with AdsOpenObject()
  66.                         // Otherwise will use ADsGetObject()    
  67.  
  68. BSTR gbsPASS      = NULL; // <Password used for binding to the DC>
  69.  
  70. BOOL gbRecurse    = FALSE; // If TRUE, will recurse any contained groups looking for the member 
  71.  
  72. BOOL gbVerbose    = FALSE; // If true- will spit out info as it is finding it
  73.  
  74. ////////////////////////////////////////////////////////////////////////////////////////////////////
  75. // Forward Declarations
  76. BOOL    ParseCommandLine( int argc, wchar_t *argv[ ]);
  77. void    PrintIADSObject (IADs * pIADs);
  78. void    PrintBanner     (LPOLESTR pwszBanner);
  79. void    PrintBanner     (LPOLESTR pwszBanner);
  80. HRESULT GetObjectGuid(IDirectoryObject * pDO,BSTR &bsGuid);
  81. HRESULT CheckGroupObjectMembersForMembership(IADsGroup * pADsGroup,LPWSTR pwszMemberGUID,LPWSTR pwszMemberPath,CStringArray & arMemberOf,
  82.                                              BOOL bVerbose,LPOLESTR  pwszUser = NULL, LPOLESTR pwszPassword = NULL);
  83.  
  84. #define FETCH_NUM 100 // number of elements to fetch at a time 
  85.  
  86.  
  87. ////////////////////////////////////////////////////////////////////////////////////////////////////
  88. /*  RecursiveRetrieveGroupsMemberBelongsto()    - Prints the Recursively scans the members of passed IADsGroup ptr
  89.                                                 and any groups belonging to the passed ptr- for membership
  90.                                                 of Passed group
  91.                                                 Will return a CStringArray of all groups which member belongs to
  92.     Parameters
  93.  
  94.         IADsGroup *     pADsGroup       - Group from which to list members
  95.         LPWSTR          pwszMember      - LDAP path for object to check membership
  96.         CStringArray &  arMemberOf      - Returned array of Groups passed member belongs to
  97.         BOOL            bVerbose        - IF TRUE- will ouput verbose information on the scanning
  98.     
  99.     OPTIONAL Parameters
  100.  
  101.        LPOLESTR  pwszUser           - User Name and Password, if the parameters are NOT passed, 
  102.        LPOLESTER pwszPassword       - Binding will use ADsGetObject, if the parameters
  103.                                     - Are specified, will use ADsOpenObject, passing user name and password
  104. */
  105.  
  106.  
  107. HRESULT RecursiveRetrieveGroupsMemberBelongsto(IADsGroup * pADsGroup,LPWSTR pwszMemberGUID,LPWSTR pwszMemberPath, CStringArray & arMemberOf,
  108.                                              BOOL bVerbose, LPOLESTR  pwszUser = NULL, LPOLESTR pwszPassword = NULL)
  109. {
  110.     HRESULT         hr                = S_OK;     // COM Result Code
  111.     IADsMembers *   pADsMembers       = NULL;     // Ptr to Members of the IADsGroup
  112.     BOOL            fContinue         = TRUE;     // Looping Variable
  113.     IEnumVARIANT *  pEnumVariant      = NULL;     // Ptr to the Enum variant
  114.     IUnknown *      pUnknown          = NULL;     // IUnknown for getting the ENUM initially
  115.     VARIANT         VariantArray[FETCH_NUM];      // Variant array for temp holding retuned data
  116.     ULONG           ulElementsFetched = NULL;     // Number of elements fetched
  117.     BSTR            bsGroupPath       = NULL;
  118.     
  119.     // Get the path of the object passed in
  120.     hr = pADsGroup->get_ADsPath(&bsGroupPath);
  121.     CheckADHRESULT(hr);
  122.  
  123.     if (!SUCCEEDED(hr))
  124.         return hr;
  125.  
  126.     if (bVerbose)
  127.     {
  128.         WCHAR pwszOutput[2048];
  129.         wsprintf(pwszOutput,L"Checking the Group:\n\n%s\n\n for the member:\n\n%s\n\n",bsGroupPath,pwszMemberPath);
  130.         PrintBanner(pwszOutput);
  131.     }
  132.     
  133.     // Get a interface pointer to the IADsCollection of members
  134.     hr = pADsGroup->Members(&pADsMembers);
  135.     CheckADHRESULT(hr);
  136.  
  137.     if (SUCCEEDED(hr))
  138.     {
  139.         // Ask the IADsCollection of members for a new ENUM Interface
  140.         // Note the enum comes back as an IUnknown *
  141.         hr = pADsMembers->get__NewEnum(&pUnknown);
  142.         CheckADHRESULT(hr);
  143.  
  144.         if (SUCCEEDED(hr))
  145.         {
  146.             // QI the IUnknown * for a IEnumVARIANT interface
  147.             hr = pUnknown->QueryInterface(IID_IEnumVARIANT, (void **)&pEnumVariant);
  148.             CheckADHRESULT(hr);
  149.  
  150.             if (SUCCEEDED(hr))
  151.             {
  152.                 // While have not hit errors or end of data....
  153.                 while (fContinue) 
  154.                 {
  155.                    ulElementsFetched = 0;
  156.                     // Get a "batch" number of group members- number of rows specified by FETCH_NUM
  157.                     hr = ADsEnumerateNext(pEnumVariant, FETCH_NUM, VariantArray, &ulElementsFetched);
  158.  
  159.                     if (ulElementsFetched )
  160.                     {
  161.                         // Loop through the current batch- printing the path 
  162.                         // for each member
  163.                         for (ULONG i = 0; i < ulElementsFetched; i++ ) 
  164.                         {
  165.                             IDispatch * pDispatch         = NULL; // ptr for holding dispath of element
  166.                             BSTR        bstrCurrentPath   = NULL; // Holds path of object
  167.                             BSTR        bstrGuidCurrent   = NULL; // Holds path of object
  168.                             IDirectoryObject * pIDOCurrent = NULL;// Holds the current object          
  169.  
  170.                             // Get the dispatch ptr for the variant
  171.                             pDispatch = VariantArray[i].pdispVal;
  172.                             assert(HAS_BIT_STYLE(VariantArray[i].vt,VT_DISPATCH));
  173.  
  174.                             // Get the IADs interface for the "member" of this group
  175.                             hr = pDispatch->QueryInterface(IID_IDirectoryObject,
  176.                                                            (VOID **) &pIDOCurrent ) ;
  177.                             CheckADHRESULT(hr);
  178.  
  179.                             if (SUCCEEDED(hr))
  180.                             {
  181.                                 // Retrieve the GUID for the current object
  182.                                 hr = GetObjectGuid(pIDOCurrent,bstrGuidCurrent);
  183.                                 CheckADHRESULT(hr);
  184.  
  185.                                 if (FAILED(hr))
  186.                                     return hr;
  187.  
  188.                                 IADs * pIADsCurrent = NULL;
  189.  
  190.                                 // Retrieve the IADs Interface for the current object
  191.                                 hr = pIDOCurrent->QueryInterface(IID_IADs,(void**)&pIADsCurrent);
  192.                                 CheckADHRESULT(hr);
  193.                                 if (FAILED(hr))
  194.                                     return hr;
  195.  
  196.                                 // Get the ADsPath property for this member
  197.                                 hr = pIADsCurrent->get_ADsPath(&bstrCurrentPath);
  198.                                 CheckADHRESULT(hr);
  199.  
  200.                                 if (SUCCEEDED(hr))
  201.                                 {
  202.                                     if (bVerbose)
  203.                                         wprintf(L"Comparing:\n\n%s\nWITH:\n%s\n\n",bstrGuidCurrent,pwszMemberGUID);
  204.                                     
  205.                                     // Is the "member of this group Equal to passed?
  206.                                     if (_wcsicmp(bstrGuidCurrent,pwszMemberGUID)==0)
  207.                                     {
  208.                                         if (bVerbose)
  209.                                             wprintf(L"!!!!!Object:\n\n%s\n\nIs a member of\n\n%s\n\n",pwszMemberPath,bstrGuidCurrent);   
  210.  
  211.                                         // Add the group to the array
  212.                                         arMemberOf.Add(bsGroupPath);
  213.                                     }
  214.                                     else // Otherwise, we should bind to this and see if it is a group
  215.                                     {    // If is it a group then the QI to IADsGroup will succeed
  216.                                         
  217.                                         IADsGroup * pIADsGroupAsMember = NULL;
  218.                                         
  219.                                         if (pwszUser)
  220.                                             hr = ADsOpenObject( bstrCurrentPath,
  221.                                                                 pwszUser, 
  222.                                                                 pwszPassword, 
  223.                                                                 ADS_SECURE_AUTHENTICATION,
  224.                                                                 IID_IADsGroup, 
  225.                                                                 (void**) &pIADsGroupAsMember);
  226.                                         else
  227.                                             hr = ADsGetObject( bstrCurrentPath, IID_IADsGroup,(void **)&pIADsGroupAsMember);
  228.  
  229.                                         // If we DID bind, then this IS a group
  230.                                         if (SUCCEEDED(hr))
  231.                                         {
  232.                                             // Recursively call ourselves to check THIS group
  233.                                             hr = RecursiveRetrieveGroupsMemberBelongsto(pIADsGroupAsMember,pwszMemberGUID,pwszMemberPath,arMemberOf,bVerbose,pwszUser ,pwszPassword );
  234.                                             pIADsGroupAsMember->Release();
  235.                                             pIADsGroupAsMember = NULL;
  236.                                         }
  237.                                     }
  238.                                     SysFreeString(bstrCurrentPath);
  239.                                     bstrCurrentPath = NULL;
  240.  
  241.                                     SysFreeString(bstrGuidCurrent);
  242.                                     bstrGuidCurrent = NULL;
  243.                                     if (pIADsCurrent)
  244.                                     {
  245.                                         pIADsCurrent->Release();
  246.                                         pIADsCurrent = NULL;
  247.                                     }
  248.                                 }
  249.                                 // Release
  250.                                 pIDOCurrent->Release();
  251.                                 pIDOCurrent = NULL;
  252.                             }
  253.                          }
  254.                         // Clear the variant array
  255.                         memset(VariantArray, 0, sizeof(VARIANT)*FETCH_NUM);
  256.                     }
  257.                     else
  258.                         fContinue = FALSE;
  259.                 }
  260.                 pEnumVariant->Release();
  261.                 pEnumVariant = NULL;
  262.             }
  263.             pUnknown->Release();
  264.             pUnknown = NULL;
  265.         }
  266.         pADsMembers ->Release();
  267.         pADsMembers  = NULL;
  268.     }
  269.  
  270.     // Free the group path if it was retrieved.
  271.     if (bsGroupPath)
  272.     {
  273.         SysFreeString(bsGroupPath);
  274.         bsGroupPath = NULL;
  275.     }
  276.     // If everything WENT ok ->we printed all the 
  277.     // data and receieved an S_FALSE (indiciating no more data)
  278.     // if that is the case we REALLY want to return a S_OK
  279.     if (hr == S_FALSE)
  280.         hr = S_OK;
  281.     return hr;
  282. }
  283.  
  284. ////////////////////////////////////////////////////////////////////////////////////////////////////
  285. /*  RecursiveIsMember()             - Prints the Recursively scans the members of passed IADsGroup ptr
  286.                                                 and any groups belonging to the passed ptr- for membership
  287.                                                 of Passed group
  288.                                                 Will return a TRUE if the member is found in in the passed group,
  289.                                                 Or if the passed member is a member of any group which is a member
  290.                                                 of the passed group
  291.     Parameters
  292.  
  293.         IADsGroup *     pADsGroup       - Group from which to check members
  294.         LPWSTR          pwszMember      - LDAP path for object to check membership
  295.         BOOL            bVerbose        - IF TRUE- will ouput verbose information on the scanning
  296.     
  297.     OPTIONAL Parameters
  298.  
  299.        LPOLESTR  pwszUser           - User Name and Password, if the parameters are NOT passed, 
  300.        LPOLESTER pwszPassword       - Binding will use ADsGetObject, if the parameters
  301.                                     - Are specified, will use ADsOpenObject, passing user name and password
  302. */
  303.  
  304. BOOL RecursiveIsMember(IADsGroup * pADsGroup,LPWSTR pwszMemberGUID,LPWSTR pwszMemberPath, 
  305.                                              BOOL bVerbose, LPOLESTR  pwszUser, LPOLESTR pwszPassword)
  306. {
  307.     HRESULT         hr                = S_OK;     // COM Result Code
  308.     IADsMembers *   pADsMembers       = NULL;     // Ptr to Members of the IADsGroup
  309.     BOOL            fContinue         = TRUE;     // Looping Variable
  310.     IEnumVARIANT *  pEnumVariant      = NULL;     // Ptr to the Enum variant
  311.     IUnknown *      pUnknown          = NULL;     // IUnknown for getting the ENUM initially
  312.     VARIANT         VariantArray[FETCH_NUM];      // Variant array for temp holding retuned data
  313.     ULONG           ulElementsFetched = NULL;     // Number of elements fetched
  314.     BSTR            bsGroupPath       = NULL;
  315.     BOOL            bRet              = FALSE;
  316.  
  317.     // Get the path of the object passed in
  318.     hr = pADsGroup->get_ADsPath(&bsGroupPath);
  319.     CheckADHRESULT(hr);
  320.  
  321.     if (!SUCCEEDED(hr))
  322.         return hr;
  323.  
  324.     if (bVerbose)
  325.     {
  326.         WCHAR pwszOutput[2048];
  327.         wsprintf(pwszOutput,L"Checking the Group:\n\n%s\n\n for the member:\n\n%s\n\n",bsGroupPath,pwszMemberPath);
  328.         PrintBanner(pwszOutput);
  329.     }
  330.     
  331.     // Get a interface pointer to the IADsCollection of members
  332.     hr = pADsGroup->Members(&pADsMembers);
  333.     CheckADHRESULT(hr);
  334.  
  335.     if (SUCCEEDED(hr))
  336.     {
  337.         // Ask the IADsCollection of members for a new ENUM Interface
  338.         // Note the enum comes back as an IUnknown *
  339.         hr = pADsMembers->get__NewEnum(&pUnknown);
  340.         CheckADHRESULT(hr);
  341.  
  342.         if (SUCCEEDED(hr))
  343.         {
  344.             // QI the IUnknown * for a IEnumVARIANT interface
  345.             hr = pUnknown->QueryInterface(IID_IEnumVARIANT, (void **)&pEnumVariant);
  346.             CheckADHRESULT(hr);
  347.  
  348.             if (SUCCEEDED(hr))
  349.             {
  350.                 // While have not hit errors or end of data....
  351.                 while (fContinue) 
  352.                 {
  353.                    ulElementsFetched = 0;
  354.                     // Get a "batch" number of group members- number of rows specified by FETCH_NUM
  355.                     hr = ADsEnumerateNext(pEnumVariant, FETCH_NUM, VariantArray, &ulElementsFetched);
  356.  
  357.                     if (ulElementsFetched )
  358.                     {
  359.                         // Loop through the current batch- printing the path 
  360.                         // for each member
  361.                         for (ULONG i = 0; i < ulElementsFetched; i++ ) 
  362.                         {
  363.                             IDispatch * pDispatch         = NULL; // ptr for holding dispath of element
  364.                             BSTR        bstrCurrentPath   = NULL; // Holds path of object
  365.                             BSTR        bstrGuidCurrent   = NULL; // Holds path of object
  366.                             IDirectoryObject * pIDOCurrent = NULL;// Holds the current object          
  367.  
  368.                             // Get the dispatch ptr for the variant
  369.                             pDispatch = VariantArray[i].pdispVal;
  370.                             assert(HAS_BIT_STYLE(VariantArray[i].vt,VT_DISPATCH));
  371.  
  372.                             // Get the IADs interface for the "member" of this group
  373.                             hr = pDispatch->QueryInterface(IID_IDirectoryObject,
  374.                                                            (VOID **) &pIDOCurrent ) ;
  375.                             CheckADHRESULT(hr);
  376.  
  377.                             if (SUCCEEDED(hr))
  378.                             {
  379.                                 // Retrieve the GUID for the current object
  380.                                 hr = GetObjectGuid(pIDOCurrent,bstrGuidCurrent);
  381.                                 CheckADHRESULT(hr);
  382.  
  383.                                 if (FAILED(hr))
  384.                                     return hr;
  385.  
  386.                                 IADs * pIADsCurrent = NULL;
  387.  
  388.                                 // Retrieve the IADs Interface for the current object
  389.                                 hr = pIDOCurrent->QueryInterface(IID_IADs,(void**)&pIADsCurrent);
  390.                                 CheckADHRESULT(hr);
  391.                                 if (FAILED(hr))
  392.                                     return hr;
  393.  
  394.                                 // Get the ADsPath property for this member
  395.                                 hr = pIADsCurrent->get_ADsPath(&bstrCurrentPath);
  396.                                 CheckADHRESULT(hr);
  397.  
  398.                                 if (SUCCEEDED(hr))
  399.                                 {
  400.                                     if (bVerbose)
  401.                                         wprintf(L"Comparing:\n\n%s\nWITH:\n%s\n\n",bstrGuidCurrent,pwszMemberGUID);
  402.                                     
  403.                                     // Is the "member of this group Equal to passed?
  404.                                     if (_wcsicmp(bstrGuidCurrent,pwszMemberGUID)==0)
  405.                                     {
  406.                                         if (bVerbose)
  407.                                             wprintf(L"!!!!!Object:\n\n%s\n\nIs a member of\n\n%s\n\n",pwszMemberPath,bstrGuidCurrent);   
  408.  
  409.                                         bRet = TRUE;
  410.                                         break;
  411.                                     }
  412.                                     else // Otherwise, we should bind to this and see if it is a group
  413.                                     {    // If is it a group then the QI to IADsGroup will succeed
  414.                                         
  415.                                         IADsGroup * pIADsGroupAsMember = NULL;
  416.                                         
  417.                                         if (pwszUser)
  418.                                             hr = ADsOpenObject( bstrCurrentPath,
  419.                                                                 pwszUser, 
  420.                                                                 pwszPassword, 
  421.                                                                 ADS_SECURE_AUTHENTICATION,
  422.                                                                 IID_IADsGroup, 
  423.                                                                 (void**) &pIADsGroupAsMember);
  424.                                         else
  425.                                             hr = ADsGetObject( bstrCurrentPath, IID_IADsGroup,(void **)&pIADsGroupAsMember);
  426.  
  427.                                         // If we DID bind, then this IS a group
  428.                                         if (SUCCEEDED(hr))
  429.                                         {
  430.                                             // Recursively call ourselves to check THIS group
  431.                                             BOOL bRetRecurse;
  432.                                             bRetRecurse = RecursiveIsMember(pIADsGroupAsMember,pwszMemberGUID,pwszMemberPath,bVerbose,pwszUser ,pwszPassword );
  433.                                             
  434.                                             if (bRetRecurse)
  435.                                             {
  436.                                                 bRet = TRUE;
  437.                                                 break;
  438.                                             }
  439.                                             pIADsGroupAsMember->Release();
  440.                                             pIADsGroupAsMember = NULL;
  441.                                         }
  442.                                     }
  443.                                     SysFreeString(bstrCurrentPath);
  444.                                     bstrCurrentPath = NULL;
  445.  
  446.                                     SysFreeString(bstrGuidCurrent);
  447.                                     bstrGuidCurrent = NULL;
  448.                                 }
  449.                                 // Release
  450.                                 pIDOCurrent->Release();
  451.                                 pIDOCurrent = NULL;
  452.                                 if (pIADsCurrent)
  453.                                 {
  454.                                     pIADsCurrent->Release();
  455.                                     pIADsCurrent = NULL;
  456.                                 }
  457.                             }
  458.                          }
  459.                         // Clear the variant array
  460.                         memset(VariantArray, 0, sizeof(VARIANT)*FETCH_NUM);
  461.                     }
  462.                     else
  463.                         fContinue = FALSE;
  464.                 }
  465.                 pEnumVariant->Release();
  466.                 pEnumVariant = NULL;
  467.             }
  468.             pUnknown->Release();
  469.             pUnknown = NULL;
  470.         }
  471.         pADsMembers ->Release();
  472.         pADsMembers  = NULL;
  473.     }
  474.  
  475.     // Free the group path if it was retrieved.
  476.     if (bsGroupPath)
  477.     {
  478.         SysFreeString(bsGroupPath);
  479.         bsGroupPath = NULL;
  480.     }
  481.     return bRet;
  482. }
  483.  
  484. ////////////////////////////////////////////////////////////////////////////////////////////////////
  485. /*  RecursiveRetrieveAllMembers()     - Recursively scans the members of passed IADsGroup ptr
  486.                                       Returns all members found
  487.     Parameters
  488.  
  489.         IADsGroup *     pADsGroup       - Group from which to check members
  490.         BOOL            bVerbose        - IF TRUE- will ouput verbose information on the scanning
  491.     
  492.     OPTIONAL Parameters
  493.  
  494.        LPOLESTR  pwszUser           - User Name and Password, if the parameters are NOT passed, 
  495.        LPOLESTER pwszPassword       - Binding will use ADsGetObject, if the parameters
  496.                                     - Are specified, will use ADsOpenObject, passing user name and password
  497. */
  498. HRESULT RecursiveRetrieveAllMembers(IADsGroup * pADsGroup,CStringArray & arMember,LPOLESTR pwszUser, LPOLESTR pwszPassword)
  499. {
  500.     HRESULT         hr                = S_OK;     // COM Result Code
  501.     IADsMembers  *  pADsMembers       = NULL;     // Ptr to Members of the IADsGroup
  502.     BOOL            fContinue         = TRUE;     // Looping Variable
  503.     IEnumVARIANT *  pEnumVariant      = NULL;     // Ptr to the Enum variant
  504.     IUnknown     *  pUnknown          = NULL;     // IUnknown for getting the ENUM initially
  505.     VARIANT         VariantArray[FETCH_NUM];      // Variant array for temp holding retuned data
  506.     ULONG           ulElementsFetched = NULL;     // Number of elements fetched
  507.     BSTR            bsGroupPath       = NULL;     // Path of the passed group *
  508.     BOOL            bRet              = FALSE;    
  509.  
  510.     // Get the path of the object passed in
  511.     hr = pADsGroup->get_ADsPath(&bsGroupPath);
  512.     CheckADHRESULT(hr);
  513.  
  514.     if (!SUCCEEDED(hr))
  515.         return hr;
  516.     
  517.     // Get a interface pointer to the IADsCollection of members
  518.     hr = pADsGroup->Members(&pADsMembers);
  519.     CheckADHRESULT(hr);
  520.  
  521.     if (SUCCEEDED(hr))
  522.     {
  523.         // Ask the IADsCollection of members for a new ENUM Interface
  524.         // Note the enum comes back as an IUnknown *
  525.         hr = pADsMembers->get__NewEnum(&pUnknown);
  526.         CheckADHRESULT(hr);
  527.  
  528.         if (SUCCEEDED(hr))
  529.         {
  530.             // QI the IUnknown * for a IEnumVARIANT interface
  531.             hr = pUnknown->QueryInterface(IID_IEnumVARIANT, (void **)&pEnumVariant);
  532.             CheckADHRESULT(hr);
  533.  
  534.             if (SUCCEEDED(hr))
  535.             {
  536.                 // While have not hit errors or end of data....
  537.                 while (fContinue) 
  538.                 {
  539.                     ulElementsFetched = 0;
  540.                     // Get a "batch" number of group members- number of rows specified by FETCH_NUM
  541.                     hr = ADsEnumerateNext(pEnumVariant, FETCH_NUM, VariantArray, &ulElementsFetched);
  542.  
  543.                     if (ulElementsFetched )
  544.                     {
  545.                         // Loop through the current batch- Saving the path for each member
  546.                         for (ULONG i = 0; i < ulElementsFetched; i++ ) 
  547.                         {
  548.                             IDispatch * pDispatch         = NULL; // ptr for holding dispath of element
  549.                             BSTR        bstrCurrentPath   = NULL; // Holds path of object
  550.                             BSTR        bstrGuidCurrent   = NULL; // Holds path of object
  551.                             IDirectoryObject * pIDOCurrent = NULL;// Holds the current object          
  552.  
  553.                             // Get the dispatch ptr for the variant
  554.                             pDispatch = VariantArray[i].pdispVal;
  555.                             assert(HAS_BIT_STYLE(VariantArray[i].vt,VT_DISPATCH));
  556.  
  557.                             // Get the IADs interface for the "member" of this group
  558.                             hr = pDispatch->QueryInterface(IID_IDirectoryObject,
  559.                                                            (VOID **) &pIDOCurrent ) ;
  560.                             CheckADHRESULT(hr);
  561.  
  562.                             if (SUCCEEDED(hr))
  563.                             {
  564.                                 IADs * pIADsCurrent = NULL;
  565.  
  566.                                 // Retrieve the IADs Interface for the current object
  567.                                 hr = pIDOCurrent->QueryInterface(IID_IADs,(void**)&pIADsCurrent);
  568.                                 CheckADHRESULT(hr);
  569.                                 if (FAILED(hr))
  570.                                     break;
  571.  
  572.                                 if (SUCCEEDED(hr))
  573.                                 {
  574.                                     // Get the ADsPath property for this member
  575.                                     hr = pIADsCurrent->get_ADsPath(&bstrCurrentPath);
  576.                                     CheckADHRESULT(hr);
  577.  
  578.                                     if (pIADsCurrent)
  579.                                     {
  580.                                         pIADsCurrent->Release();
  581.                                         pIADsCurrent= NULL;
  582.                                     }
  583.                                 }
  584.  
  585.                                 if (SUCCEEDED(hr))
  586.                                 {
  587.                                     // Add the group to the array
  588.                                     arMember.Add(bsGroupPath);
  589.  
  590.                                     // bind to this and see if it is a group
  591.                                     // If is it a group then the QI to IADsGroup will succeed
  592.                                     IADsGroup * pIADsGroupAsMember = NULL;
  593.  
  594.                                     if (pwszUser)
  595.                                         hr = ADsOpenObject( bstrCurrentPath,
  596.                                                             pwszUser, 
  597.                                                             pwszPassword, 
  598.                                                             ADS_SECURE_AUTHENTICATION,
  599.                                                             IID_IADsGroup, 
  600.                                                             (void**) &pIADsGroupAsMember);
  601.                                     else
  602.                                         hr = ADsGetObject( bstrCurrentPath, IID_IADsGroup,(void **)&pIADsGroupAsMember);
  603.  
  604.                                     // If we DID bind, then this IS a group
  605.                                     if (SUCCEEDED(hr))
  606.                                     {
  607.                                         // Recursively call ourselves to load the members from THIS group
  608.                                         hr = RecursiveRetrieveAllMembers(pIADsGroupAsMember,arMember,pwszUser ,pwszPassword );
  609.                                         if (FAILED(hr))
  610.                                         break;
  611.  
  612.                                         pIADsGroupAsMember->Release();
  613.                                         pIADsGroupAsMember = NULL;
  614.                                     }
  615.                                 }
  616.                                 SysFreeString(bstrCurrentPath);
  617.                                 bstrCurrentPath = NULL;
  618.  
  619.                                 SysFreeString(bstrGuidCurrent);
  620.                                 bstrGuidCurrent = NULL;
  621.                             }
  622.                             // Release
  623.                             pIDOCurrent->Release();
  624.                             pIDOCurrent = NULL;
  625.                         } // For loop
  626.                     }
  627.                     else
  628.                         fContinue = FALSE;
  629.                     // Clear the variant array
  630.                     memset(VariantArray, 0, sizeof(VARIANT)*FETCH_NUM);
  631.                 } // while
  632.                 pEnumVariant->Release();
  633.                 pEnumVariant = NULL;
  634.             }
  635.             pUnknown->Release();
  636.             pUnknown = NULL;
  637.         }
  638.         pADsMembers ->Release();
  639.         pADsMembers  = NULL;
  640.     }
  641.  
  642.     // Free the group path if it was retrieved.
  643.     if (bsGroupPath)
  644.     {
  645.         SysFreeString(bsGroupPath);
  646.         bsGroupPath = NULL;
  647.     }
  648.     return hr;
  649. }
  650.  
  651.  
  652. ////////////////////////////////////////////////////////////////////////////////////////////////////
  653. /*
  654.     wmain()- UNICODE version of main()
  655.  
  656. */
  657. void wmain( int argc, wchar_t *argv[ ])
  658. {
  659.     // initialize MFC and print and error on failure
  660.     if (!AfxWinInit(::GetModuleHandle(NULL), NULL, ::GetCommandLine(), 0))
  661.         return;
  662.     CStringArray  arMemberOf;
  663.     HRESULT hr;
  664.     IADsGroup * pIADsG = NULL;
  665.  
  666.     // Initialize COM
  667.     CoInitialize(0);
  668.     if (!ParseCommandLine(argc,argv))
  669.         return;
  670.  
  671.     // Bind to the container passed 
  672.     // If USER and PASS passed in, use ADsOpenObject()
  673.     if (gbsUSER)
  674.         hr = ADsOpenObject( gbsGroup,
  675.                             gbsUSER, 
  676.                             gbsPASS, 
  677.                             ADS_SECURE_AUTHENTICATION,
  678.                             IID_IADsGroup, 
  679.                             (void**) &pIADsG);
  680.     else
  681.         hr = ADsGetObject( gbsGroup, IID_IADsGroup,(void **)&pIADsG);
  682.  
  683.     CheckADHRESULT(hr);
  684.  
  685.     if (SUCCEEDED(hr))
  686.     {
  687.         VARIANT_BOOL bMember = FALSE;  
  688.         
  689.         // Ask the bound to group if it contains the passed member
  690.         hr = pIADsG->IsMember(gbsMember,&bMember);
  691.  
  692.         if (SUCCEEDED(hr))
  693.         {
  694.             /* 0 == FALSE, -1 == TRUE */
  695.             // If it is a member and Recusion is NOT specified
  696.             if (bMember == -1 && !gbRecurse)
  697.             {
  698.                 wprintf(L"Object \n\n%s\n\n IS a member of the following Group:\n\n%s\n\n",gbsMember,gbsGroup);
  699.             }
  700.             else if (gbRecurse) // If Recursion is Specified
  701.             {
  702.                 BSTR bsMemberGUID = NULL;
  703.                 IDirectoryObject * pDOMember = NULL;
  704.  
  705.                 // Need to get the member's GUID- so we bind with IDirectoryObject
  706.  
  707.                 // Bind to the Member passed 
  708.                 // If USER and PASS passed in, use ADsOpenObject()
  709.                 if (gbsUSER)
  710.                     hr = ADsOpenObject( gbsMember,
  711.                                         gbsUSER, 
  712.                                         gbsPASS, 
  713.                                         ADS_SECURE_AUTHENTICATION,
  714.                                         IID_IDirectoryObject, 
  715.                                         (void**) &pDOMember);
  716.                 else
  717.                     hr = ADsGetObject( gbsMember, IID_IDirectoryObject,(void **)&pDOMember );
  718.  
  719.                 CheckADHRESULT(hr);
  720.  
  721.                 if (SUCCEEDED(hr))
  722.                 {
  723.                     hr = GetObjectGuid(pDOMember,bsMemberGUID);
  724.                     pDOMember->Release();
  725.                     pDOMember  = NULL;
  726.                 }
  727.                 else
  728.                 {
  729.                     wprintf(L"ERROR!!!!: Cannot bind to member:\n\n%s\n\n",gbsMember);
  730.                     return ;
  731.                 }
  732.  
  733.                 RecursiveRetrieveAllMembers(pIADsG,arMemberOf,gbsUSER ,gbsPASS );
  734.  
  735.                 int iSize = arMemberOf.GetSize();
  736.                 if (iSize)
  737.                 {
  738.                     // Display the output:
  739.                     wprintf(L"\nObject \n\n%s\n\n Contains the following members:\n",gbsGroup);
  740.                     puts("------------------------------------------------");
  741.                     for (int x = 0; x <iSize; x++)
  742.                     {
  743.                         CString s = arMemberOf.GetAt(x);
  744.                         _putws(s);
  745.                     }
  746.                 }
  747.  
  748.                 if (bsMemberGUID)
  749.                 {
  750.                     SysFreeString(bsMemberGUID);
  751.                     bsMemberGUID = NULL;
  752.                 }
  753.             }
  754.             else // NOT a member and NO recursion specified
  755.                 wprintf(L"Object \n\n%s\n\n IS NOT a member of the Group:\n\n%s\n\n",gbsMember,gbsGroup);
  756.         }
  757.         pIADsG->Release();
  758.         pIADsG = NULL;
  759.     }
  760.     else
  761.         CheckADHRESULT(hr);
  762.  
  763.     if (gbsGroup)
  764.     {
  765.         SysFreeString(gbsGroup);
  766.         gbsGroup = NULL;
  767.     }
  768.     if (gbsMember)
  769.     {
  770.         gbsUSER = NULL;
  771.         SysFreeString(gbsUSER);
  772.     }
  773.     if (gbsUSER)
  774.     {
  775.         SysFreeString(gbsPASS);
  776.         gbsPASS = NULL;
  777.     }
  778.     
  779.     CoUninitialize();
  780. }
  781.  
  782.  
  783.  
  784.  
  785. ////////////////////////////////////////////////////////////////////////////////////////////////////
  786. /*  CheckGroupObjectMembersForMembership()    - Prints the Recirsively scans the members of passed IADsGroup ptr
  787.                                                 and any groups belonging to the passed ptr- for membership
  788.                                                 of Passed group
  789.                                                 Will return a CStringArray of all groups which member belongs to
  790.     Parameters
  791.  
  792.         IADsGroup *     pADsGroup       - Group from which to list members
  793.         LPWSTR          pwszMember      - LDAP path for object to check membership
  794.         CStringArray &  arMemberOf      - Returned array of Groups passed member belongs to
  795.         BOOL            bVerbose        - IF TRUE- will ouput verbose information on the scanning
  796.     
  797.     OPTIONAL Parameters
  798.  
  799.        LPOLESTR  pwszUser           - User Name and Password, if the parameters are NOT passed, 
  800.        LPOLESTER pwszPassword       - Binding will use ADsGetObject, if the parameters
  801.                                     - Are specified, will use ADsOpenObject, passing user name and password
  802. */
  803.  
  804. #define FETCH_NUM 100 // number of elements to fetch at a time for CheckGroupObjectMembersForMembership()
  805.  
  806. HRESULT CheckGroupObjectMembersForMembership(IADsGroup * pADsGroup,LPWSTR pwszMemberGUID,LPWSTR pwszMemberPath, CStringArray & arMemberOf,
  807.                                              BOOL bVerbose, LPOLESTR  pwszUser, LPOLESTR pwszPassword)
  808. {
  809.     HRESULT         hr                = S_OK;     // COM Result Code
  810.     IADsMembers *   pADsMembers       = NULL;     // Ptr to Members of the IADsGroup
  811.     BOOL            fContinue         = TRUE;     // Looping Variable
  812.     IEnumVARIANT *  pEnumVariant      = NULL;     // Ptr to the Enum variant
  813.     IUnknown *      pUnknown          = NULL;     // IUnknown for getting the ENUM initially
  814.     VARIANT         VariantArray[FETCH_NUM];      // Variant array for temp holding retuned data
  815.     ULONG           ulElementsFetched = NULL;     // Number of elements fetched
  816.     BSTR            bsGroupPath       = NULL;
  817.     
  818.     // Get the path of the object passed in
  819.     hr = pADsGroup->get_ADsPath(&bsGroupPath);
  820.     CheckADHRESULT(hr);
  821.  
  822.     if (!SUCCEEDED(hr))
  823.         return hr;
  824.  
  825.     if (bVerbose)
  826.     {
  827.         WCHAR pwszOutput[2048];
  828.         wsprintf(pwszOutput,L"Checking the Group:\n\n%s\n\n for the member:\n\n%s\n\n",bsGroupPath,pwszMemberPath);
  829.         PrintBanner(pwszOutput);
  830.     }
  831.     
  832.     // Get a interface pointer to the IADsCollection of members
  833.     hr = pADsGroup->Members(&pADsMembers);
  834.     CheckADHRESULT(hr);
  835.  
  836.     if (SUCCEEDED(hr))
  837.     {
  838.         // Ask the IADsCollection of members for a new ENUM Interface
  839.         // Note the enum comes back as an IUnknown *
  840.         hr = pADsMembers->get__NewEnum(&pUnknown);
  841.         CheckADHRESULT(hr);
  842.  
  843.         if (SUCCEEDED(hr))
  844.         {
  845.             // QI the IUnknown * for a IEnumVARIANT interface
  846.             hr = pUnknown->QueryInterface(IID_IEnumVARIANT, (void **)&pEnumVariant);
  847.             CheckADHRESULT(hr);
  848.  
  849.             if (SUCCEEDED(hr))
  850.             {
  851.                 // While have not hit errors or end of data....
  852.                 while (fContinue) 
  853.                 {
  854.                    ulElementsFetched = 0;
  855.                     // Get a "batch" number of group members- number of rows specified by FETCH_NUM
  856.                     hr = ADsEnumerateNext(pEnumVariant, FETCH_NUM, VariantArray, &ulElementsFetched);
  857.  
  858.                     if (ulElementsFetched )
  859.                     {
  860.                         // Loop through the current batch- printing the path 
  861.                         // for each member
  862.                         for (ULONG i = 0; i < ulElementsFetched; i++ ) 
  863.                         {
  864.                             IDispatch * pDispatch         = NULL; // ptr for holding dispath of element
  865.                             //IADs      * pIADsGroupMember  = NULL; // IADs ptr to group member
  866.                             BSTR        bstrCurrentPath          = NULL; // Holds path of object
  867.                            BSTR        bstrGuidCurrent          = NULL; // Holds path of object
  868.                            IDirectoryObject * pIDOCurrent = NULL;
  869.  
  870.                             // Get the dispatch ptr for the variant
  871.                             pDispatch = VariantArray[i].pdispVal;
  872.                             assert(HAS_BIT_STYLE(VariantArray[i].vt,VT_DISPATCH));
  873.  
  874.                             // Get the IADs interface for the "member" of this group
  875.                             hr = pDispatch->QueryInterface(IID_IDirectoryObject,
  876.                                                            (VOID **) &pIDOCurrent ) ;
  877.                             CheckADHRESULT(hr);
  878.  
  879.                             if (SUCCEEDED(hr))
  880.                             {
  881.                                 // Get the ADsPath property for this member
  882.                                 //hr = pIADsGroupMember->get_ADsPath(&bstrPath) ;
  883.  
  884.                                 hr = GetObjectGuid(pIDOCurrent,bstrGuidCurrent);
  885.  
  886.                                // hr = pIADsGroupMember->get_GUID(&bstrPath);//get_ADsPath() ;
  887.                                 CheckADHRESULT(hr);
  888.  
  889.                                 if (FAILED(hr))
  890.                                     return hr;
  891.  
  892.                                 IADs * pIADsCurrent = NULL;
  893.  
  894.                                 hr = pIDOCurrent->QueryInterface(IID_IADs,(void**)&pIADsCurrent);
  895.  
  896.                                 if (FAILED(hr))
  897.                                     return hr;
  898.  
  899.  
  900.                                 hr = pIADsCurrent->get_ADsPath(&bstrCurrentPath);
  901.  
  902.  
  903.                                 if (SUCCEEDED(hr))
  904.                                 {
  905.                                     if (bVerbose)
  906.                                         wprintf(L"Comparing:\n\n%s\nWITH:\n%s\n\n",bstrGuidCurrent,pwszMemberGUID);
  907.                                     
  908.                                     // Is the "member of this group Equal to passed?
  909.                                     if (_wcsicmp(bstrGuidCurrent,pwszMemberGUID)==0)
  910.                                     {
  911.                                         if (bVerbose)
  912.                                         {
  913.                                             wprintf(L"!!!!!Object:\n\n%s\n\nIs a member of\n\n%s\n\n",pwszMemberPath,bstrGuidCurrent);   
  914.                                         }
  915.                                         // Add the group to the array
  916.                                         arMemberOf.Add(bsGroupPath);
  917.                                     }
  918.                                     else // Otherwise, we should bind to this and see if it is a group
  919.                                     {    // If is it a group then the QI to IADsGroup will succeed
  920.                                         
  921.                                         IADsGroup * pIADsGroupAsMember = NULL;
  922.                                         
  923.                                         if (pwszUser)
  924.                                             hr = ADsOpenObject( bstrCurrentPath,
  925.                                                                 pwszUser, 
  926.                                                                 pwszPassword, 
  927.                                                                 ADS_SECURE_AUTHENTICATION,
  928.                                                                 IID_IADsGroup, 
  929.                                                                 (void**) &pIADsGroupAsMember);
  930.                                         else
  931.                                             hr = ADsGetObject( bstrCurrentPath, IID_IADsGroup,(void **)&pIADsGroupAsMember);
  932.  
  933.                                         // If we DID bind, then this IS a group
  934.                                         if (SUCCEEDED(hr))
  935.                                         {
  936.                                             // Recursively call ourselves to check THIS group
  937.                                             hr = CheckGroupObjectMembersForMembership(pIADsGroupAsMember,pwszMemberGUID,pwszMemberPath,arMemberOf,bVerbose,pwszUser ,pwszPassword );
  938.                                             pIADsGroupAsMember->Release();
  939.                                             pIADsGroupAsMember = NULL;
  940.                                         }
  941.                                     }
  942.                                     SysFreeString(bstrCurrentPath);
  943.                                     bstrCurrentPath = NULL;
  944.  
  945.                                     SysFreeString(bstrGuidCurrent);
  946.                                     bstrGuidCurrent = NULL;
  947.                                 }
  948.                                 pIDOCurrent->Release();
  949.                                 pIDOCurrent = NULL;
  950.                             }
  951.                          }
  952.                         // Clear the variant array
  953.                         memset(VariantArray, 0, sizeof(VARIANT)*FETCH_NUM);
  954.                     }
  955.                     else
  956.                         fContinue = FALSE;
  957.                 }
  958.                 pEnumVariant->Release();
  959.                 pEnumVariant = NULL;
  960.             }
  961.             pUnknown->Release();
  962.             pUnknown = NULL;
  963.         }
  964.         pADsMembers ->Release();
  965.         pADsMembers  = NULL;
  966.     }
  967.  
  968.     // Free the group path if it was retrieved.
  969.     if (bsGroupPath)
  970.     {
  971.         SysFreeString(bsGroupPath);
  972.         bsGroupPath = NULL;
  973.     }
  974.     // If everything WENT ok ->we printed all the 
  975.     // data and receieved an S_FALSE (indiciating no more data)
  976.     // if that is the case we REALLY want to return a S_OK
  977.     if (hr == S_FALSE)
  978.         hr = S_OK;
  979.     return hr;
  980. }
  981.  
  982. ////////////////////////////////////////////////////////////////////////////////////////////////////
  983. /*  GetObjectGuid()    - Retrieves the GUID in String form from the passed Directory Object
  984.                          Returns S_OK on success   
  985.     
  986.     Parameters
  987.  
  988.         IDirectoryObject *  pDO     -   Directory Object from where GUID will be retrieved.
  989.         BSTR             &  bsGuid  -   Returned GUID            
  990. */
  991.  
  992. HRESULT GetObjectGuid(IDirectoryObject * pDO,BSTR &bsGuid)
  993. {
  994.  
  995.     GUID *pObjectGUID   = NULL;
  996.     PADS_ATTR_INFO      pAttributeEntries;
  997.     LPWSTR              pAttributeName = L"objectGUID";  //Get the GUID for the object
  998.     DWORD               dwAttributesReturned = 0;
  999.     HRESULT             hr;
  1000.     hr = pDO->GetObjectAttributes(  &pAttributeName, //objectGUID
  1001.                                     1, //Only objectGUID
  1002.                                     &pAttributeEntries, // Returned attributes
  1003.                                     &dwAttributesReturned //Number of attributes returned
  1004.                                     );
  1005.     
  1006.     if (SUCCEEDED(hr) && dwAttributesReturned>0)
  1007.     {
  1008.         //Make sure that we got the right type--objectGUID is ADSTYPE_OCTET_STRING
  1009.         if (pAttributeEntries->dwADsType == ADSTYPE_OCTET_STRING)
  1010.         {
  1011.             //Get COM converted string version of the GUID
  1012.             //lpvalue should be LPBYTE. Should be able to cast it to ptr to GUID.
  1013.             pObjectGUID = (GUID*)(pAttributeEntries->pADsValues[0].OctetString.lpValue);
  1014.             
  1015.             //OLE str to fit a GUID
  1016.             
  1017.             LPOLESTR szGUID = new WCHAR [64];
  1018.             szGUID[0]=NULL;
  1019.             //Convert GUID to string.
  1020.             ::StringFromGUID2(*pObjectGUID, szGUID, 39); 
  1021.             bsGuid = SysAllocString(szGUID);
  1022.             
  1023.             delete [] szGUID;
  1024.          }
  1025.     }
  1026.  
  1027.     return hr;
  1028.  
  1029. }
  1030.  
  1031. ////////////////////////////////////////////////////////////////////////////////////////////////////
  1032. /*  
  1033.     PrintIADSObject()       -   Calls all the methods on a IADs object 
  1034.                                 and prints them the console window
  1035.     Parameters
  1036.     
  1037.         IADs * pIADs        - IADs Interface from which to retrieve attribute values
  1038. */
  1039. void PrintIADSObject(IADs * pIADs)
  1040. {
  1041.     assert(pIADs);
  1042.  
  1043.     BSTR bsResult;
  1044.  
  1045.     pIADs->get_Name(&bsResult); 
  1046.     wprintf(L" NAME: %s\n",(LPOLESTR) bsResult);
  1047.     SysFreeString(bsResult);
  1048.     
  1049.     pIADs->get_Class(&bsResult); 
  1050.     wprintf(L" CLASS: %s\n",(LPOLESTR) bsResult);
  1051.     SysFreeString(bsResult);
  1052.     
  1053.     pIADs->get_GUID(&bsResult); 
  1054.     wprintf(L" GUID: %s\n",(LPOLESTR) bsResult);
  1055.     SysFreeString(bsResult);
  1056.     
  1057.     pIADs->get_ADsPath(&bsResult); 
  1058.     wprintf(L" ADSPATH: %s\n",(LPOLESTR) bsResult);
  1059.     SysFreeString(bsResult);
  1060.     
  1061.     pIADs->get_Parent(&bsResult); 
  1062.     wprintf(L" PARENT: %s\n",(LPOLESTR) bsResult);
  1063.     SysFreeString(bsResult);
  1064.     
  1065.     pIADs->get_Schema(&bsResult); 
  1066.     wprintf(L" SCHEMA: %s\n",(LPOLESTR) bsResult);
  1067.     SysFreeString(bsResult);
  1068.     
  1069. }
  1070.  
  1071.  
  1072. ////////////////////////////////////////////////////////////////////////////////////////////////////
  1073. /*  PrintBanner()   -       Prints a banner on the screen
  1074.  
  1075.     Parameters
  1076.  
  1077.                 LPOLESTR pwszBanner   - String to print
  1078. */
  1079. void PrintBanner(LPOLESTR pwszBanner)
  1080. {
  1081.     _putws(L"");
  1082.     _putws(L"////////////////////////////////////////////////////");
  1083.     wprintf(L"\t");
  1084.     _putws(pwszBanner);
  1085.     _putws(L"////////////////////////////////////////////////////\n");
  1086. }
  1087. ////////////////////////////////////////////////////////////////////////////////////////////////////
  1088. /*
  1089.     ParseCommandLine()- Parses command line and sets module level globals
  1090.     
  1091.     Parameters:
  1092.  
  1093.         int argc            - Number of Arguments
  1094.         wchar_t *argv[ ]    - Array of arguments
  1095.  
  1096.     Returns:
  1097.         TRUE if Command line was successfully parsed
  1098.  
  1099.     Affectets global variables:
  1100.  
  1101.         BSTR bsGroup    
  1102.         BSTR bsMember    
  1103.         BSTR bsUSER
  1104.         BSTR bsPASS    
  1105.         BOOL gbRecurse    
  1106.         BOOL gbVerbose    
  1107.  
  1108. */    
  1109. BOOL ParseCommandLine( int argc, wchar_t *argv[ ])
  1110. {
  1111. /*
  1112.      ** PARSE the FOLLOWING ARGUMENTS:
  1113.    
  1114.         BSTR bsGroup     = NULL; // <Group to check> This is the LDAP path for the group to check
  1115.  
  1116.         BSTR bsMember    = NULL; // <Member to check> ath in the SCHEMA of the object
  1117.     
  1118.         BSTR bsUSER      = NULL; // <User name used for binding to the DC>
  1119.                                 // If this is NON-NULL, then binding with occurr with AdsOpenObject()
  1120.                                 // Otherwise will use ADsGetObject()    
  1121.  
  1122.         BSTR bsPASS      = NULL; // <Password used for binding to the DC>
  1123.  
  1124.         BOOL gbRecurse    = FALSE; // If TRUE, will recurse any contained groups looking for the member 
  1125.  
  1126.         BOOL gbVerbose    = FALSE; // If true- will spit out info as it is finding it
  1127.  
  1128. */        
  1129.     if (argc == 1)
  1130.     {
  1131.         _putws(pwszUsage);
  1132.         return FALSE;
  1133.     }
  1134.     for (int x= 1; x < argc; x++)
  1135.     {
  1136.         if (_wcsicmp(argv[x],L"/GROUP")==0)
  1137.         {
  1138.             if (argc == x) // Make sure the parameter was passed
  1139.             {
  1140.                 wprintf(L"\nERROR: %s Missing parameter!!!!\n\n",argv[x]);
  1141.                 _putws(pwszUsage);
  1142.                 return FALSE;
  1143.             }
  1144.             // Go to the next argument and save it in module level variable
  1145.             x++;
  1146.             gbsGroup= SysAllocString(argv[x]);                
  1147.         
  1148.         } 
  1149.         else if (_wcsicmp(argv[x],L"/MEMBER")==0)
  1150.         {
  1151.             if (argc == x) // Make sure the parameter was passed
  1152.             {
  1153.                 wprintf(L"\nERROR: %s Missing parameter!!!!\n\n",argv[x]);
  1154.                 _putws(pwszUsage);
  1155.                 return FALSE;
  1156.             }
  1157.             // Go to the next argument and save it in module level variable
  1158.             x++;
  1159.             gbsMember= SysAllocString(argv[x]);                
  1160.         
  1161.         } 
  1162.         else if (_wcsicmp(argv[x],L"/USER")==0)
  1163.         {
  1164.             if (argc == x) // Make sure the parameter was passed
  1165.             {
  1166.                 wprintf(L"\nERROR: %s Missing parameter!!!!\n\n",argv[x]);
  1167.                 _putws(pwszUsage);
  1168.                 return FALSE;
  1169.             }
  1170.             // Go to the next argument and save it in module level variable
  1171.             x++;
  1172.             gbsUSER = SysAllocString(argv[x]);                
  1173.         }
  1174.         else if (_wcsicmp(argv[x],L"/PASS")==0)
  1175.         {
  1176.             if (argc == x) // Make sure the parameter was passed
  1177.             {
  1178.                 wprintf(L"\nERROR: %s Missing parameter!!!!\n\n",argv[x]);
  1179.                 _putws(pwszUsage);
  1180.                 return FALSE;
  1181.             }
  1182.             // Go to the next argument and save it in module level variable
  1183.             x++;
  1184.             gbsPASS = SysAllocString(argv[x]);                
  1185.         }
  1186.         else if (_wcsicmp(argv[x],L"/RECURSE")==0)
  1187.         {
  1188.             gbRecurse  = TRUE;
  1189.         } 
  1190.         else if (_wcsicmp(argv[x],L"/VERBOSE")==0)
  1191.         {
  1192.             gbVerbose = TRUE;
  1193.         } 
  1194.         else
  1195.         {
  1196.                 wprintf(L"\nERROR: %s UNknown Argument\n\n",argv[x]);
  1197.                 _putws(pwszUsage);
  1198.                 return FALSE;
  1199.         }
  1200.     }
  1201.     if (!gbsGroup)
  1202.     {
  1203.         _putws(L"\nERROR: /GROUP is required!");
  1204.         return FALSE;
  1205.     }                    
  1206.     if (!gbsMember)
  1207.     {
  1208.         _putws(L"\nERROR: /MEMBER is required!");
  1209.         return FALSE;
  1210.     }                    
  1211.     // Check if User is poassed, then password is required:
  1212.     if (gbsUSER || gbsPASS)
  1213.         if (!gbsUSER || !gbsPASS) // if either one is missing complain
  1214.         {
  1215.             _putws(L"\nERROR: If /USER is specified /PASS is required!");
  1216.             return FALSE;
  1217.         }                    
  1218.       
  1219.     return TRUE;
  1220. }
  1221.  
  1222.  
  1223.