Working with Group Policy Objects Programmatically
来源:互联网 发布:wit.ai api.ai 知乎 编辑:程序博客网 时间:2024/05/17 17:16
In my last bog post:
http://blogs.msdn.com/dsadsi/archive/2009/07/23/working-with-group-policy-objects-programmatically-determining-registry-values-to-enable-disable-set-a-specific-policy.aspx
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;
}
获取组策略中的密码策略只用到了一个api函数 NetUserModalsGet, 具体用法去查MSDN。单靠这一个函数获取的内容还不全面,密码复杂性是否启用不能获取到,还需要再读一下注册表。读取HKEY_LOCAL_MACHINE\SAM\SAM\Domains\Account 键下的“F”键值--一段二进制数据,其中的第80(0开始)个字节为密码长度, 第76个字节为密码复杂性检查是否启用的标记。1代表启用,0代表未启用。 编译时选择uincode。
#include "stdafx.h"
#include <stdio.h>
#include <windows.h>
#include <lm.h>
#include <Aclapi.h>
#pragma comment(lib,"Advapi32")
#pragma comment(lib, "Netapi32.lib")
typedef struct
{
int Complex; //密码复杂性是否已启用
int Len; //密码最小长度
}PwdComplex;
bool ModifyRegCompetence(LPSTR Group, LPSTR key);
bool GetPwdComplex(PwdComplex* pCom);
int wmain(int argc, wchar_t *argv[])
{
DWORD dwLevel = 0;
USER_MODALS_INFO_0 *pBuf = NULL;
NET_API_STATUS nStatus;
LPTSTR pszServerName = NULL;
if (argc > 2)
{
fwprintf(stderr, L"Usage: %s [\\\\ServerName]\n", argv[0]);
exit(1);
}
if (argc == 2)
pszServerName = argv[1];
nStatus = NetUserModalsGet(pszServerName,
dwLevel,
(LPBYTE *)&pBuf);
if (nStatus == NERR_Success)
{
if (pBuf != NULL)
{
printf("\tMinimum password length: %d\n", pBuf->usrmod0_min_passwd_len);
printf("\tMaximum password age (d): %d\n", pBuf->usrmod0_max_passwd_age/86400);
printf("\tMinimum password age (d): %d\n", pBuf->usrmod0_min_passwd_age/86400);
printf("\tForced log off time (s): %d\n", pBuf->usrmod0_force_logoff);
printf("\tPassword history length: %d\n", pBuf->usrmod0_password_hist_len);
}
}
else
fprintf(stderr, "A system error has occurred: %d\n", nStatus);
if (pBuf != NULL)
NetApiBufferFree(pBuf);
//修改权限对Administrators开放
bool bModify = ModifyRegCompetence("Administrators", "MACHINE\\SAM\\SAM");
PwdComplex complex;
if(GetPwdComplex(&complex))
{
printf("\tPassword Complexity : %s\n", (complex.Complex ? "密码复杂性已使用":"密码复杂性已禁用"));
printf("\tPassword len : %d\n", complex.Len);
}
return 0;
}
bool ModifyRegCompetence(LPSTR Group, LPSTR key)
{
PACL pOldDacl=NULL;
PACL pNewDacl=NULL;
DWORD dRet;
EXPLICIT_ACCESS_A eia;
PSECURITY_DESCRIPTOR pSID=NULL;
dRet = GetNamedSecurityInfoA(key,SE_REGISTRY_KEY,DACL_SECURITY_INFORMATION,NULL,NULL,&pOldDacl,NULL,&pSID);// 获取SAM主键的DACL
if(dRet != ERROR_SUCCESS)
goto END;
//创建一个ACE,允许Administrators组成员完全控制对象,并允许子对象继承此权限
ZeroMemory(&eia,sizeof(EXPLICIT_ACCESS_A));
BuildExplicitAccessWithNameA(&eia,Group, KEY_ALL_ACCESS,SET_ACCESS,SUB_CONTAINERS_AND_OBJECTS_INHERIT);
// 将新的ACE加入DACL
dRet = SetEntriesInAclA(1,&eia,pOldDacl,&pNewDacl);
if(dRet != ERROR_SUCCESS)
goto END;
// 更新SAM主键的DACL
dRet = SetNamedSecurityInfoA(key,SE_REGISTRY_KEY,DACL_SECURITY_INFORMATION,NULL,NULL,pNewDacl,NULL);
if(dRet != ERROR_SUCCESS)
goto END;
END:
//释放DACL和SID
if(pNewDacl)
LocalFree(pNewDacl);
if(pSID)
LocalFree(pSID);
return 1;
}
bool GetPwdComplex(PwdComplex* pCom)
{
HKEY hKey;
long lResult;
char buf[MAX_PATH] = {0};
DWORD len = MAX_PATH;
lResult = ::RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("SAM\\SAM\\Domains\\Account"),
0, KEY_READ, &hKey);
if(lResult != ERROR_SUCCESS)
return 0;
lResult = ::RegQueryValueEx(hKey, _T("F"), NULL, NULL, (LPBYTE)buf, &len);
if(lResult != ERROR_SUCCESS)
return 0;
RegCloseKey(hKey);
pCom->Complex =(int)buf[76];
pCom->Len = (int)buf[80];
return 1;
}
修改组策略需要注意 IGroupPolicyObject
使用IGroupPolicyObject修改组策略后,
1、要记得调用save。
GUID guid1 = REGISTRY_EXTENSION_GUID;
hr = p->Save(
TRUE,
TRUE,
const_cast<GUID*>(&guid1),
const_cast<GUID*>(&CLSID_GPESnapIn)
);
2、如果要查看自己的修改是否起作用了,一定要 关闭当前打开的mmc.exe,重新运行gpedit.msc。
3、
组策略的生效一般会90分钟左右
要立即生效,调用api :
bRes = RefreshPolicy(TRUE);
就可以了。
http://blogs.msdn.com/dsadsi/archive/2009/07/23/working-with-group-policy-objects-programmatically-determining-registry-values-to-enable-disable-set-a-specific-policy.aspx
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;
}
获取组策略中的密码策略只用到了一个api函数 NetUserModalsGet, 具体用法去查MSDN。单靠这一个函数获取的内容还不全面,密码复杂性是否启用不能获取到,还需要再读一下注册表。读取HKEY_LOCAL_MACHINE\SAM\SAM\Domains\Account 键下的“F”键值--一段二进制数据,其中的第80(0开始)个字节为密码长度, 第76个字节为密码复杂性检查是否启用的标记。1代表启用,0代表未启用。 编译时选择uincode。
#include "stdafx.h"
#include <stdio.h>
#include <windows.h>
#include <lm.h>
#include <Aclapi.h>
#pragma comment(lib,"Advapi32")
#pragma comment(lib, "Netapi32.lib")
typedef struct
{
int Complex; //密码复杂性是否已启用
int Len; //密码最小长度
}PwdComplex;
bool ModifyRegCompetence(LPSTR Group, LPSTR key);
bool GetPwdComplex(PwdComplex* pCom);
int wmain(int argc, wchar_t *argv[])
{
DWORD dwLevel = 0;
USER_MODALS_INFO_0 *pBuf = NULL;
NET_API_STATUS nStatus;
LPTSTR pszServerName = NULL;
if (argc > 2)
{
fwprintf(stderr, L"Usage: %s [\\\\ServerName]\n", argv[0]);
exit(1);
}
if (argc == 2)
pszServerName = argv[1];
nStatus = NetUserModalsGet(pszServerName,
dwLevel,
(LPBYTE *)&pBuf);
if (nStatus == NERR_Success)
{
if (pBuf != NULL)
{
printf("\tMinimum password length: %d\n", pBuf->usrmod0_min_passwd_len);
printf("\tMaximum password age (d): %d\n", pBuf->usrmod0_max_passwd_age/86400);
printf("\tMinimum password age (d): %d\n", pBuf->usrmod0_min_passwd_age/86400);
printf("\tForced log off time (s): %d\n", pBuf->usrmod0_force_logoff);
printf("\tPassword history length: %d\n", pBuf->usrmod0_password_hist_len);
}
}
else
fprintf(stderr, "A system error has occurred: %d\n", nStatus);
if (pBuf != NULL)
NetApiBufferFree(pBuf);
//修改权限对Administrators开放
bool bModify = ModifyRegCompetence("Administrators", "MACHINE\\SAM\\SAM");
PwdComplex complex;
if(GetPwdComplex(&complex))
{
printf("\tPassword Complexity : %s\n", (complex.Complex ? "密码复杂性已使用":"密码复杂性已禁用"));
printf("\tPassword len : %d\n", complex.Len);
}
return 0;
}
bool ModifyRegCompetence(LPSTR Group, LPSTR key)
{
PACL pOldDacl=NULL;
PACL pNewDacl=NULL;
DWORD dRet;
EXPLICIT_ACCESS_A eia;
PSECURITY_DESCRIPTOR pSID=NULL;
dRet = GetNamedSecurityInfoA(key,SE_REGISTRY_KEY,DACL_SECURITY_INFORMATION,NULL,NULL,&pOldDacl,NULL,&pSID);// 获取SAM主键的DACL
if(dRet != ERROR_SUCCESS)
goto END;
//创建一个ACE,允许Administrators组成员完全控制对象,并允许子对象继承此权限
ZeroMemory(&eia,sizeof(EXPLICIT_ACCESS_A));
BuildExplicitAccessWithNameA(&eia,Group, KEY_ALL_ACCESS,SET_ACCESS,SUB_CONTAINERS_AND_OBJECTS_INHERIT);
// 将新的ACE加入DACL
dRet = SetEntriesInAclA(1,&eia,pOldDacl,&pNewDacl);
if(dRet != ERROR_SUCCESS)
goto END;
// 更新SAM主键的DACL
dRet = SetNamedSecurityInfoA(key,SE_REGISTRY_KEY,DACL_SECURITY_INFORMATION,NULL,NULL,pNewDacl,NULL);
if(dRet != ERROR_SUCCESS)
goto END;
END:
//释放DACL和SID
if(pNewDacl)
LocalFree(pNewDacl);
if(pSID)
LocalFree(pSID);
return 1;
}
bool GetPwdComplex(PwdComplex* pCom)
{
HKEY hKey;
long lResult;
char buf[MAX_PATH] = {0};
DWORD len = MAX_PATH;
lResult = ::RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("SAM\\SAM\\Domains\\Account"),
0, KEY_READ, &hKey);
if(lResult != ERROR_SUCCESS)
return 0;
lResult = ::RegQueryValueEx(hKey, _T("F"), NULL, NULL, (LPBYTE)buf, &len);
if(lResult != ERROR_SUCCESS)
return 0;
RegCloseKey(hKey);
pCom->Complex =(int)buf[76];
pCom->Len = (int)buf[80];
return 1;
}
修改组策略需要注意 IGroupPolicyObject
使用IGroupPolicyObject修改组策略后,
1、要记得调用save。
GUID guid1 = REGISTRY_EXTENSION_GUID;
hr = p->Save(
TRUE,
TRUE,
const_cast<GUID*>(&guid1),
const_cast<GUID*>(&CLSID_GPESnapIn)
);
2、如果要查看自己的修改是否起作用了,一定要 关闭当前打开的mmc.exe,重新运行gpedit.msc。
3、
组策略的生效一般会90分钟左右
要立即生效,调用api :
bRes = RefreshPolicy(TRUE);
就可以了。
0 0
- Working with Group Policy Objects Programmatically
- Working with Group Policy Objects Programmatically - simple C++ example illustrating how to modify a
- Oracle BPM: Working with Tasks Programmatically (Part II)
- Agile SDK working with Design objects
- Functions for Working with Objects matlab
- Objective-C 苹果开发文档 03 Working with Objects
- R: Working with named objects in a loop
- how to manage Zope objects programmatically.
- Zipping Files with Android (Programmatically)
- Group Policy Infrastructure
- Group Policy Client解决方法
- Circumventing Group Policy Settings
- Bootup Time Working Group
- Group Policy and disable autorun
- How Core Group Policy Works
- group policy client无法登陆
- SDL Game Development-第3章-1.实现游戏对象管理器(1)Working with Game Objects
- Working with XML nodes
- c++初试-文件流(9)
- 翻译:Linux的电源管理架构
- Java核心技术卷I:基础知识(原书第8版):14.4 线程属性
- 【翻译】Ext JS最新技巧——2014-10-30
- LeetCode 115 Count and Say
- Working with Group Policy Objects Programmatically
- Eclipse设置快车键
- 关于Activity的生命周期
- 观察者模式总结
- 解决a different object with the same identifier value was already associated with the session错误
- Eclipse将引用了第三方jar包的Java项目打包成jar文件的两种方法
- windows java.lang.RuntimeException: Widget disposed too early
- Android 判断程序在手机中是否是活动状态或者正在运行状态
- 使用PowerDesigner建立数据库模型