File manager - Edit - /opt/saltstack/salt/lib/python3.10/site-packages/salt/modules/win_lgpo_reg.py
Back
""" LGPO - Registry.pol =================== .. versionadded:: 3006.0 A module for working with registry based policies in Windows Local Group Policy (LGPO). This module contains functions for working with the ``Registry.pol`` file. The ``Registry.pol`` file is the source of truth for registry settings and LGPO. Group Policy is refreshed every 90 seconds by default. During that refresh the contents of the ``Registry.pol`` file are applied to the Registry. If the setting is changed outside of Group Policy to something other than what is contained in the ``Registry.pol`` file, it will be changed back during the next refresh. In the Group Policy Editor (``gpedit.msc``) these policies can be set to three states: - Not Configured - Enabled - Disabled A policy that is "Not Configured" does not have an entry in the ``Registry.pol`` file. A Group Policy refresh will not make any changes to key/value pairs in the registry that are not specified in the ``Registry.pol`` file. An "Enabled" policy will have an entry in the ``Registry.pol`` files that contains its key path, value name, value type, value size, and value data. When Group Policy is refreshed, existing values will be overwritten with those contained in the ``Registry.pol`` file. A "Disabled" policy will have an entry in the ``Registry.pol`` file with the key path and the value name, but the value name will be prepended with ``**del.``. When Group Policy is refreshed the key/value will be deleted from the registry. If the key contains no values, it will also be deleted. Working with LGPO Reg --------------------- The easiest way to figure out the values needed for this module is to set the policy using the Group Policy Editor (``gpedit.msc``) and then run the ``lgpo_reg.read_reg_pol`` function. This function will display a dictionary of all registry-based policies in the ``Registry.pol`` file. From its return you can get the ``key``, ``v_name``, ``v_type``, and ``v_data`` required to "enable" that policy. Use those values to set/disable/delete policies using this module. The same values can also be used to create states for setting these policies. .. note:: Not all policies in the Group Policy Editor (``gpedit.msc``) that write to the registry make that change in the ``Registry.pol`` file. Those policies could still be enforced via the ``Registry.pol`` file... theoretically. But you will have to find the values needed to set them with this module using a different method. """ import logging import salt.utils.platform import salt.utils.win_functions import salt.utils.win_lgpo_reg import salt.utils.win_reg import salt.utils.winapi from salt.exceptions import SaltInvocationError log = logging.getLogger(__name__) __virtualname__ = "lgpo_reg" LOCAL_POLICY_GPO_ID = "{00000000-0000-0000-0000-000000000000}" _RSOP_VALUE_TYPES = { 0: "REG_NONE", 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", 11: "REG_QWORD", } def __virtual__(): """ Only works on Windows """ if not salt.utils.platform.is_windows(): return False, "LGPO_REG Module: Only available on Windows" return __virtualname__ def _find_value(pol_data, key, v_name): """ Helper function to find the value in the registry.pol file. Sometimes the value is prepended by an action that needs to happen with that value, such as `**del.` to delete it from the registry. Returns: tuple: A tuple containing: found_key, found_name """ found_key = "" found_name = "" for p_key in pol_data: if key.lower() == p_key.lower(): found_key = p_key for p_name in pol_data[p_key]: if p_name.lower().startswith("**del."): if v_name.lower() == p_name.lower().split(".", 1)[1]: found_name = p_name else: if v_name.lower() == p_name.lower(): found_name = p_name return found_key, found_name def read_reg_pol(policy_class="Machine"): r""" Read the contents of the Registry.pol file. Display the contents as a human-readable dictionary. Args: policy_class (:obj:`str`, optional): The registry class to retrieve. Can be one of the following: - Computer - Machine - User Default is ``Machine``. Raises: SaltInvocationError: Invalid policy class Returns: dict: A dictionary representing the contents of the Registry.pol file CLI Example: .. code-block:: bash # Read the machine Registry.pol salt '*' lgpo_reg.read_reg_pol """ # Verify policy_class if policy_class.lower() in ["computer", "machine"]: policy_class = "Machine" elif policy_class.lower() in ["user"]: policy_class = "User" else: raise SaltInvocationError("An invalid policy class was specified") pol_info = salt.utils.win_lgpo_reg.CLASS_INFO[policy_class] pol_file_data = salt.utils.win_lgpo_reg.read_reg_pol_file( reg_pol_path=pol_info["policy_path"] ) return salt.utils.win_lgpo_reg.reg_pol_to_dict(pol_file_data) def write_reg_pol(data, policy_class="Machine"): r""" Write data to the Registry.pol file. The data is a dictionary that is then converted to the appropriate bytes format expected by Registry.pol Args: data (dict): A dictionary containing Registry.pol data policy_class (:obj:`str`, optional): The registry class to write to. Can be one of the following: - Computer - Machine - User Default is ``Machine``. Raises: SaltInvocationError: Invalid policy class CommandExecutionError: On failure Returns: bool: True if successful CLI Example: .. code-block:: bash # Write to Machine Registry.pol salt '*' lgpo_reg.write_reg_pol "{'SOFTWARE\MyKey': {'MyValue': 'data': 1, 'type': 'REG_DWORD'}}" """ # Maybe have this data passed instead of opening it here # Verify policy_class if policy_class.lower() in ["computer", "machine"]: policy_class = "Machine" elif policy_class.lower() in ["user"]: policy_class = "User" else: raise SaltInvocationError("An invalid policy class was specified") policy_class_info = salt.utils.win_lgpo_reg.CLASS_INFO[policy_class] policy_file_data = salt.utils.win_lgpo_reg.dict_to_reg_pol(data) return salt.utils.win_lgpo_reg.write_reg_pol_data( policy_file_data, policy_class_info["policy_path"], policy_class_info["gpt_extension_location"], policy_class_info["gpt_extension_guid"], ) def get_value(key, v_name, policy_class="Machine"): r""" Get the value of a single value pair as set in the ``Registry.pol`` file. Args: key (str): The registry key where the value name resides v_name (str): The value name to retrieve policy_class (:obj:`str`, optional): The registry class to read from. Can be one of the following: - Computer - Machine - User Default is ``Machine``. Raises: SaltInvocationError: Invalid policy class Returns: dict: A dictionary containing the value data and the value type found CLI Example: .. code-block:: bash # Get a value salt '*' lgpo_reg.get_value "SOFTWARE\MyKey" "MyValue" """ # Verify input if policy_class.lower() in ["computer", "machine"]: policy_class = "Machine" elif policy_class.lower() in ["user"]: policy_class = "User" else: raise SaltInvocationError("An invalid policy class was specified") pol_data = read_reg_pol(policy_class=policy_class) found_key, found_name = _find_value(pol_data, key, v_name) if found_key: if found_name: if "**del." in found_name: pol_data[found_key][found_name]["data"] = found_name return pol_data[found_key][found_name] return {} def get_key(key, policy_class="Machine"): r""" Get all the values set in a key in the ``Registry.pol`` file. Args: key (str): The registry key where the values reside policy_class (:obj:`str`, optional): The registry class to read from. Can be one of the following: - Computer - Machine - User Default is ``Machine``. Raises: SaltInvocationError: Invalid policy class Returns: dict: A dictionary containing the value data and the value type CLI Example: .. code-block:: bash # Get all values from a key salt '*' lgpo_reg.get_key "SOFTWARE\MyKey" """ # Verify input if policy_class.lower() in ["computer", "machine"]: policy_class = "Machine" elif policy_class.lower() in ["user"]: policy_class = "User" else: raise SaltInvocationError("An invalid policy class was specified") pol_data = read_reg_pol(policy_class=policy_class) found_key = "" for p_key in pol_data: if key.lower() == p_key.lower(): found_key = p_key if found_key: return pol_data[found_key] return {} def get_rsop_value(key, v_name): r""" Query the Resultant Set of Policy (RSoP) for a specific Machine registry key/value. Returns information about the winning Group Policy Object (GPO) for that value, including whether it is managed by a Domain GPO. .. note:: Only Machine (computer) policy is supported. User policy RSoP requires per-user SID scoping and a different WMI namespace, which is not practical when Salt runs as SYSTEM. Args: key (str): The registry key path v_name (str): The registry value name Returns: dict: A dictionary containing the RSoP information, or ``{}`` if the value is not found in RSoP, if the machine is not domain-joined, or if WMI is unavailable. Keys when a result is found: - key (str): The registry key path - name (str): The registry value name - data: The value data - type (str): The registry value type (e.g. ``REG_DWORD``) - gpo_id (str): The GUID of the winning GPO - gpo_name (str): The display name of the winning GPO - precedence (int): The policy precedence (1 = winning) - domain_managed (bool): ``True`` if managed by a Domain GPO CLI Example: .. code-block:: bash salt '*' lgpo_reg.get_rsop_value "SYSTEM\CurrentControlSet\Services\Netlogon\Parameters" VulnerableChannelAllowList """ try: import wmi except ImportError: log.debug("LGPO_REG Mod: wmi module not available, cannot query RSoP") return {} try: with salt.utils.winapi.Com(): conn = wmi.WMI(namespace="root\\rsop\\computer") wmi_key = key.replace("\\", "\\\\") results = conn.query( f"SELECT * FROM RSOP_RegistryPolicySetting " f"WHERE RegistryKey = '{wmi_key}' " f"AND ValueName = '{v_name}' " f"AND Precedence = 1" ) if not results: return {} setting = results[0] gpo_id = setting.GPOID gpo_name = gpo_id try: gpos = conn.query(f"SELECT * FROM RSOP_GPO WHERE ID = '{gpo_id}'") if gpos: gpo_name = gpos[0].Name except Exception: # pylint: disable=broad-exception-caught pass value_type_int = getattr(setting, "ValueType", None) value_type_str = _RSOP_VALUE_TYPES.get( value_type_int, f"REG_TYPE_{value_type_int}" ) return { "key": key, "name": v_name, "data": setting.Value, "type": value_type_str, "gpo_id": gpo_id, "gpo_name": gpo_name, "precedence": setting.Precedence, "domain_managed": gpo_id != LOCAL_POLICY_GPO_ID, } except Exception as exc: # pylint: disable=broad-exception-caught log.debug("LGPO_REG Mod: Failed to query RSoP: %s", exc) return {} def set_value( key, v_name, v_data, v_type="REG_DWORD", policy_class="Machine", write_registry=None, refresh_policy=False, ): r""" Add a key/value pair to the registry.pol file. This bypasses the admx/adml style policies. This is the equivalent of setting a policy to ``Enabled`` Args: key (str): The registry key path v_name (str): The registry value name within the key v_data(str): The registry value v_type (:obj:`str`, optional): The registry value type. Must be one of the following: - REG_BINARY - REG_DWORD - REG_EXPAND_SZ - REG_MULTI_SZ - REG_QWORD - REG_SZ Default is REG_DWORD. policy_class (:obj:`str`, optional): The registry class to write to. Can be one of the following: - Computer - Machine - User Default is ``Machine``. write_registry (:obj:`bool`, optional): Controls whether the value is also written to the live registry immediately after updating ``Registry.pol``. - ``None`` (default): auto-detect. Skips the registry write on Domain Controllers where ``HKLM\\SOFTWARE\\Policies\\`` is write-protected; writes directly on all other machine types. - ``True``: always write to the registry (non-DC behaviour). - ``False``: always skip the registry write; the Group Policy engine will commit the value on the next refresh. refresh_policy (:obj:`bool`, optional): When ``True``, trigger a native in-process Group Policy refresh via ``userenv.dll`` after successfully writing ``Registry.pol``. .. note:: The refresh is **asynchronous**. This call signals the Group Policy service to begin processing; it returns before processing is complete. Registry values will reflect the updated policy only after the service finishes its refresh cycle. Use :func:`get_rsop_value` to verify applied state. Default is ``False``. Raises: SaltInvocationError: Invalid policy_class SaltInvocationError: Invalid v_type SaltInvocationError: v_data doesn't match v_type Returns: bool: ``True`` if successful, otherwise ``False``. CLI Example: .. code-block:: bash # Set REG_DWORD value (default) salt '*' lgpo_reg.set_value "SOFTWARE\MyKey" "MyValue" 1 # Set REG_SZ value salt '*' lgpo_reg.set_value "SOFTWARE\MyKey" "MyValue" "string value" "REG_SZ" """ # Verify input if policy_class.lower() in ["computer", "machine"]: policy_class = "Machine" hive = "HKLM" elif policy_class.lower() in ["user"]: policy_class = "User" hive = "HKCU" else: raise SaltInvocationError("An invalid policy class was specified") v_type = v_type.upper() valid_types = [ "REG_BINARY", "REG_DWORD", "REG_EXPAND_SZ", "REG_MULTI_SZ", "REG_QWORD", "REG_SZ", ] if v_type not in valid_types: msg = f"Invalid type: {v_type}" raise SaltInvocationError(msg) if v_type in ["REG_SZ", "REG_EXPAND_SZ"]: if isinstance(v_data, int): v_data = str(v_data) if not isinstance(v_data, str): msg = f"{v_type} data must be a string" raise SaltInvocationError(msg) elif v_type == "REG_MULTI_SZ": if not isinstance(v_data, list): msg = f"{v_type} data must be a list" raise SaltInvocationError(msg) elif v_type in ["REG_DWORD", "REG_QWORD"]: try: int(v_data) except (TypeError, ValueError): msg = f"{v_type} data must be an integer" raise SaltInvocationError(msg) machine = policy_class == "Machine" with salt.utils.win_lgpo_reg._policy_lock(machine=machine): pol_data = read_reg_pol(policy_class=policy_class) found_key, found_name = _find_value(pol_data, key, v_name) if found_key: if found_name: if "**del." in found_name: log.debug("LGPO_REG Mod: Found disabled name: %s", found_name) pol_data[found_key][v_name] = pol_data[found_key].pop(found_name) found_name = v_name log.debug("LGPO_REG Mod: Updating value: %s", found_name) pol_data[found_key][found_name] = {"data": v_data, "type": v_type} else: log.debug("LGPO_REG Mod: Setting new value: %s", found_name) pol_data[found_key][v_name] = {"data": v_data, "type": v_type} else: log.debug("LGPO_REG Mod: Adding new key and value: %s", found_name) pol_data[key] = {v_name: {"data": v_data, "type": v_type}} success = True if not write_reg_pol(pol_data, policy_class=policy_class): log.error("LGPO_REG Mod: Failed to write registry.pol file") success = False # Resolve auto-detect: skip registry write on Domain Controllers where # HKLM\SOFTWARE\Policies\ is write-protected by AD security hardening. if write_registry is None: write_registry = not salt.utils.win_functions.is_domain_controller() # We only want to modify the actual registry value if this is machine policy. # The user policy will be applied by the user registry.pol when the user # logs in. Setting it here only sets it on the user running the salt minion, # most likely SYSTEM, which doesn't make sense here. if policy_class == "Machine" and write_registry: if not salt.utils.win_reg.set_value( hive=hive, key=key, vname=v_name, vdata=v_data, vtype=v_type, ): log.error("LGPO_REG Mod: Failed to set registry entry") success = False if success and refresh_policy: if not salt.utils.win_lgpo_reg.refresh_policy(): log.warning( "LGPO_REG Mod: Group Policy refresh did not complete successfully" ) if success and policy_class == "Machine": rsop = get_rsop_value(key=key, v_name=v_name) if rsop.get("domain_managed"): log.warning( "LGPO_REG Mod: '%s\\%s' is managed by Domain GPO '%s'. " "Changes may be overridden on the next Group Policy refresh.", key, v_name, rsop.get("gpo_name", rsop.get("gpo_id")), ) return success def disable_value( key, v_name, policy_class="machine", write_registry=None, refresh_policy=False, ): r""" Mark a registry value for deletion in the registry.pol file. This bypasses the admx/adml style policies. This is the equivalent of setting the policy to ``Disabled`` in the Group Policy editor (``gpedit.msc``) Args: key (str): The registry key path v_name (str): The registry value name within the key policy_class (:obj:`str`, optional): The registry class to write to. Can be one of the following: - Computer - Machine - User Default is ``Machine``. write_registry (:obj:`bool`, optional): Controls whether the registry value is also deleted immediately after updating ``Registry.pol``. - ``None`` (default): auto-detect. Skips the registry delete on Domain Controllers; deletes directly on all other machine types. - ``True``: always delete from the registry (non-DC behaviour). - ``False``: always skip the registry delete; the Group Policy engine will remove the value on the next refresh. refresh_policy (:obj:`bool`, optional): When ``True``, trigger a native in-process Group Policy refresh via ``userenv.dll`` after successfully writing ``Registry.pol``. .. note:: The refresh is **asynchronous**. This call signals the Group Policy service to begin processing; it returns before processing is complete. Registry values will reflect the updated policy only after the service finishes its refresh cycle. Use :func:`get_rsop_value` to verify applied state. Default is ``False``. Raises: SaltInvocationError: Invalid policy_class CommandExecutionError: On failure Returns: bool: ``True`` if successful, otherwise ``False`` None: If already disabled CLI Example: .. code-block:: bash # Delete a value salt '*' lgpo_reg.delete_value "SOFTWARE\MyKey" "MyValue" """ # Verify input if policy_class.lower() in ["computer", "machine"]: policy_class = "Machine" hive = "HKLM" elif policy_class.lower() in ["user"]: policy_class = "User" hive = "HKCU" else: raise SaltInvocationError("An invalid policy class was specified") machine = policy_class == "Machine" with salt.utils.win_lgpo_reg._policy_lock(machine=machine): pol_data = read_reg_pol(policy_class=policy_class) found_key, found_name = _find_value(pol_data, key, v_name) pol_modified = False if found_key: if found_name: if "**del." in found_name: log.debug("LGPO_REG Mod: Already disabled: %s", v_name) else: log.debug("LGPO_REG Mod: Disabling value name: %s", v_name) pol_data[found_key].pop(found_name) found_name = f"**del.{found_name}" pol_data[found_key][found_name] = {"data": " ", "type": "REG_SZ"} pol_modified = True else: log.debug("LGPO_REG Mod: Setting new disabled value name: %s", v_name) pol_data[found_key][f"**del.{v_name}"] = { "data": " ", "type": "REG_SZ", } pol_modified = True else: log.debug( "LGPO_REG Mod: Adding new key and disabled value name: %s", found_name ) pol_data[key] = {f"**del.{v_name}": {"data": " ", "type": "REG_SZ"}} pol_modified = True success = True if pol_modified: if not write_reg_pol(pol_data, policy_class=policy_class): log.error("LGPO_REG Mod: Failed to write registry.pol file") success = False # Resolve auto-detect: skip registry delete on Domain Controllers. if write_registry is None: write_registry = not salt.utils.win_functions.is_domain_controller() # We only want to modify the actual registry value if this is machine policy. # The user policy will be applied by the user registry.pol when the user # logs in. Setting it here only sets it on the user running the salt minion, # most likely SYSTEM, which doesn't make sense here. reg_ret = None if policy_class == "Machine" and write_registry: reg_ret = salt.utils.win_reg.delete_value(hive=hive, key=key, vname=v_name) if not reg_ret: if reg_ret is None: log.debug("LGPO_REG Mod: Registry key/value already missing") else: log.error("LGPO_REG Mod: Failed to remove registry entry") success = False # Return None only when pol was already disabled and registry was already absent if not pol_modified and reg_ret is None: return None if success and refresh_policy: if not salt.utils.win_lgpo_reg.refresh_policy(): log.warning( "LGPO_REG Mod: Group Policy refresh did not complete successfully" ) if success and policy_class == "Machine": rsop = get_rsop_value(key=key, v_name=v_name) if rsop.get("domain_managed"): log.warning( "LGPO_REG Mod: '%s\\%s' is managed by Domain GPO '%s'. " "Changes may be overridden on the next Group Policy refresh.", key, v_name, rsop.get("gpo_name", rsop.get("gpo_id")), ) return success def delete_value( key, v_name, policy_class="Machine", write_registry=None, refresh_policy=False, ): r""" Delete a key/value pair from the Registry.pol file. This bypasses the admx/adml style policies. This is the equivalent of setting the policy to ``Not Configured``. Args: key (str): The registry key path v_name (str): The registry value name within the key policy_class (:obj:`str`, optional): The registry class to write to. Can be one of the following: - Computer - Machine - User Default is ``Machine``. write_registry (:obj:`bool`, optional): Controls whether the registry value is also deleted immediately after updating ``Registry.pol``. - ``None`` (default): auto-detect. Skips the registry delete on Domain Controllers; deletes directly on all other machine types. - ``True``: always delete from the registry (non-DC behaviour). - ``False``: always skip the registry delete; the Group Policy engine will remove the value on the next refresh. refresh_policy (:obj:`bool`, optional): When ``True``, trigger a native in-process Group Policy refresh via ``userenv.dll`` after successfully writing ``Registry.pol``. .. note:: The refresh is **asynchronous**. This call signals the Group Policy service to begin processing; it returns before processing is complete. Registry values will reflect the updated policy only after the service finishes its refresh cycle. Use :func:`get_rsop_value` to verify applied state. Default is ``False``. Raises: SaltInvocationError: Invalid policy_class CommandExecutionError: On failure Returns: bool: ``True`` if successful, otherwise ``False`` None: Key/value not present CLI Example: .. code-block:: bash # Delete all values under a key salt '*' lgpo_reg.delete_value "SOFTWARE\MyKey" "MyValue" """ # Verify input if policy_class.lower() in ["computer", "machine"]: policy_class = "Machine" hive = "HKLM" elif policy_class.lower() in ["user"]: policy_class = "User" hive = "HKCU" else: raise SaltInvocationError("An invalid policy class was specified") machine = policy_class == "Machine" with salt.utils.win_lgpo_reg._policy_lock(machine=machine): pol_data = read_reg_pol(policy_class=policy_class) found_key, found_name = _find_value(pol_data, key, v_name) pol_modified = False if found_key: if found_name: log.debug("LGPO_REG Mod: Removing value name: %s", found_name) pol_data[found_key].pop(found_name) pol_modified = True if len(pol_data[found_key]) == 0: log.debug("LGPO_REG Mod: Removing empty key: %s", found_key) pol_data.pop(found_key) else: log.debug("LGPO_REG Mod: Value name not found: %s", v_name) else: log.debug("LGPO_REG Mod: Key not found: %s", key) success = True if pol_modified: if not write_reg_pol(pol_data, policy_class=policy_class): log.error("LGPO_REG Mod: Failed to write registry.pol file") success = False # Resolve auto-detect: skip registry delete on Domain Controllers. if write_registry is None: write_registry = not salt.utils.win_functions.is_domain_controller() # We only want to modify the actual registry value if this is machine policy. # The user policy will be applied by the user registry.pol when the user # logs in. Setting it here only sets it on the user running the salt minion, # most likely SYSTEM, which doesn't make sense here. reg_ret = None if policy_class == "Machine" and write_registry: reg_ret = salt.utils.win_reg.delete_value(hive=hive, key=key, vname=v_name) if not reg_ret: if reg_ret is None: log.debug("LGPO_REG Mod: Registry key/value already missing") else: log.error("LGPO_REG Mod: Failed to remove registry entry") success = False # Return None only when there was nothing to do in either pol or registry if not pol_modified and reg_ret is None: return None if success and refresh_policy: if not salt.utils.win_lgpo_reg.refresh_policy(): log.warning( "LGPO_REG Mod: Group Policy refresh did not complete successfully" ) if success and policy_class == "Machine": rsop = get_rsop_value(key=key, v_name=v_name) if rsop.get("domain_managed"): log.warning( "LGPO_REG Mod: '%s\\%s' is managed by Domain GPO '%s'. " "Changes may be overridden on the next Group Policy refresh.", key, v_name, rsop.get("gpo_name", rsop.get("gpo_id")), ) return success def refresh_policy(): r""" Trigger a native in-process Machine Group Policy refresh. Delegates to :func:`salt.utils.win_lgpo_reg.refresh_policy`. Use this after a batch of ``set_value`` / ``disable_value`` calls made with ``refresh_policy=False`` to commit all policy changes in a single pass. .. note:: This call is **asynchronous**. It signals the Group Policy service to begin processing the local ``Registry.pol`` file, but returns before that processing is complete. Registry values will reflect the updated policy only after the service finishes its refresh cycle. Use :func:`get_rsop_value` to verify the applied state after the refresh has had time to complete. Returns: bool: ``True`` if the refresh signal was accepted successfully CLI Example: .. code-block:: bash salt '*' lgpo_reg.refresh_policy """ return salt.utils.win_lgpo_reg.refresh_policy() # This is for testing different settings and verifying that we are writing the # values correctly # def test(): # pol_info = salt.utils.win_lgpo_reg.CLASS_INFO["Machine"] # reg_data = salt.utils.win_lgpo_reg.read_reg_pol_file(reg_pol_path=pol_info["policy_path"]) # print(reg_data) # dict_data = salt.utils.win_lgpo_reg.reg_pol_to_dict(reg_data) # print(salt.utils.win_lgpo_reg.dict_to_reg_pol(dict_data))
| ver. 1.4 |
Github
|
.
| PHP 8.2.30 | Generation time: 0 |
proxy
|
phpinfo
|
Settings