Working with Group Policy Objects Programmatically – Locating a GPO using the GPMC ( Group Policy Management Console ) object model in C++

In my previous post we discussed how to modify a registry based GPO programmatically. In this post we will focus on using the GPMC ( Group Policy Management Console ) object model to find a GPO that contains a specific string in the display name.

The steps for using the GPMC to locate GPOs from C++ are straight forward:

1. Create an IGPM interface to initialize the GPMC dlls. (msdn.microsoft.com/en-us/library/aa814148(VS.85).aspx )

2. Use IGPM::GetDomain to initialize a SOM (Scope of Management) object to manage GPOs from a specific domain. (msdn.microsoft.com/en-us/library/aa814309(VS.85).aspx). This returns an IGPMDomain object (msdn.microsoft.com/en-us/library/aa814189(VS.85).aspx ).

3. Initialize a variant with the portion of the string you wish to match in the Display Name attribute of the GroupPolicyContainer object in the Active Directory.

4. Retrieve a GPMC Constants object from the IGPM interface by calling IGPM::GetConstants(). This method returns an IGPMConstants object (msdn.microsoft.com/en-us/library/aa814177(VS.85).aspx  ) Using the GPMC constants object to retrieve GPMC constants will make the code much easier to read.

5. Create a Search Criteria object using the IGPMC::CreateSearchCriteria() method. This method returns an IGPMSearchCriteria object (msdn.microsoft.com/en-us/library/aa814259(VS.85).aspx ).

6. Using the IGPMConstants::get_SearchPropertyGPODisplayName() object, create a GPMSearchProperty object. This object will contain information that identifies the attribute you are searching for.

7. Using the IGPMConstants::get_SearchOpContains () method to retrieve a GPMSearchOperation object initialized to a wild card contains search.

8. Add the search property object ( GPMSearchProperty created in step 6) along with the search operation object ( GPMSearchOperation created in step 7) to the search criteria object ( created in step 5 ) with the variant ( initialized in step 3 ) using the IGPMSearchCriteria::Add method (msdn.microsoft.com/en-us/library/aa814260(VS.85).aspx )

9. Execute the search using the SOM domain object created in step 2 by calling the IGPMDomain::SearchForGPOs( ) method passing in the IGPMSearchCriteria object initialized in step 8. You will be given a IGPMGPOCollection object (msdn.microsoft.com/en-us/library/aa814200(VS.85).aspx ) containing the results of the search. The collection object will contain a set of IGPMGPO objects returned as variants containing IDispatch interfaces.

