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;
}
Comments
Anonymous
September 27, 2010
What caused this error? error LNK2001: unresolved external symbol _IID_IGPMAnonymous
April 27, 2011
Try after including 'gpmuuid.lib' libraryAnonymous
May 02, 2013
hi code is running well on windows server but when i run it on my xp machine then in following step i got error Class not Register hr = CoCreateInstance(CLSID_GPM, NULL, CLSCTX_INPROC_SERVER, IID_IGPM , (LPVOID*)&pGPM); even i register dll gpmgmt.dll on this machine please tell me how can i run this from aremote xp machine