Working with Group Policy Objects Programmatically - simple C++ example illustrating how to modify a registry based policy
In my last bog post:
I discussed an empirical method to determine the values one needs to write to the registry to enable/disable/set a registry based group policy. In this post, I will provide a simple C++ function that illustrates how to write the key information into the GPO.
For now, lets concentrate on the C++ code for modifying the GPO.
The function requires 3 pieces of information:
- ADsPath to the GPO object to modify
- A mode control values, 0=Not Configured, 1=Enabled, 2=Disabled
- The actual value to write in the key that represents the mode control value.
The source for the function follows. The comments should provide insight into how the code works.
One key point is to realize that if you are modifying an existing GPO that contains multiple settings on a specific registry key tree, you cannot just delete the entire key tree, you must delete just the values that affect the settings you are working with.
Another subtle gotcha is the way you use the IGroupPolicyObject::GetRegistryKey and the IGroupPolicyObject::Save methods. The flag on in GetRegistryKey to indicate the section is an unsigned valued ( GPO_SECTION_ROOT or GPO_SECTION_USER or GPO_SECTION_MACHINE) , the flag to indicate the section on the Save method is a boolean ( TRUE to write the machine configuration, FALSE to write the user configuration). I made the mistake of using the same value in both locations, and thought I was chasing a bug in the IGroupPolicyObject interface.
Finding the path can be a challenge. The next blog post will provide details on how to locate a GPO object in the AD based on specific information using either the GPMC object model or the BrowseForGPO function.
C++ Source Code follows:
HRESULT ModifyUserPolicyForPreventAccessToCmdPrompt( BSTR bGPOPath, int iMode, DWORD lData)
{
HRESULT hr=S_OK;
//
// Use IGroupPolicyObject to retrieve and modify the registry settings.
// for the GPO represented by the gpoInfo.lpDsPath
//
IGroupPolicyObject* p = NULL;
hr = CoCreateInstance(CLSID_GroupPolicyObject, NULL,
CLSCTX_INPROC_SERVER, IID_IGroupPolicyObject,
(LPVOID*)&p);
if (SUCCEEDED(hr))
{
//
// The GPO value we want to modify is the
//
// User Configuration
// +> Policies
// +>Administrative Templates
// +->System
// +->Prevent access to the command prompt
//
DWORD dwSection = GPO_SECTION_USER;
HKEY hGPOSectionKey = NULL;
DWORD dwData;
HKEY hSettingKey;
LSTATUS rStatus;
hr = 0;
//
//Open the GPO and load its registy values for both: Machine and user
//
hr = p->OpenDSGPO( bGPOPath, GPO_OPEN_LOAD_REGISTRY);
//
// Request the user Registy hive for the GPO
//
hr = p->GetRegistryKey(dwSection, &hGPOSectionKey);
//
// Determine if you want to set it to Not Congigure,
// Enabled or Disabled for the GPO itself.
//
// The second call, RequestSetting will provide the "Yes" or "No"
// value for setting
// the policy as shown by the GPO Editor
//
// iMode
// 0=Not Configured, 1=Enabled, 2=Disabled
//
switch (iMode)
{
case 0:
//
// We do not want to configure the GPO, but we don't want to
// affect other GPOs on the same key,
// so just delete values associated with this
// particular GPO setting.
//
rStatus = RegDeleteValue(hGPOSectionKey,
L"Software\\Policies\\Microsoft\\Windows\\System\\DisableCMD"
);
rStatus = RegDeleteValue(hGPOSectionKey,
L"Software\\Policies\\Microsoft\\Windows\\System\\**del.DisableCMD"
);
break;
case 1:
{
//
// To enable the policy, the DisableCMD value must
// exist and the **del.DisableCMD value must not.
//
// lData:
//
// Check to see if the key for this policy exists.
// If if it does, retrieve a handle
// If not, create it.
//
if( RegOpenKeyEx( hGPOSectionKey,
L"Software\\Policies\\Microsoft\\Windows\\System", 0,
KEY_WRITE, &hSettingKey) != ERROR_SUCCESS )
{
rStatus = RegCreateKeyEx(
hGPOSectionKey,
L"Software\\Policies\\Microsoft\\Windows\\System",
0,
NULL,
REG_OPTION_NON_VOLATILE,
KEY_WRITE,
NULL,
&hSettingKey,
NULL );
}
//
// Set the value DisableCMD and allow, disallow
// script launching of CMD
//
rStatus = RegSetValueEx(hSettingKey, L"DisableCMD",
NULL, REG_DWORD, (BYTE *)(&lData),
sizeof(DWORD));
//
// Remove the not configured value indicator from the hive.
// It may not exist, so the RegDeleteValue may return
// and error, this can be ignored.
//
rStatus = RegDeleteValue(hGPOSectionKey,
L"Software\\Policies\\Microsoft\\Windows\\System\\**del.DisableCMD"
);
rStatus = RegCloseKey(hSettingKey);
break;
}
case 2:
{
//
// Disable the policy.
// must remove the DisableCMD value and add the
// **del.DisableCMD value.
//
// Same stesp as before, check to see if the key for this
// policy exists,
// if not, create it.
//
BOOL bCreate = FALSE;
if( RegOpenKeyEx( hGPOSectionKey, L"Software\\Policies\\Microsoft\\Windows\\System", 0, KEY_WRITE, &hSettingKey) != ERROR_SUCCESS )
{
rStatus = RegCreateKeyEx(
hGPOSectionKey,
L"Software\\Policies\\Microsoft\\Windows\\System",
0,
NULL,
REG_OPTION_NON_VOLATILE,
KEY_WRITE,
NULL,
&hSettingKey,
NULL );
bCreate = TRUE;
}
DWORD dwType = 0;
DWORD cbType = sizeof( dwData );
if( !bCreate )
{
//
// If we did not create the key, then our value
// *may* exist.
// try to read it. If we succeed, write that value back
// to **del.DisableCMD
// if not, then set **del.DisableCMD to 0
//
rStatus = RegGetValue(hGPOSectionKey,
L"Software\\Policies\\Microsoft\\Windows\\System", L"DisableCMD", RRF_RT_ANY, &dwType, (BYTE *)(&dwData), &cbType);
if( rStatus != ERROR_SUCCESS ) dwData = 0;
else RegDeleteValue( hSettingKey, L"DisableCMD");
rStatus = RegSetValueEx(hSettingKey, L"**del.DisableCMD", NULL, REG_DWORD, (BYTE *)(&dwData), sizeof(DWORD));
}
else
{
//
// The key was created, just set the **del.DisableCMD
// value to 0
//
dwData = 0;
rStatus = RegSetValueEx(hSettingKey, L"**del.DisableCMD", NULL, REG_DWORD, (BYTE *)(&dwData), sizeof(DWORD));
}
rStatus = RegCloseKey(hSettingKey);
}
}
GUID RegistryId = REGISTRY_EXTENSION_GUID;
GUID ThisAdminToolGuid =
/*{ CLSID_PolicySnapinUser/* */
{
0x0F6B957E,
0x509E,
0x11D1,
{0xA7, 0xCC, 0x00, 0x00, 0xF8, 0x75, 0x71, 0xE3}
};
rStatus = RegCloseKey(hGPOSectionKey);
//
// Write the GPO back to the directory
//
hr = p->Save(
FALSE,
TRUE,
&RegistryId,
&ThisAdminToolGuid );
hr = p->Release();
}
return hr;
}
Comments
Anonymous
September 24, 2010
The comment has been removedAnonymous
September 24, 2010
I found what caused the problem . ThanksAnonymous
September 24, 2010
How can I get the Active Directory for GPO?Anonymous
February 19, 2012
Hi, I'm using vc6, downloaded sdk 2003 , icluded gpedit.h and compiled the above code the first Arg of the above fn :- bGPOPath : what is it ? how can i get it? Why: RRF_RT_ANY, LSTATUS,RegGetValue : undeclared identifier? ThanksAnonymous
February 22, 2012
Max Vaughn , Where're you ? bGPOPath : what is it ? how can i get it? I tried to use GetDSPath to get bGPOPath but it didnt workAnonymous
June 18, 2014
hello sir , when i compiled the code i got C:UserspcDesktopUntitled3.cpp|1|error: `HRESULT' does not name a type| ||=== Build failed: 1 error(s), 0 warning(s) (0 minute(s), 0 second(s)) ===| can i know the soutionAnonymous
February 22, 2015
Hi, I am working on implementing user based software restriction policy programmatically for local group policy object. If I create a policy through Domain Controller ,I do have option for software restriction policy in user configuration but in local group policy editor I don't have option for that. When I look for the changes made by policy applied from Domain Controller in registry, they modify registry values for specific users on path HKEY_USERS(SID of User)SoftwaresPoliciesMicrosoftWindowsSaferCodeidentifiers They also have registry.pol stored in SYSvol folder in Domain Controller. When I make the same changes in registry to block any other application, application is getting blocked. I achieved what I wanted but is it right to modify registry values ? If the implementation ever changes, if Windows notices that there are group policy settings in place that aren't in the actual group policy, will they remove it ?Anonymous
November 02, 2015
Is the last parameter to save always the save, irrespective of an OS?Anonymous
January 15, 2016
@ADiL: The RegGetValue function requires a header of Winreg.h and isn't part of the Windows API in Windows XP. RegGetValue was added in Windows XP 64-bit and will work in all newer Windows OS's. A good alternative is RegQueryValueEx, although you will have to handle checking for the � character at the end of returned strings with this function.Anonymous
February 18, 2016
Hi, I have the same problem as ADiL. How to find the ADsPath? I tried OpenLocalMachineGPO (), it works, but then RegOpenKey () fails with error 2 for every subkey path.