Windows组策略的刷新和修改
By Kingron, 版权所有
组策略的注册表对应项目请参考:
http://msdn2.microsoft.com/en-us/library/ms815238.aspx
Windows有一个gpedit.msc,很好用的一个工具,可以定制Windows很多的配置。但是如果我们需要自己的程序来修改这些配置的话,你会发现Windows的组策略根本不认!但是你修改注册表重新启动机器后,某些配置是起作用的,这个原因在于,我们必须同时刷新系统,而且必须刷新组策略。
Windows组策略会在你的注册表中建立一个组策略的缓冲,必须更新这个缓冲才会同时起作用!
下面以修改Windows XP的开始中的"注销"菜单项配置来说明。
注意:在Windows组策略中,一般地,如果注册表项目不存在,则显示为"未配置",如果数值为0,则显示为已禁用,为1则显示为已启用,其他的值和对应数据相关。
Windows开始菜单的注销配置存储在Software\Microsoft\Windows\CurrentVersion\Policies\Explorer下
数值为: StartMenuLogOff(DWORD) = 0 | 1;
我们正常写注册表代码为:
RootKey := HKEY_CURRENT_USER;
if OpenKey('Software\Microsoft\Windows\CurrentVersion\Policies\Explorer', True) then
begin
WriteInteger('StartMenuLogOff', 0);
end;
写入注册表后刷新系统或者重新启动服务器,是可以起作用的,但是组策略不认,因此在下一次组策略刷新后可能会导致配置失效,因此还是必须让组策略接纳我们的修改,组策略的缓冲存储在注册表 Software\Microsoft\Windows\CurrentVersion\Group Policy Objects\{574DE082-1E91-47C9-95A1-C731CC87F739}Machine\下,其中的GUID为组策略在注册表中映射,组策略实际存储在文件%system%wbem\Repository\FS\OBJECTS.DATA中,该GUID是动态的,每次运行Gpedit.msc或者进行其他组策略操作的时候都不一样。然后必须在这个Key下建立你的除Root外的Key,其中的Machine也可以为User,决定于策略的有效范围!并写入你的数据,最后刷新系统即可。
因此完整的代码如下:
uses ComObj , ActiveX , Registry ;
const
GPO_OPEN_LOAD_REGISTRY = $00000001 ; // Load the registry files
{$EXTERNALSYM GPO_OPEN_LOAD_REGISTRY}
GPO_OPEN_READ_ONLY = $00000002 ; // Open the GPO as read only
GPO_SECTION_ROOT = 0 ; // Root
{$EXTERNALSYM GPO_SECTION_ROOT}
GPO_SECTION_USER = 1 ; // User
{$EXTERNALSYM GPO_SECTION_USER}
GPO_SECTION_MACHINE = 2 ; // Machine
const
IID_GPO : TGUID = '{EA502722-A23D-11d1-A7D3-0000F87571E3}' ;
type
HPROPSHEETPAGE = Pointer ;
{$EXTERNALSYM HPROPSHEETPAGE}
PHPROPSHEETPAGE = ^ HPROPSHEETPAGE ;
LPOLESTR = POleStr ;
_GROUP_POLICY_OBJECT_TYPE = (
GPOTypeLocal , // GPO on the local machine
GPOTypeRemote , // GPO on a remote machine
GPOTypeDS ); // GPO in the Active Directory
{$EXTERNALSYM _GROUP_POLICY_OBJECT_TYPE}
GROUP_POLICY_OBJECT_TYPE = _GROUP_POLICY_OBJECT_TYPE ;
IGroupPolicyObject = interface ( IUnknown )
[ '{EA502723-A23D-11d1-A7D3-0000F87571E3}' ]
function New ( pszDomainName , pszDisplayName : LPOLESTR ; dwFlags : DWORD ): HRESULT ; stdcall ;
function OpenDSGPO ( pszPath : LPOLESTR ; dwFlags : DWORD ): HRESULT ; stdcall ;
function OpenLocalMachineGPO ( dwFlags : DWORD ): HRESULT ; stdcall ;
function OpenRemoteMachineGPO ( pszComputerName : LPOLESTR ; dwFlags : DWORD ): HRESULT ; stdcall ;
function Save ( bMachine , bAdd : BOOL ; const pGuidExtension , pGuid : TGUID ): HRESULT ; stdcall ;
function Delete : HRESULT ; stdcall ;
function GetName ( pszName : LPOLESTR ; cchMaxLength : Integer ): HRESULT ; stdcall ;
function GetDisplayName ( pszName : LPOLESTR ; cchMaxLength : Integer ): HRESULT ; stdcall ;
function SetDisplayName ( pszName : LPOLESTR ): HRESULT ; stdcall ;
function GetPath ( pszPath : LPOLESTR ; cchMaxPath : Integer ): HRESULT ; stdcall ;
function GetDSPath ( dwSection : DWORD ; pszPath : LPOLESTR ; cchMaxPath : Integer ): HRESULT ; stdcall ;
function GetFileSysPath ( dwSection : DWORD ; pszPath : LPOLESTR ; cchMaxPath : Integer ): HRESULT ; stdcall ;
//
// Returns a registry key handle for the requested section. The returned
// key is the root of the registry, not the Policies subkey. To set / read
// a value in the Policies subkey, you will need to call RegOpenKeyEx to
// open Software\Policies subkey first.
//
// The handle has been opened with ALL ACCESS rights. Call RegCloseKey
// on the handle when finished.
//
// If the GPO was loaded / created without the registry being loaded
// this method will return E_FAIL.
//
// dwSection is either GPO_SECTION_USER or GPO_SECTION_MACHINE
// hKey contains the registry key on return
//
function GetRegistryKey ( dwSection : DWORD ; var hKey : HKEY ): HRESULT ; stdcall ;
function GetOptions ( var dwOptions : DWORD ): HRESULT ; stdcall ;
function SetOptions ( dwOptions , dwMask : DWORD ): HRESULT ; stdcall ;
function GetType ( var gpoType : GROUP_POLICY_OBJECT_TYPE ): HRESULT ; stdcall ;
function GetMachineName ( pszName : LPOLESTR ; cchMaxLength : Integer ): HRESULT ; stdcall ;
function GetPropertySheetPages ( var hPages : PHPROPSHEETPAGE ; var uPageCount : UINT ): HRESULT ; stdcall ;
end ;
const
REGISTRY_EXTENSION_GUID : TGUID = (
D1 : $35378EAC ; D2 : $683F ; D3 : $11D2 ; D4 :( $A8 , $9A , $00 , $C0 , $4F , $BB , $CF , $A2 ));
CLSID_GPESnapIn : TGUID = (
D1 : $8fc0b734 ; D2 : $a0e1 ; D3 : $11d1 ; D4 :( $a7 , $d3 , $0 , $0 , $f8 , $75 , $71 , $e3 ));
procedure TForm1 . Button1Click ( Sender : TObject );
var
GPO : IGroupPolicyObject ;
Key : HKEY ;
begin
GPO := CreateComObject ( IID_GPO ) as IGroupPolicyObject ;
if S_OK = GPO . OpenLocalMachineGPO ( GPO_OPEN_LOAD_REGISTRY ) then
begin
if S_OK = GPO . GetRegistryKey ( GPO_SECTION_USER , Key ) then
with TRegistry . Create do
try
RootKey := HKEY_CURRENT_USER ;
if OpenKey ( 'Software\Microsoft\Windows\CurrentVersion\Policies\Explorer' , True ) then
begin
WriteInteger ( 'StartMenuLogOff' , 0 );
end ;
RootKey := Key ;
if OpenKey ( '\Software\Microsoft\Windows\CurrentVersion\Policies\Explorer' , True ) then
begin
WriteInteger ( 'StartMenuLogOff' , 0 );
end ;
RegCloseKey ( Key );
GPO . Save ( False , True , REGISTRY_EXTENSION_GUID , CLSID_GPESnapIn );
finally
Free ;
end ;
SendMessage ( HWND_BROADCAST , WM_SETTINGCHANGE , Integer ( PChar ( 'Polices' )), 0 );
end ;
end ;
同时需要注意的是,组策略不支持多线程处理的,总是以最后的一个存储结果为准,因此在测试上面代码的时候,请不要运行gpedit.msc,如果要验证结果是否正确,可以先启动gpedit.msc,记录下配置,然后关闭gpedit.msc,再运行上面的代码,然后启动gpedit.msc查看配置是不是已经改过来了? :-)
BTW ,组策略的全部注册表项目,可以在MSDN中的Group Policy Registry Table目录中找到。
地址: ms-help://MS.MSDNQTR.2004JAN.1033/gp/gpref.htm
下面是一个网友的C#的代码:
/*
更改组策略设置方法
参数:
hKey:注册表根项目
subKey:注册表子项目
valueName:项目名称
dwType:项目类型
szkeyValue:REG_SZ类型的项目值
dwkeyValue:REG_DWORD类型的项目值
*/
private: System::Boolean SetGroupPolicy(HKEY hKey,LPCTSTR subKey,LPCTSTR valueName,DWORD dwType,const BYTE* szkeyValue,DWORD dwkeyValue){
HKEY ghKey,ghSubKey,hSubKey;
LPDWORD flag = NULL;
//初始化GPO接口对象,如果失败,提示错误信息
HRESULT hr = CoCreateInstance(CLSID_GroupPolicyObject,NULL,CLSCTX_ALL,IID_IGroupPolicyObject,(LPVOID*)&pGPO);
if(!SUCCEEDED(hr))
MessageBox::Show(L"GPO接口对象初始化失败",L"",MessageBoxButtons::OK,MessageBoxIcon::Error);
//修改本地注册表
if ( RegCreateKeyEx(hKey,
subKey,
0,
NULL,
REG_OPTION_NON_VOLATILE,
KEY_WRITE,
NULL,
&hSubKey,
flag) != ERROR_SUCCESS){
return false;
}
if(dwType == REG_SZ){
if( RegSetValueEx(hSubKey,valueName,0,dwType,szkeyValue,strlen((char*)szkeyValue)+1) != ERROR_SUCCESS){
RegCloseKey(hSubKey);
return false;
}
}
else if(dwType == REG_DWORD){
if( RegSetValueEx(hSubKey,valueName,0,dwType,(BYTE*)&dwkeyValue,sizeof(dwkeyValue)) != ERROR_SUCCESS){
RegCloseKey(hSubKey);
return false;
}
}
//修改本地GPO
if(!SUCCEEDED(hr)){
MessageBox::Show(L"GPO接口对象初始化失败",L"",MessageBoxButtons::OK,MessageBoxIcon::Error);
return false;
}
if(pGPO->OpenLocalMachineGPO(GPO_OPEN_LOAD_REGISTRY) != S_OK){
MessageBox::Show(L"获取本地GPO映射失败",L"",MessageBoxButtons::OK,MessageBoxIcon::Error);
return false;
}//OpenLocalMachine
if(pGPO->GetRegistryKey(GPO_SECTION_USER,&ghKey) != S_OK){
MessageBox::Show(L"获取本地GPO映射注册表根键失败",L"",MessageBoxButtons::OK,MessageBoxIcon::Error);
return false;
}//GetRegistryKey
if(RegCreateKeyEx(ghKey,
subKey,
0,
NULL,
REG_OPTION_NON_VOLATILE,
KEY_WRITE,
NULL,
&ghSubKey,
flag) != ERROR_SUCCESS){
RegCloseKey(ghKey);
MessageBox::Show(L"无法创建组策略注册表子项目",L"",MessageBoxButtons::OK,MessageBoxIcon::Error);
return false;
}//RegCreateKeyEx
if(dwType == REG_SZ){
if(RegSetValueEx(ghSubKey,valueName,0,dwType,szkeyValue,strlen((char*)szkeyValue)+1) != ERROR_SUCCESS){
RegCloseKey(ghKey);
RegCloseKey(ghSubKey);
MessageBox::Show(L"无法创建组策略注册表子项目值",L"",MessageBoxButtons::OK,MessageBoxIcon::Error);
return false;
}//RegSetValueEx
}
else if(dwType == REG_DWORD){
if(RegSetValueEx(ghSubKey,valueName,0,dwType,(BYTE*)&dwkeyValue,sizeof(dwkeyValue)) != ERROR_SUCCESS){
RegCloseKey(ghKey);
RegCloseKey(ghSubKey);
MessageBox::Show(L"无法创建组策略注册表子项目值",L"",MessageBoxButtons::OK,MessageBoxIcon::Error);
return false;
}//RegSetValueEx
}
if(pGPO->Save(false,true,&ng1,&ng2) != S_OK){
RegCloseKey(ghKey);
RegCloseKey(ghSubKey);
MessageBox::Show(L"保存组策略失败",L"",MessageBoxButtons::OK,MessageBoxIcon::Error);
return false;
}
pGPO->Release();
RegCloseKey(ghKey);
RegCloseKey(ghSubKey);
return true;
}