Set a local server policy.

    Args:

        computer_policy (dict):
            A dictionary of "policyname: value" pairs of computer policies to
            set. 'value' should be how it is displayed in the gpedit GUI, i.e.
            if a setting can be 'Enabled'/'Disabled', then that should be passed

            Administrative Template data may require dicts within dicts, to
            specify each element of the Administrative Template policy.
            Administrative Templates policies are always cumulative.

            Policy names can be specified in a number of ways based on the type
            of policy:

                Windows Settings Policies:

                    These policies can be specified using the GUI display name
                    or the key name from the _policy_info class in this module.
                    The GUI display name is also contained in the _policy_info
                    class in this module.

                Administrative Template Policies:

                    These can be specified using the policy name as displayed in
                    the GUI (case sensitive). Some policies have the same name,
                    but a different location (for example, "Access data sources
                    across domains"). These can be differentiated by the "path"
                    in the GUI (for example, "Windows Components\\Internet
                    Explorer\\Internet Control Panel\\Security Page\\Internet
                    Zone\\Access data sources across domains").

                    Additionally, policies can be specified using the "name" and
                    "id" attributes from the ADMX files.

                    For Administrative Templates that have policy elements, each
                    element can be specified using the text string as seen in
                    the GUI or using the ID attribute from the ADMX file. Due to
                    the way some of the GUI text is laid out, some policy
                    element names could include descriptive text that appears
                    lbefore the policy element in the GUI.

                    Use the get_policy_info function for the policy name to view
                    the element ID/names that the module will accept.

        user_policy (dict):
            The same setup as the computer_policy, except with data to configure
            the local user policy.

        cumulative_rights_assignments (bool):
            Determine how user rights assignment policies are configured.

            If True, user right assignment specifications are simply added to
            the existing policy

            If False, only the users specified will get the right (any existing
            will have the right revoked)

        adml_language (str):
            The language files to use for looking up Administrative Template
            policy data (i.e. how the policy is displayed in the GUI). Defaults
            to 'en-US' (U.S. English).

    Returns:
        bool: True is successful, otherwise False

    CLI Example:

    .. code-block:: bash

        salt '*' lgpo.set computer_policy="{'LockoutDuration': 2, 'RestrictAnonymous': 'Enabled', 'AuditProcessTracking': 'Succes, Failure'}"

def set_(computer_policy=None,
         user_policy=None,
         cumulative_rights_assignments=True,
         adml_language='en-US'):
    '''
    Set a local server policy.

    Args:

        computer_policy (dict):
            A dictionary of "policyname: value" pairs of computer policies to
            set. 'value' should be how it is displayed in the gpedit GUI, i.e.
            if a setting can be 'Enabled'/'Disabled', then that should be passed

            Administrative Template data may require dicts within dicts, to
            specify each element of the Administrative Template policy.
            Administrative Templates policies are always cumulative.

            Policy names can be specified in a number of ways based on the type
            of policy:

                Windows Settings Policies:

                    These policies can be specified using the GUI display name
                    or the key name from the _policy_info class in this module.
                    The GUI display name is also contained in the _policy_info
                    class in this module.

                Administrative Template Policies:

                    These can be specified using the policy name as displayed in
                    the GUI (case sensitive). Some policies have the same name,
                    but a different location (for example, "Access data sources
                    across domains"). These can be differentiated by the "path"
                    in the GUI (for example, "Windows Components\\Internet
                    Explorer\\Internet Control Panel\\Security Page\\Internet
                    Zone\\Access data sources across domains").

                    Additionally, policies can be specified using the "name" and
                    "id" attributes from the ADMX files.

                    For Administrative Templates that have policy elements, each
                    element can be specified using the text string as seen in
                    the GUI or using the ID attribute from the ADMX file. Due to
                    the way some of the GUI text is laid out, some policy
                    element names could include descriptive text that appears
                    lbefore the policy element in the GUI.

                    Use the get_policy_info function for the policy name to view
                    the element ID/names that the module will accept.

        user_policy (dict):
            The same setup as the computer_policy, except with data to configure
            the local user policy.

        cumulative_rights_assignments (bool):
            Determine how user rights assignment policies are configured.

            If True, user right assignment specifications are simply added to
            the existing policy

            If False, only the users specified will get the right (any existing
            will have the right revoked)

        adml_language (str):
            The language files to use for looking up Administrative Template
            policy data (i.e. how the policy is displayed in the GUI). Defaults
            to 'en-US' (U.S. English).

    Returns:
        bool: True is successful, otherwise False

    CLI Example:

    .. code-block:: bash

        salt '*' lgpo.set computer_policy="{'LockoutDuration': 2, 'RestrictAnonymous': 'Enabled', 'AuditProcessTracking': 'Succes, Failure'}"
    '''

    if computer_policy and not isinstance(computer_policy, dict):
        msg = 'computer_policy must be specified as a dict'
        raise SaltInvocationError(msg)
    if user_policy and not isinstance(user_policy, dict):
        msg = 'user_policy must be specified as a dict'
        raise SaltInvocationError(msg)
    policies = {}
    policies['User'] = user_policy
    policies['Machine'] = computer_policy
    if policies:
        adml_policy_resources = _get_policy_resources(language=adml_language)
        for p_class in policies:
            _secedits = {}
            _netshs = {}
            _advaudits = {}
            _modal_sets = {}
            _admTemplateData = {}
            _regedits = {}
            _lsarights = {}
            _policydata = _policy_info()
            if policies[p_class]:
                for policy_name in policies[p_class]:
                    _pol = None
                    policy_key_name = policy_name
                    if policy_name in _policydata.policies[p_class]['policies']:
                        _pol = _policydata.policies[p_class]['policies'][policy_name]
                    else:
                        for policy in _policydata.policies[p_class]['policies']:
                            if _policydata.policies[p_class]['policies'][policy]['Policy'].upper() == \
                                    policy_name.upper():
                                _pol = _policydata.policies[p_class]['policies'][policy]
                                policy_key_name = policy
                    if _pol:
                        # transform and validate the setting
                        _value = _transform_value(
                            value=policies[p_class][policy_name],
                            policy=_policydata.policies[p_class]['policies'][policy_key_name],
                            transform_type='Put')
                        if not _validateSetting(
                                value=_value,
                                policy=_policydata.policies[p_class]['policies'][policy_key_name]):
                            msg = 'The specified value {0} is not an acceptable setting for policy {1}.'
                            raise SaltInvocationError(msg.format(policies[p_class][policy_name], policy_name))
                        if 'Registry' in _pol:
                            # set value in registry
                            log.debug('%s is a registry policy', policy_name)
                            _regedits[policy_name] = {'policy': _pol, 'value': _value}
                        elif 'Secedit' in _pol:
                            # set value with secedit
                            log.debug('%s is a Secedit policy', policy_name)
                            if _pol['Secedit']['Section'] not in _secedits:
                                _secedits[_pol['Secedit']['Section']] = []
                            _secedits[_pol['Secedit']['Section']].append(
                                    ' '.join([_pol['Secedit']['Option'],
                                             '=', six.text_type(_value)]))
                        elif 'NetSH' in _pol:
                            # set value with netsh
                            log.debug('%s is a NetSH policy', policy_name)
                            _netshs.setdefault(policy_name, {
                                'profile': _pol['NetSH']['Profile'],
                                'section': _pol['NetSH']['Section'],
                                'option': _pol['NetSH']['Option'],
                                'value': six.text_type(_value)
                            })
                        elif 'AdvAudit' in _pol:
                            # set value with advaudit
                            _advaudits.setdefault(policy_name, {
                                'option': _pol['AdvAudit']['Option'],
                                'value': six.text_type(_value)
                            })
                        elif 'NetUserModal' in _pol:
                            # set value via NetUserModal
                            log.debug('%s is a NetUserModal policy', policy_name)
                            if _pol['NetUserModal']['Modal'] not in _modal_sets:
                                _modal_sets[_pol['NetUserModal']['Modal']] = {}
                            _modal_sets[_pol['NetUserModal']['Modal']][_pol['NetUserModal']['Option']] = _value
                        elif 'LsaRights' in _pol:
                            log.debug('%s is a LsaRights policy', policy_name)
                            _lsarights[policy_name] = {'policy': _pol, 'value': _value}
                    else:
                        _value = policies[p_class][policy_name]
                        log.debug('searching for "%s" in admx data', policy_name)
                        success, the_policy, policy_name_list, msg = _lookup_admin_template(
                                policy_name=policy_name,
                                policy_class=p_class,
                                adml_language=adml_language)
                        if success:
                            policy_name = the_policy.attrib['name']
                            policy_namespace = the_policy.nsmap[the_policy.prefix]
                            if policy_namespace not in _admTemplateData:
                                _admTemplateData[policy_namespace] = {}
                            _admTemplateData[policy_namespace][policy_name] = _value
                        else:
                            raise SaltInvocationError(msg)
                        if policy_namespace and policy_name in _admTemplateData[policy_namespace] and the_policy is not None:
                            log.debug('setting == %s', six.text_type(_admTemplateData[policy_namespace][policy_name]).lower())
                            log.debug(six.text_type(_admTemplateData[policy_namespace][policy_name]).lower())
                            if six.text_type(_admTemplateData[policy_namespace][policy_name]).lower() != 'disabled' \
                                    and six.text_type(_admTemplateData[policy_namespace][policy_name]).lower() != 'not configured':
                                if ELEMENTS_XPATH(the_policy):
                                    if isinstance(_admTemplateData[policy_namespace][policy_name], dict):
                                        for elements_item in ELEMENTS_XPATH(the_policy):
                                            for child_item in elements_item.getchildren():
                                                # check each element
                                                log.debug('checking element %s', child_item.attrib['id'])
                                                temp_element_name = None
                                                this_element_name = _getFullPolicyName(
                                                    policy_item=child_item,
                                                    policy_name=child_item.attrib['id'],
                                                    return_full_policy_names=True,
                                                    adml_language=adml_language)
                                                log.debug('id attribute == "%s"  this_element_name == "%s"', child_item.attrib['id'], this_element_name)
                                                if this_element_name in _admTemplateData[policy_namespace][policy_name]:
                                                    temp_element_name = this_element_name
                                                elif child_item.attrib['id'] in _admTemplateData[policy_namespace][policy_name]:
                                                    temp_element_name = child_item.attrib['id']
                                                else:
                                                    msg = ('Element "{0}" must be included'
                                                           ' in the policy configuration for policy {1}')
                                                    raise SaltInvocationError(msg.format(this_element_name, policy_name))
                                                if 'required' in child_item.attrib \
                                                        and child_item.attrib['required'].lower() == 'true':
                                                    if not _admTemplateData[policy_namespace][policy_name][temp_element_name]:
                                                        msg = 'Element "{0}" requires a value to be specified'
                                                        raise SaltInvocationError(msg.format(temp_element_name))
                                                if etree.QName(child_item).localname == 'boolean':
                                                    if not isinstance(
                                                            _admTemplateData[policy_namespace][policy_name][temp_element_name],
                                                            bool):
                                                        msg = 'Element {0} requires a boolean True or False'
                                                        raise SaltInvocationError(msg.format(temp_element_name))
                                                elif etree.QName(child_item).localname == 'decimal' or \
                                                        etree.QName(child_item).localname == 'longDecimal':
                                                    min_val = 0
                                                    max_val = 9999
                                                    if 'minValue' in child_item.attrib:
                                                        min_val = int(child_item.attrib['minValue'])
                                                    if 'maxValue' in child_item.attrib:
                                                        max_val = int(child_item.attrib['maxValue'])
                                                    if int(_admTemplateData[policy_namespace][policy_name][temp_element_name]) \
                                                            < min_val or \
                                                            int(_admTemplateData[policy_namespace][policy_name][temp_element_name]) \
                                                            > max_val:
                                                        msg = 'Element "{0}" value must be between {1} and {2}'
                                                        raise SaltInvocationError(msg.format(temp_element_name,
                                                                                             min_val,
                                                                                             max_val))
                                                elif etree.QName(child_item).localname == 'enum':
                                                    # make sure the value is in the enumeration
                                                    found = False
                                                    for enum_item in child_item.getchildren():
                                                        if _admTemplateData[policy_namespace][policy_name][temp_element_name] == \
                                                                _getAdmlDisplayName(
                                                                adml_policy_resources,
                                                                enum_item.attrib['displayName']).strip():
                                                            found = True
                                                            break
                                                    if not found:
                                                        msg = 'Element "{0}" does not have a valid value'
                                                        raise SaltInvocationError(msg.format(temp_element_name))
                                                elif etree.QName(child_item).localname == 'list':
                                                    if 'explicitValue' in child_item.attrib \
                                                                and child_item.attrib['explicitValue'].lower() == \
                                                                'true':
                                                        if not isinstance(
                                                                _admTemplateData[policy_namespace][policy_name][temp_element_name],
                                                                dict):
                                                            msg = ('Each list item of element "{0}" '
                                                                   'requires a dict value')
                                                            msg = msg.format(temp_element_name)
                                                            raise SaltInvocationError(msg)
                                                    elif not isinstance(
                                                            _admTemplateData[policy_namespace][policy_name][temp_element_name],
                                                            list):
                                                        msg = 'Element "{0}" requires a list value'
                                                        msg = msg.format(temp_element_name)
                                                        raise SaltInvocationError(msg)
                                                elif etree.QName(child_item).localname == 'multiText':
                                                    if not isinstance(
                                                            _admTemplateData[policy_namespace][policy_name][temp_element_name],
                                                            list):
                                                        msg = 'Element "{0}" requires a list value'
                                                        msg = msg.format(temp_element_name)
                                                        raise SaltInvocationError(msg)
                                                _admTemplateData[policy_namespace][policy_name][child_item.attrib['id']] = \
                                                    _admTemplateData[policy_namespace][policy_name].pop(temp_element_name)
                                    else:
                                        msg = 'The policy "{0}" has elements which must be configured'
                                        msg = msg.format(policy_name)
                                        raise SaltInvocationError(msg)
                                else:
                                    if six.text_type(_admTemplateData[policy_namespace][policy_name]).lower() != 'enabled':
                                        msg = ('The policy {0} must either be "Enabled", '
                                               '"Disabled", or "Not Configured"')
                                        msg = msg.format(policy_name)
                                        raise SaltInvocationError(msg)
                if _regedits:
                    for regedit in _regedits:
                        log.debug('%s is a Registry policy', regedit)
                        # if the value setting is None or "(value not set)", we will delete the value from the registry
                        if _regedits[regedit]['value'] is not None and _regedits[regedit]['value'] != '(value not set)':
                            _ret = __utils__['reg.set_value'](
                                    _regedits[regedit]['policy']['Registry']['Hive'],
                                    _regedits[regedit]['policy']['Registry']['Path'],
                                    _regedits[regedit]['policy']['Registry']['Value'],
                                    _regedits[regedit]['value'],
                                    _regedits[regedit]['policy']['Registry']['Type'])
                        else:
                            _ret = __utils__['reg.read_value'](
                                    _regedits[regedit]['policy']['Registry']['Hive'],
                                    _regedits[regedit]['policy']['Registry']['Path'],
                                    _regedits[regedit]['policy']['Registry']['Value'])
                            if _ret['success'] and _ret['vdata'] != '(value not set)':
                                _ret = __utils__['reg.delete_value'](
                                        _regedits[regedit]['policy']['Registry']['Hive'],
                                        _regedits[regedit]['policy']['Registry']['Path'],
                                        _regedits[regedit]['policy']['Registry']['Value'])
                        if not _ret:
                            msg = ('Error while attempting to set policy {0} via the registry.'
                                   '  Some changes may not be applied as expected')
                            raise CommandExecutionError(msg.format(regedit))
                if _lsarights:
                    for lsaright in _lsarights:
                        _existingUsers = None
                        if not cumulative_rights_assignments:
                            _existingUsers = _getRightsAssignments(
                                    _lsarights[lsaright]['policy']['LsaRights']['Option'])
                        if _lsarights[lsaright]['value']:
                            for acct in _lsarights[lsaright]['value']:
                                _ret = _addAccountRights(acct, _lsarights[lsaright]['policy']['LsaRights']['Option'])
                                if not _ret:
                                    msg = 'An error occurred attempting to configure the user right {0}.'
                                    raise SaltInvocationError(msg.format(lsaright))
                        if _existingUsers:
                            for acct in _existingUsers:
                                if acct not in _lsarights[lsaright]['value']:
                                    _ret = _delAccountRights(
                                            acct, _lsarights[lsaright]['policy']['LsaRights']['Option'])
                                    if not _ret:
                                        msg = ('An error occurred attempting to remove previously'
                                               'configured users with right {0}.')
                                        raise SaltInvocationError(msg.format(lsaright))
                if _secedits:
                    # we've got secedits to make
                    log.debug(_secedits)
                    ini_data = '\r\n'.join(['[Unicode]', 'Unicode=yes'])
                    _seceditSections = ['System Access', 'Event Audit', 'Registry Values', 'Privilege Rights']
                    for _seceditSection in _seceditSections:
                        if _seceditSection in _secedits:
                            ini_data = '\r\n'.join([ini_data, ''.join(['[', _seceditSection, ']']),
                                                   '\r\n'.join(_secedits[_seceditSection])])
                    ini_data = '\r\n'.join([ini_data, '[Version]',
                                            'signature="$CHICAGO$"',
                                            'Revision=1'])
                    log.debug('ini_data == %s', ini_data)
                    if not _write_secedit_data(ini_data):
                        msg = ('Error while attempting to set policies via '
                               'secedit. Some changes may not be applied as '
                               'expected')
                        raise CommandExecutionError(msg)
                if _netshs:
                    # we've got netsh settings to make
                    for setting in _netshs:
                        log.debug('Setting firewall policy: %s', setting)
                        log.debug(_netshs[setting])
                        _setOptionValueNetSH(**_netshs[setting])

                if _advaudits:
                    # We've got AdvAudit settings to make
                    for setting in _advaudits:
                        log.debug('Setting Advanced Audit policy: {0}'.format(setting))
                        log.debug(_advaudits[setting])
                        _setOptionValueAdvAudit(**_advaudits[setting])

                if _modal_sets:
                    # we've got modalsets to make
                    log.debug(_modal_sets)
                    for _modal_set in _modal_sets:
                        try:
                            _existingModalData = win32net.NetUserModalsGet(None, _modal_set)
                            _newModalSetData = dictupdate.update(_existingModalData, _modal_sets[_modal_set])
                            log.debug('NEW MODAL SET = %s', _newModalSetData)
                            _ret = win32net.NetUserModalsSet(None, _modal_set, _newModalSetData)
                        # TODO: This needs to be more specific
                        except Exception:
                            msg = 'An unhandled exception occurred while attempting to set policy via NetUserModalSet'
                            log.exception(msg)
                            raise CommandExecutionError(msg)
                if _admTemplateData:
                    _ret = False
                    log.debug('going to write some adm template data :: %s', _admTemplateData)
                    _ret = _writeAdminTemplateRegPolFile(_admTemplateData,
                                                         adml_language=adml_language,
                                                         registry_class=p_class)
                    if not _ret:
                        msg = ('Error while attempting to write Administrative Template Policy data.'
                               '  Some changes may not be applied as expected')
                        raise CommandExecutionError(msg)
        return True
    else:
        msg = 'You have to specify something!'
        raise SaltInvocationError(msg)