Let’s take a look at each step in a C++ code block.

        //

        // Locate a GPO with contains match and modify it

        //

        {

    //

    IGPM *pGPM = NULL; // Initial GPMC interface.

                                 // Used to retrieve other GPO objects.

    IGPMDomain *pDom = NULL; // Returned by pGPM, limits items

                                    // to a specific domain.

    IGPMGPO *pGPO = NULL; // The GPMC interface that

                                     // represents a single GPO

    IGPMConstants *pGPMConstants = NULL; // Used to help retrieve

   // GPMC constants easily

    IGPMSearchCriteria *pIGPMSearch = NULL; // Defines a search

                                                    // criteria to locate

                                                    // GPOs.

    IGPMGPOCollection *pGPOCollection = NULL; // used to search for

                                                      // a GPO, this will

                                                      // contain the results

                                                      // of the search.

    //

            // To use _bstr_t classes must use the comutil library and

            // and header files

            //

            _bstr_t bErrorStr("");

            //

            // Retrieve FQDN

            //

            wchar_t strFQDN[255], strDispName[255];

            fflush( stdin );

            printf("Enter the FQDN of the domain to create the GPO in: ");

            _getws( strFQDN );

            fflush(stdin);

            //

            // Retrieve Display Name

            //

            printf("Enter Display name for GPO to Match: ");

            _getws( strDispName );

            fflush(stdin);

            //

            // Step 1: Create and initialize the GPMC objects.

            // Use the GPMC to create SOM and locate GPO

            // To use this interface the GPMC components must be present

            // on the client.

            //

            _bstr_t bstrFQDN(strFQDN);

            hr = CoCreateInstance(CLSID_GPM, NULL,

                                  CLSCTX_INPROC_SERVER,

                                  IID_IGPM , (LPVOID*)&pGPM);

            //

            // Step 2: Retreive the SOM ( Scope of Management object )

            // Retrieve a SOM object associated with the target domain

            //

            hr = pGPM->GetDomain( (BSTR)bstrFQDN, NULL, 0, &pDom);

            //

            // Step 3: initialize the search string into a variant.

            //

            _variant_t vData( strDispName );

            //

            // Step 4:

            // Retreive the GPMC constants object.

            //

            hr = pGPM->GetConstants( &pGPMConstants );

            if( FAILED(hr) )

            {

       bErrorStr = L"Failed to retrieve IGPMConstants";

                goto CLEANUP_CONTAINS2;

            }

            //

            // Step 5:

            // Retrieve the search criteria object.

            //

            hr = pGPM->CreateSearchCriteria( &pIGPMSearch);

            if( FAILED(hr) )

            {

                bErrorStr = L"Failed to create IGPMSearchCirteria";

                goto CLEANUP_CONTAINS2;

            }

            //

            // Step 6 & 7: Setup the search property and the

            // search operation constants.

  //

            GPMSearchProperty sp;

  GPMSearchOperation so;

            //

            // Contains Match for display name.

            //

            pGPMConstants->get_SearchPropertyGPODisplayName( &sp);

            pGPMConstants->get_SearchOpContains( &so);

            //

            // Step 8:

            // Add the search operation and property

            // to the search criteria object.

            //

            pIGPMSearch->Add( sp, so, vData );

            long lCount = 0;

            //

            // Step 9:

            // Perform the search and retrieve the GOP collection.

            //

            hr = pDom->SearchGPOs( pIGPMSearch, &pGPOCollection);

            if( FAILED(hr) )

            {

                bErrorStr = L"IGPMDomain::SearchGPOs failed";

                vData.Clear();

                goto CLEANUP_CONTAINS2;

            }

            //

            // the following is an example of how to work

            // with the GPO collection returned from the search.

            // If we matched at least one item, lets use a helper

            // function to retrieve the index of the GPO object

            // from the collection.

            //

            pGPOCollection->get_Count( &lCount);

            printf("Found %d GPOs that matched the display name criteria \"%S\"\n",

                  lCount, strDispName);

            if( lCount > 0 )

            {

                long lIndex = 0;

                //

                // Get a selected GPO to delete

      // if the count is 1, then we have only 1 item,

                // if the count is > 1, then we need to

                // ask the user to select one to modify.

                //

                if( lCount == 1 ) lIndex = 1;

                else lIndex = RequestGPOIndex( pGPOCollection );

                if( lIndex > 0 )

                {

                    //

                    // Retrieve the mode and settings

                    //

                    int iMode = RequestMode();

            DWORD lData = RequestSetting();

                    //

                    // Clear the variant to request an IDispatch

                    // pointer to the IGPMGPO interface that

                    // represents the GPO.

                    //

                    vData.Clear();

                    hr = pGPOCollection->get_Item( lIndex, &vData);

                    if( FAILED(hr) )

                    {

                        bErrorStr = L"Failed to retrieve IGPMGPO interface form collection";

  goto CLEANUP_CONTAINS2;

                    }

                    //

                    // QI for the GPO interface

                    //

                    hr = vData.pdispVal->QueryInterface( IID_IGPMGPO,

                                                         (void **)&pGPO);

      if( FAILED(hr) )

                    {

                        bErrorStr = L"Failed to retreive GPO pointer from vData.pdispVal->QueryInterface";

                        vData.Clear();

                        goto CLEANUP_CONTAINS2;

                    }

                    //

                    // Get the path to the GPO and then call the

                    // modify function.

                    //

                    BSTR bPath;

                    pGPO->get_Path( &bPath);

                    _bstr_t bADsPath("LDAP://");

                    bADsPath = bADsPath + strFQDN;

                    bADsPath = bADsPath + "/";

                    bADsPath = bADsPath + bPath;

                    SysFreeString( bPath );

                    hr = ModifyUserPolicyForPreventAccessToCmdPrompt(

                                        bADsPath, iMode, lData);

                    if( SUCCEEDED(hr) ) bErrorStr = L"Successfully modified GPO";

                    else bErrorStr = L"Unable to modify GPO";

               }

CLEANUP_CONTAINS2:

                vData.Clear();

                if( pGPO ) pGPO->Release();

                if( pGPOCollection) pGPOCollection->Release();

                if ( pIGPMSearch ) pIGPMSearch->Release();

                if( pGPMConstants ) pGPMConstants->Release();

                if( pGPM ) pGPM->Release();

                if( pDom ) pDom->Release();

                LPTSTR pstr = bErrorStr;

                printf("%S\nLast HRESULT: %0X\n", pstr, hr);

                CoUninitialize();

      return hr;

            }

        }

        break;

