#AutoIt3Wrapper_UseX64=y ; change this as needed for your target architecture #cs ---------------------------------------------------------------------------- Title: GPO Registry Editor standalone add and delete functions AutoIt Version: 3.3.8.1 Original Author: Michael Mims (zorphnog) Search Autoit3 forums for "Registry Policy File Editor" https://www.autoitscript.com/forum/topic/141076-registry-policy-file-editor/ Modifed by: ModemJunki, strip out GUI and keep only the operating functions needed to modify the .POL files. Whats missing: Logging functions. Perhaps I will add them later. I usually log to the event log, not everyones cup of tea. Script Function: Provides read/write capabilities for the registry policy file format (.pol) for use as an include file. Can also be hard-coded for standalone use (see "some samples to play with." commant in code). Registry policy files contain registry information used by the local group policy. Editing these files, followed by a `gpupdate /force` command will update the local group policy (or a reboot will update). This include-file does not create new .pol files. The original script with GUI, I think, can. **Note: On Windows Vista and above, administrator rights are required to save to the system group policy folder. #RequireAdmin must be used. Reference(s): Registry Policy File Format - http://msdn.microsoft.com/en-us/library/windows/desktop/aa374407(v=vs.85).aspx The _OpenFile function opens the policy file for read/write. Syntax: _OpenFile(policy registry space) where the policy registry space is either of the two below variables: $USER_REGISTRY_FILE for user policies $MACHINE_REGISTRY_FILE for machine policies The _AddEntry function adds a new or modifies an existing policy entry. Syntax: _AddEntry(Key, Value, Type, Data) where Type is default 1 (REG_SZ) The Types are: 1 = REG_SZ 2 = REG_EXPAND_SZ 3 = REG_BINARY 4 = REG_DWORD 5 = REG_DWORD_BIG_ENDIAN 6 = REG_LINK 7 = REG_MULTI_SZ 8 = REG_RESOURCE_LIST 9 = REG_FULL_RESOURCE_DESCRIPTION 10 = REG_RESOURCE_REQUIREMENTRS_LIST 11 = REG_QWORD Example: _AddEntry("Software\Policies\Microsoft\MyTestKey", "My Test Value", 1, "Registry Policy File editing") The _DeleteEntry function deletes an existing policy key. Syntax: _DeleteEntry(Key, Value) Example: _DeleteEntry("Software\Policies\Microsoft\MyTestKey", "My Test Value") The _WritePolFile function must be used to close the same file that was opened by the _OpenFile function Syntax: _WritePolFile(policy registry space) where the policy registry space is either of the two below variables: $USER_REGISTRY_FILE for user policies $MACHINE_REGISTRY_FILE for machine policies #ce ---------------------------------------------------------------------------- #RequireAdmin #include ; File globals Global Const $USER_REGISTRY_FILE = @SystemDir & "\GroupPolicy\User\Registry.pol" Global Const $MACHINE_REGISTRY_FILE = @SystemDir & "\GroupPolicy\Machine\Registry.pol" ; Policy file format globals Global Const $REGISTRY_FILE_SIGNATURE = 0x67655250 Global Const $REGISTRY_FILE_VERSION = 0x00000001 Global Const $REGISTRY_FILE_ENCODING = 2 ; 1 - ANSI, 2 - UTF16 LE, 3 - UTF16 BE, 4 - UTF8 ; $g_aEntries array indices Global Enum $POLENTRY_KEY, $POLENTRY_VALUE, $POLENTRY_TYPE, $POLENTRY_SIZE, $POLENTRY_DATA ; Registry globals Global Enum $REG_NONE,$REG_SZ,$REG_EXPAND_SZ,$REG_BINARY,$REG_DWORD,$REG_DWORD_BIG_ENDIAN,$REG_LINK,$REG_MULTI_SZ, _ $REG_RESOURCE_LIST,$REG_FULL_RESOURCE_DESCRIPTOR,$REG_RESOURCE_REQUIREMENTS_LIST,$REG_QWORD Global Const $g_REGTYPES[12] = [ "REG_NONE", "REG_SZ", "REG_EXPAND_SZ", "REG_BINARY", _ "REG_DWORD", "REG_DWORD_BIG_ENDIAN", "REG_LINK", "REG_MULTI_SZ", "REG_RESOURCE_LIST", _ "REG_FULL_RESOURCE_DESCRIPTOR", "REG_RESOURCE_REQUIREMENTS_LIST", "REG_QWORD"] Global Const $g_ENTRYREGTYPE_CONV[4] = [$REG_SZ,$REG_EXPAND_SZ,$REG_BINARY,$REG_DWORD] Global Const $g_ENTRYREGTYPES[4] = [$g_REGTYPES[$g_ENTRYREGTYPE_CONV[0]],$g_REGTYPES[$g_ENTRYREGTYPE_CONV[1]], _ $g_REGTYPES[$g_ENTRYREGTYPE_CONV[2]], $g_REGTYPES[$g_ENTRYREGTYPE_CONV[3]]] ; Policy entry type globals Global Enum $ENTRY_TYPE_NORM,$ENTRY_TYPE_DEL,$ENTRY_TYPE_DELMULVALS,$ENTRY_TYPE_DELALLVALS,$ENTRY_TYPE_DELKEYS, _ $ENTRY_TYPE_SECKEY,$_ENTRY_TYPE_SIZE Global Const $g_ENTRYTYPES[$_ENTRY_TYPE_SIZE] = ["Normal Entry", "Delete Value", "Delete Multiple Values", _ "Delete All Values", "Delete Subkeys", "Secure Key"] ; $g_EntryCtrl array indices Global Enum $MAIN_GUI,$MAIN_LVENTR,$MAIN_BTNEW,$MAIN_BTEDIT,$MAIN_BTDEL,$MAIN_MIMPOL,$MAIN_MIUPOL,$MAIN_MISAVE, _ $MAIN_MISAVA,$_MAIN_SIZE ; Error code globals Global Enum Step *2 $GRE_ERROR_NONE=0,$GRE_ERROR_NOFILE=1,$GRE_ERROR_NOACTION,$GRE_ERROR_NOKEY,$GRE_ERROR_NOVALUE, _ $GRE_ERROR_NOTYPE,$GRE_ERROR_INVALIDTYPE,$GRE_ERROR_NODATA,$GRE_ERROR_FILENOTEXIST,$GRE_ERROR_INVALIDARG, _ $GRE_ERROR_DUPLICATEARG,$GRE_ERROR_INVALIDSWITCH,$GRE_ERROR_FILEWRITE,$GRE_ERROR_INVALIDREGISTRYSIG, _ $GRE_ERROR_INVALIDREGISTRYVERSION,$GRE_ERROR_ENTRYNOTFOUND,$GRE_ERROR_DELETEENTRY Global $g_aEntries[1][5] ; -------------------------------------------------------------------------------------------------------------------------------- ; here is the code you could put in your calling function or just hardcode it here ; open the policy file _OpenFile($MACHINE_REGISTRY_FILE) ; some samples to play with. ;~ _AddEntry("Software\Policies\Microsoft\MyTestKey", "My Test Value", 1, "Registry Policy File editing") ;~ _DeleteEntry("Software\Policies\Microsoft\MyTestKey", "My Test Value") ; close the policy file _WritePolFile($MACHINE_REGISTRY_FILE) ; -------------------------------------------------------------------------------------------------------------------------------- ; ------------- Main functions are: Add and Delete ------------- ; Func _AddEntry($sKey, $sValue, $iType = 1, $vData = "") Local $iIndex = _FindEntry($sKey, $sValue) If @error Then $iIndex = UBound($g_aEntries) ReDim $g_aEntries[$iIndex + 1][5] $g_aEntries[$iIndex][$POLENTRY_KEY] = $sKey & ChrW(0) $g_aEntries[$iIndex][$POLENTRY_VALUE] = $sValue & ChrW(0) EndIf ; Force type for special values If StringLeft($sValue, 2) == "**" Then ;~ __DebugPrint("Special value; forcing REG_SZ", "_AddEntry") $iType = $REG_SZ EndIf $g_aEntries[$iIndex][$POLENTRY_TYPE] = Binary(Int($iType)) ; Determine if value is string data and convert properly Switch $iType Case $REG_SZ, $REG_EXPAND_SZ ; Check for special values If StringLeft($sValue, 2) == "**" Then Select Case StringMid($sValue, 3, 12) = "DeleteValues" Or StringMid($sValue, 3, 10) = "DeleteKeys" $vData = StringToBinary(StringRegExpReplace(StringStripWS($vData, 3), "(\s*;\s*)", ";") & _ ChrW(0), $REGISTRY_FILE_ENCODING) Case Else $vData = StringToBinary(ChrW(0x20) & ChrW(0), $REGISTRY_FILE_ENCODING) EndSelect Else $vData = StringToBinary($vData & ChrW(0), $REGISTRY_FILE_ENCODING) EndIf Case $REG_DWORD $vData = Binary(Int($vData)) Case Else $vData = Binary($vData) EndSwitch $g_aEntries[$iIndex][$POLENTRY_SIZE] = BinaryLen($vData) $g_aEntries[$iIndex][$POLENTRY_DATA] = $vData Return $iIndex EndFunc ;==>_AddEntry Func _DeleteEntry($sKey, $sValue) Local $iIndex = _FindEntry($sKey, $sValue) If @error Then Return SetError(@error, 0, -1) ;~ __DebugPrint("--key=" & $sKey & " --value=" & $sValue, "_DeleteEntry") _ArrayDelete($g_aEntries, $iIndex) If @error Then Return SetError($GRE_ERROR_DELETEENTRY, 0, -1) Return 1 EndFunc ;==>_DeleteEntry ; ----------------- Supporting functions below ----------------- ; Func _OpenFile($sFilename = "") ; appears to work If $sFilename <> "" Then _ReadPolFile($sFilename) EndFunc ;==>_OpenFile Func _ReadPolFile($sFilename) Local $hInfile, $bBuffer, $iStart, $iCurrent, $iLength, $iColon, $iNumEntries, $bTemp If Not FileExists($sFilename) Then MsgBox(0x1010, "Error", "ERROR: File not found: " & $sFilename) $hInfile = FileOpen($sFilename, 16) $bBuffer = FileRead($hInfile) FileClose($hInfile) $iLength = BinaryLen($bBuffer) If BinaryMid($bBuffer, 1, 4) <> Binary($REGISTRY_FILE_SIGNATURE) Then MsgBox(0x1010,"Error", "ERROR: Invalid file signature. File will not be processed.") If BinaryMid($bBuffer, 5, 4) <> Binary($REGISTRY_FILE_VERSION) Then MsgBox(0x1010, "Error", "ERROR: Invalid registry file version. File will not be processed.") $iStart = 9 $iCurrent = 9 $iColon = 0 $iNumEntries = 0 $g_aEntries = 0 Dim $g_aEntries[1][5] ; The body consists of registry values in the following format. ; [key;value;type;size;data] While $iCurrent < $iLength $bTemp = BinaryMid($bBuffer, $iCurrent, 2) Switch $bTemp Case 0x005B ; Unicode => [ ReDim $g_aEntries[$iNumEntries+1][5] $iColon = 0 $iStart = $iCurrent + 2 Case 0x005D ; Unicode => ] $iStart = $iCurrent + 2 $iNumEntries += 1 Case 0x003B ; Unicode => ; Switch $iColon Case 0 $g_aEntries[$iNumEntries][$POLENTRY_KEY] = BinaryToString(BinaryMid($bBuffer, $iStart, $iCurrent - $iStart), $REGISTRY_FILE_ENCODING) $iColon += 1 $iStart = $iCurrent + 2 Case 1 $g_aEntries[$iNumEntries][$POLENTRY_VALUE] = BinaryToString(BinaryMid($bBuffer, $iStart, $iCurrent - $iStart), $REGISTRY_FILE_ENCODING) $iColon += 1 $iStart = $iCurrent + 2 Case 2 ;~ _ArrayDisplay($g_aEntries) $g_aEntries[$iNumEntries][$POLENTRY_TYPE] = Int(BinaryMid($bBuffer, $iStart, $iCurrent - $iStart)) $iColon += 1 $iStart = $iCurrent + 2 Case 3 $g_aEntries[$iNumEntries][$POLENTRY_SIZE] = Int(BinaryMid($bBuffer, $iStart, $iCurrent - $iStart)) $iColon += 1 $iStart = $iCurrent + 2 $g_aEntries[$iNumEntries][$POLENTRY_DATA] = BinaryMid($bBuffer, $iStart, $g_aEntries[$iNumEntries][$POLENTRY_SIZE]) $iCurrent = $iStart + $g_aEntries[$iNumEntries][$POLENTRY_SIZE] - 2 Case Else $iColon += 1 $iStart = $iCurrent + 2 EndSwitch EndSwitch $iCurrent += 2 WEnd EndFunc ;==>_ReadPolFile Func _FindEntry($sKey, $sValue) Local $iCurrent, $iIndex, $iSize $iCurrent = 0 $iSize = UBound($g_aEntries) While $iCurrent < $iSize $iIndex = _ArraySearch($g_aEntries, $sValue, $iCurrent, 0, 0, 0, 1, $POLENTRY_VALUE) If @error Then ExitLoop If $g_aEntries[$iIndex][$POLENTRY_KEY] = $sKey Then Return $iIndex EndIf $iCurrent = $iIndex + 1 WEnd Return SetError($GRE_ERROR_ENTRYNOTFOUND, 0, -1) EndFunc ;==>_FindEntry Func _WritePolFile($sFilename) Local $hOutfile, $iMax ; Open file for writing ;~ __DebugPrint("Writing output file...", "_WritePolFile") $hOutfile = FileOpen($sFilename, 26) If $hOutfile = -1 Then MsgBox(0x1010, "Error", "ERROR: File could not be created [" & $sFilename & "].") ;~ Return SetError($GRE_ERROR_FILEWRITE, 0, -1) EndIf ; Write header information FileWrite($hOutfile, Binary($REGISTRY_FILE_SIGNATURE)) FileWrite($hOutfile, Binary($REGISTRY_FILE_VERSION)) ; Write entries $iMax = UBound($g_aEntries) - 1 For $i = 0 To $iMax FileWrite($hOutfile, StringToBinary("[" & $g_aEntries[$i][$POLENTRY_KEY], $REGISTRY_FILE_ENCODING)) FileWrite($hOutfile, StringToBinary(";", $REGISTRY_FILE_ENCODING)) FileWrite($hOutfile, StringToBinary($g_aEntries[$i][$POLENTRY_VALUE], $REGISTRY_FILE_ENCODING)) FileWrite($hOutfile, StringToBinary(";", $REGISTRY_FILE_ENCODING)) FileWrite($hOutfile, $g_aEntries[$i][$POLENTRY_TYPE]) FileWrite($hOutfile, StringToBinary(";", $REGISTRY_FILE_ENCODING)) FileWrite($hOutfile, $g_aEntries[$i][$POLENTRY_SIZE]) FileWrite($hOutfile, StringToBinary(";", $REGISTRY_FILE_ENCODING)) FileWrite($hOutfile, $g_aEntries[$i][$POLENTRY_DATA]) FileWrite($hOutfile, StringToBinary("]", $REGISTRY_FILE_ENCODING)) Next ; Close file FileClose($hOutfile) EndFunc ;==>_WritePolFile