Below are 3 helper functions:

RequestGPOIndex – example of working with the GPO collection returned from the search.

RequestMode – retrieves the mode setting for the GPO.

RequestSetting – Retreives the data to be written to the registry.

int RequestMode ( )

{

    int retval = -1;

    BOOL bContinue = TRUE;

    fflush(stdin);

    while( (retval < 0 ) || ( retval > 2 ) )

    {

        printf("\nEnter GPO Mode Value:\n 0 - Not Configured\n 1 - Enabled\n 2 - Disabled\nEnter Selection: ");

        fscanf_s(stdin, "%d", &retval);

        if( (retval < 0 ) || ( retval > 2 )) printf("Invalid Mode Values, must be 0, 1, 2\n");

   fflush(stdin);

    }

    return retval;

}

DWORD RequestSetting( )

{

    int retval = -1;

    BOOL bContinue = TRUE;

    fflush(stdin);

    while( (retval < 1 ) || ( retval > 2 ) )

    {

        printf("\nDisable the command prompt script processing also?\n 1 - Yes\n 2 - No\nEnter Selection: ");

        fscanf_s(stdin, "%d", &retval);

        if( (retval < 1 ) || ( retval > 2 )) printf("Invalid Mode Values, must be 1, 2\n");

        fflush(stdin);

    }

    return retval;

}

long RequestGPOIndex( IGPMGPOCollection *pGPOs)

{

    long lSelection = -1;

    long lCount = 0;

    if( pGPOs )

    {

        pGPOs->get_Count( &lCount );

        _variant_t vData;

        IGPMGPO *pGPO;

        while ( (lSelection < 0) || (lSelection > lCount ) )

        {

            long lLoop = 1;

            printf("GPOs in Collection:\n");

            BSTR bID;

            VARIANT_BOOL bUser;

            VARIANT_BOOL bMachine;

            HRESULT hr;

            for( lLoop =1 ;lLoop <= lCount; lLoop++ )

            {

                hr = pGPOs->get_Item( lLoop, &vData );

                hr = vData.pdispVal->QueryInterface(IID_IGPMGPO, (void **)&pGPO);

                pGPO->get_ID( &bID);

                pGPO->IsComputerEnabled( &bMachine );

                pGPO->IsUserEnabled( &bUser);

                printf(" %d -> ID: \"%S\"\n", lLoop, bID );

                printf("\tUser Enabled: ");

                if( bUser == VARIANT_TRUE ) printf(" Yes ");

                else printf(" No ");

                printf(" Machine Enabled: ");

                if( bMachine ) printf(" Yes \n");

                else printf(" No\n");

                SysFreeString( bID );

                pGPO->get_DisplayName( &bID );

                printf("\tDisplay Name: \"%S\"\n", bID);

                SysFreeString( bID );

                pGPO->Release();

                vData.Clear();

            }

            printf(" 0 -> No Selection\n\nEnter a number from 0 to %d: " , lCount);

            fflush(stdin);

        fscanf_s(stdin,"%d",&lSelection);

            if( (lSelection < 0) || (lSelection > lCount) ) printf("\n\007Invalid Entry\n");

        }

        if( lSelection == 0 ) lSelection = -1;

    }

    return lSelection;

}