# -*- coding: utf-8 -*- # Import Python libs from __future__ import absolute_import, print_function, unicode_literals import os import re import io import logging import pytest # Import Salt Testing libs from tests.support.case import ModuleCase from tests.support.unit import skipIf from tests.support.helpers import generate_random_name from tests.support.runtests import RUNTIME_VARS # Import Salt libs import salt.utils.files import salt.utils.platform import salt.utils.win_reg as reg log = logging.getLogger(__name__) @skipIf(not salt.utils.platform.is_windows(), 'windows test only') class WinLgpoTest(ModuleCase): ''' Tests for salt.modules.win_lgpo ''' osrelease = None def _testRegistryPolicy(self, policy_name, policy_config, registry_value_hive, registry_value_path, registry_value_vname, expected_value_data): ''' Takes a registry based policy name and config and validates that the expected registry value exists and has the correct data policy_name name of the registry based policy to configure policy_config the configuration of the policy registry_value_hive the registry hive that the policy registry path is in registry_value_path the registry value path that the policy updates registry_value_vname the registry value name expected_value_data the expected data that the value will contain ''' ret = self.run_function('lgpo.set_computer_policy', (policy_name, policy_config)) self.assertTrue(ret) val = reg.read_value( registry_value_hive, registry_value_path, registry_value_vname) self.assertTrue(val['success'], msg='Failed to obtain the registry data for policy {0}'.format(policy_name)) if val['success']: self.assertEqual(val['vdata'], expected_value_data, 'The registry value data {0} does not match the expected value {1} for policy {2}'.format( val['vdata'], expected_value_data, policy_name)) def _testSeceditPolicy(self, policy_name, policy_config, expected_regexes, cumulative_rights_assignments=True): ''' Takes a secedit policy name and config and validates that the expected output is returned from secedit policy_name name of the secedit policy to configure policy_config the configuration of the policy expected_regexes the expected regexes to be found in the secedit output file ''' ret = self.run_function('lgpo.set_computer_policy', (policy_name, policy_config), cumulative_rights_assignments=cumulative_rights_assignments) self.assertTrue(ret) secedit_output_file = os.path.join(RUNTIME_VARS.TMP, generate_random_name('secedit-output-')) secedit_output = self.run_function( 'cmd.run', (), cmd='secedit /export /cfg {0}'.format(secedit_output_file)) secedit_file_content = None if secedit_output: with io.open(secedit_output_file, encoding='utf-16') as _reader: secedit_file_content = _reader.read() for expected_regex in expected_regexes: match = re.search( expected_regex, secedit_file_content, re.IGNORECASE | re.MULTILINE) self.assertIsNotNone(match, 'Failed validating policy "{0}" configuration, regex "{1}" not found in secedit output'.format(policy_name, expected_regex)) def _testAdmxPolicy(self, policy_name, policy_config, expected_regexes, assert_true=True, policy_class='Machine'): ''' Takes a ADMX policy name and config and validates that the expected output is returned from lgpo looking at the Registry.pol file policy_name name of the ADMX policy to configure policy_config the configuration of the policy expected_regexes the expected regexes to be found in the lgpo parse output assert_true set to false if expecting the module run to fail policy_class the policy class this policy belongs to, either Machine or User ''' lgpo_function = 'set_computer_policy' lgpo_class = '/m' lgpo_folder = 'Machine' if policy_class.lower() == 'user': lgpo_function = 'set_user_policy' lgpo_class = '/u' lgpo_folder = 'User' ret = self.run_function('lgpo.{0}'.format(lgpo_function), (policy_name, policy_config)) log.debug('lgpo set_computer_policy ret == %s', ret) cmd = ['lgpo.exe', '/parse', lgpo_class, r'c:\Windows\System32\GroupPolicy\{}\Registry.pol'.format(lgpo_folder)] if assert_true: self.assertTrue(ret) lgpo_output = self.run_function('cmd.run', (), cmd=' '.join(cmd)) # validate that the lgpo output doesn't say the format is invalid self.assertIsNone( re.search(r'Invalid file format\.', lgpo_output, re.IGNORECASE), msg='Failed validating Registry.pol file format') # validate that the regexes we expect are in the output for expected_regex in expected_regexes: match = re.search(expected_regex, lgpo_output, re.IGNORECASE) self.assertIsNotNone( match, msg='Failed validating policy "{0}" configuration, regex ' '"{1}" not found in lgpo output:\n{2}' ''.format(policy_name, expected_regex, lgpo_output)) else: # expecting it to fail self.assertNotEqual(ret, True) def runTest(self): ''' runTest method ''' pass @classmethod def setUpClass(cls): ''' class setup function, only runs once downloads and extracts the lgpo.exe tool into c:/windows/system32 for use in validating the registry.pol files gets osrelease grain for tests that are only applicable to certain windows versions ''' osrelease_grains = cls().run_function('grains.item', ['osrelease']) if 'osrelease' in osrelease_grains: cls.osrelease = osrelease_grains['osrelease'] else: log.debug('Unable to get osrelease grain') if not os.path.exists(r'c:\windows\system32\lgpo.exe'): log.debug('lgpo.exe does not exist, attempting to download/extract') ret = cls().run_function('state.single', ('archive.extracted', r'c:\windows\system32'), source='https://download.microsoft.com/download/8/5/C/85C25433-A1B0-4FFA-9429-7E023E7DA8D8/LGPO.zip', archive_format='zip', source_hash='sha256=6ffb6416366652993c992280e29faea3507b5b5aa661c33ba1af31f48acea9c4', enforce_toplevel=False) log.debug('ret from archive.unzip == %s', ret) @pytest.mark.destructive_test def test_set_user_policy_point_and_print_restrictions(self): ''' Test setting/unsetting/changing the PointAndPrint_Restrictions user policy ''' # Disable Point and Print Restrictions self._testAdmxPolicy( r'Control Panel\Printers\Point and Print Restrictions', 'Disabled', [ r'User[\s]*Software\\Policies\\Microsoft\\Windows NT\\Printers\\PointAndPrint[\s]*Restricted[\s]*DWORD:0', r'User[\s]*Software\\Policies\\Microsoft\\Windows NT\\Printers\\PointAndPrint[\s]*TrustedServers[\s]*DELETE', r'User[\s]*Software\\Policies\\Microsoft\\Windows NT\\Printers\\PointAndPrint[\s]*ServerList[\s]*DELETE', r'User[\s]*Software\\Policies\\Microsoft\\Windows NT\\Printers\\PointAndPrint[\s]*InForest[\s]*DELETE', r'User[\s]*Software\\Policies\\Microsoft\\Windows NT\\Printers\\PointAndPrint[\s]*NoWarningNoElevationOnInstall[\s]*DELETE', r'User[\s]*Software\\Policies\\Microsoft\\Windows NT\\Printers\\PointAndPrint[\s]*UpdatePromptSettings[\s]*DELETE', ], policy_class='User') # Enable Point and Print Restrictions self._testAdmxPolicy( r'Control Panel\Printers\Point and Print Restrictions', { 'Users can only point and print to these servers': True, 'Enter fully qualified server names separated by semicolons': 'fakeserver1;fakeserver2', 'Users can only point and print to machines in their forest': True, 'Security Prompts: When installing drivers for a new connection': 'Show warning and elevation prompt', 'When updating drivers for an existing connection': 'Do not show warning or elevation prompt', }, [ r'User[\s]*Software\\Policies\\Microsoft\\Windows NT\\Printers\\PointAndPrint[\s]*Restricted[\s]*DWORD:1', r'User[\s]*Software\\Policies\\Microsoft\\Windows NT\\Printers\\PointAndPrint[\s]*TrustedServers[\s]*DWORD:1', r'User[\s]*Software\\Policies\\Microsoft\\Windows NT\\Printers\\PointAndPrint[\s]*ServerList[\s]*SZ:fakeserver1;fakeserver2', r'User[\s]*Software\\Policies\\Microsoft\\Windows NT\\Printers\\PointAndPrint[\s]*InForest[\s]*DWORD:1', r'User[\s]*Software\\Policies\\Microsoft\\Windows NT\\Printers\\PointAndPrint[\s]*NoWarningNoElevationOnInstall[\s]*DWORD:0', r'User[\s]*Software\\Policies\\Microsoft\\Windows NT\\Printers\\PointAndPrint[\s]*UpdatePromptSettings[\s]*DWORD:2', ], policy_class='User') # set Point and Print Restrictions to 'Not Configured' self._testAdmxPolicy( r'Control Panel\Printers\Point and Print Restrictions', 'Not Configured', [ r'; Source file: c:\\windows\\system32\\grouppolicy\\user\\registry.pol[\s]*; PARSING COMPLETED.'], policy_class='User') @pytest.mark.destructive_test def test_set_computer_policy_NTP_Client(self): ''' Test setting/unsetting/changing NTP Client policies ''' # Disable Configure NTP Client self._testAdmxPolicy(r'System\Windows Time Service\Time Providers\Configure Windows NTP Client', 'Disabled', [ r'Computer[\s]*Software\\Policies\\Microsoft\\W32time\\Parameters[\s]*NtpServer[\s]*DELETE', r'Computer[\s]*Software\\Policies\\Microsoft\\W32time\\Parameters[\s]*Type[\s]*DELETE', r'Computer[\s]*Software\\Policies\\Microsoft\\W32time\\TimeProviders\\NtpClient[\s]*CrossSiteSyncFlags[\s]*DELETE', r'Computer[\s]*Software\\Policies\\Microsoft\\W32time\\TimeProviders\\NtpClient[\s]*ResolvePeerBackoffMinutes[\s]*DELETE', r'Computer[\s]*Software\\Policies\\Microsoft\\W32time\\TimeProviders\\NtpClient[\s]*ResolvePeerBackoffMaxTimes[\s]*DELETE', r'Computer[\s]*Software\\Policies\\Microsoft\\W32time\\TimeProviders\\NtpClient[\s]*SpecialPollInterval[\s]*DELETE', r'Computer[\s]*Software\\Policies\\Microsoft\\W32time\\TimeProviders\\NtpClient[\s]*EventLogFlags[\s]*DELETE' ]) # Enable Configure NTP Client self._testAdmxPolicy(r'System\Windows Time Service\Time Providers\Configure Windows NTP Client', { 'NtpServer': 'time.windows.com,0x9', 'Type': 'NT5DS', 'CrossSiteSyncFlags': 2, 'ResolvePeerBackoffMinutes': 15, 'ResolvePeerBackoffMaxTimes': 7, 'W32TIME_SpecialPollInterval': 3600, 'W32TIME_NtpClientEventLogFlags': 0 }, [ r'Computer[\s]*Software\\Policies\\Microsoft\\W32time\\Parameters[\s]*NtpServer[\s]*SZ:time.windows.com,0x9', r'Computer[\s]*Software\\Policies\\Microsoft\\W32time\\Parameters[\s]*Type[\s]*SZ:NT5DS', r'Computer[\s]*Software\\Policies\\Microsoft\\W32time\\TimeProviders\\NtpClient[\s]*CrossSiteSyncFlags[\s]*DWORD:2', r'Computer[\s]*Software\\Policies\\Microsoft\\W32time\\TimeProviders\\NtpClient[\s]*ResolvePeerBackoffMinutes[\s]*DWORD:15', r'Computer[\s]*Software\\Policies\\Microsoft\\W32time\\TimeProviders\\NtpClient[\s]*ResolvePeerBackoffMaxTimes[\s]*DWORD:7', r'Computer[\s]*Software\\Policies\\Microsoft\\W32time\\TimeProviders\\NtpClient[\s]*SpecialPollInterval[\s]*DWORD:3600', r'Computer[\s]*Software\\Policies\\Microsoft\\W32time\\TimeProviders\\NtpClient[\s]*EventLogFlags[\s]*DWORD:0', ]) # set Configure NTP Client to 'Not Configured' self._testAdmxPolicy(r'System\Windows Time Service\Time Providers\Configure Windows NTP Client', 'Not Configured', [r'; Source file: c:\\windows\\system32\\grouppolicy\\machine\\registry.pol[\s]*; PARSING COMPLETED.']) @pytest.mark.destructive_test def test_set_computer_policy_RA_Unsolicit(self): ''' Test setting/unsetting/changing RA_Unsolicit policy ''' # Disable RA_Unsolicit log.debug('Attempting to disable RA_Unsolicit') self._testAdmxPolicy('RA_Unsolicit', 'Disabled', [ r'Computer[\s]*Software\\policies\\Microsoft\\Windows NT\\Terminal Services[\s]*fAllowUnsolicited[\s]*DWORD:0', r'Computer[\s]*Software\\policies\\Microsoft\\Windows NT\\Terminal Services[\s]*fAllowUnsolicitedFullControl[\s]*DELETE', r'Computer[\s]*Software\\policies\\Microsoft\\Windows NT\\Terminal Services\\RAUnsolicit[\s]*\*[\s]*DELETEALLVALUES', ]) # configure RA_Unsolicit log.debug('Attempting to configure RA_Unsolicit') self._testAdmxPolicy('RA_Unsolicit', { 'Configure Offer Remote Access': 'Enabled', 'Permit remote control of this computer': 'Allow helpers to remotely control the computer', 'Helpers': ['administrators', 'user1'] }, [ r'Computer[\s]*Software\\policies\\Microsoft\\Windows NT\\Terminal Services\\RAUnsolicit[\s]*user1[\s]*SZ:user1[\s]*', r'Computer[\s]*Software\\policies\\Microsoft\\Windows NT\\Terminal Services\\RAUnsolicit[\s]*administrators[\s]*SZ:administrators[\s]*', r'Computer[\s]*Software\\policies\\Microsoft\\Windows NT\\Terminal Services[\s]*fAllowUnsolicited[\s]*DWORD:1', r'Computer[\s]*Software\\policies\\Microsoft\\Windows NT\\Terminal Services[\s]*fAllowUnsolicitedFullControl[\s]*DWORD:1', ]) # Not Configure RA_Unsolicit log.debug('Attempting to set RA_Unsolicit to Not Configured') self._testAdmxPolicy('RA_Unsolicit', 'Not Configured', [r'; Source file: c:\\windows\\system32\\grouppolicy\\machine\\registry.pol[\s]*; PARSING COMPLETED.']) @pytest.mark.destructive_test def test_set_computer_policy_Pol_HardenedPaths(self): # Disable Pol_HardenedPaths log.debug('Attempting to disable Pol_HardenedPaths') self._testAdmxPolicy( 'Pol_HardenedPaths', 'Disabled', [r'Computer[\s]*Software\\policies\\Microsoft\\Windows\\NetworkProvider\\HardenedPaths[\s]*\*[\s]*DELETEALLVALUES']) # Configure Pol_HardenedPaths log.debug('Attempting to configure Pol_HardenedPaths') self._testAdmxPolicy( 'Pol_HardenedPaths', { 'Hardened UNC Paths': { r'\\*\NETLOGON': 'RequireMutualAuthentication=1, RequireIntegrity=1', r'\\*\SYSVOL': 'RequireMutualAuthentication=1, RequireIntegrity=1' } }, [ r'Computer[\s]*Software\\policies\\Microsoft\\Windows\\NetworkProvider\\HardenedPaths[\s]*\\\\\*\\NETLOGON[\s]*SZ:RequireMutualAuthentication=1, RequireIntegrity=1[\s]*', r'Computer[\s]*Software\\policies\\Microsoft\\Windows\\NetworkProvider\\HardenedPaths[\s]*\\\\\*\\SYSVOL[\s]*SZ:RequireMutualAuthentication=1, RequireIntegrity=1[\s]*', ]) # Not Configure Pol_HardenedPaths log.debug('Attempting to set Pol_HardenedPaths to Not Configured') self._testAdmxPolicy( 'Pol_HardenedPaths', 'Not Configured', [r'; Source file: c:\\windows\\system32\\grouppolicy\\machine\\registry.pol[\s]*; PARSING COMPLETED.']) @pytest.mark.destructive_test def test_set_computer_policy_WindowsUpdate(self): ''' Test setting/unsetting/changing WindowsUpdate policy ''' the_policy = { 'Configure automatic updating': '4 - Auto download and schedule the install', 'Install during automatic maintenance': False, 'Scheduled install day': '7 - Every Saturday', 'Scheduled install time': '17:00', 'Install updates for other Microsoft products': True } the_policy_check = [ r'Computer[\s]*Software\\Policies\\Microsoft\\Windows\\WindowsUpdate\\AU[\s]*NoAutoUpdate[\s]*DWORD:0', r'Computer[\s]*Software\\Policies\\Microsoft\\Windows\\WindowsUpdate\\AU[\s]*AUOptions[\s]*DWORD:4', r'Computer[\s]*Software\\Policies\\Microsoft\\Windows\\WindowsUpdate\\AU[\s]*AutomaticMaintenanceEnabled[\s]*DELETE', r'Computer[\s]*Software\\Policies\\Microsoft\\Windows\\WindowsUpdate\\AU[\s]*ScheduledInstallDay[\s]*DWORD:7', r'Computer[\s]*Software\\Policies\\Microsoft\\Windows\\WindowsUpdate\\AU[\s]*ScheduledInstallTime[\s]*DWORD:17', r'Computer[\s]*Software\\Policies\\Microsoft\\Windows\\WindowsUpdate\\AU[\s]*AllowMUUpdateService[\s]*DWORD:1\s*' ] # Configure Automatic Updates has different options in 2016 than in 2012 # and has only one boolean item, so we'll test it "False" in this block # and then "True" in next block if self.osrelease in ['2012Server', '2012ServerR2']: the_policy = { 'Configure automatic updating': '4 - Auto download and schedule the install', 'Install during automatic maintenance': False, 'Schedule install day': '7 - Every Saturday', 'Schedule install time': '17:00', } the_policy_check = [ r'Computer[\s]*Software\\Policies\\Microsoft\\Windows\\WindowsUpdate\\AU[\s]*NoAutoUpdate[\s]*DWORD:0', r'Computer[\s]*Software\\Policies\\Microsoft\\Windows\\WindowsUpdate\\AU[\s]*AUOptions[\s]*DWORD:4', r'Computer[\s]*Software\\Policies\\Microsoft\\Windows\\WindowsUpdate\\AU[\s]*AutomaticMaintenanceEnabled[\s]*DELETE', r'Computer[\s]*Software\\Policies\\Microsoft\\Windows\\WindowsUpdate\\AU[\s]*ScheduledInstallDay[\s]*DWORD:7', r'Computer[\s]*Software\\Policies\\Microsoft\\Windows\\WindowsUpdate\\AU[\s]*ScheduledInstallTime[\s]*DWORD:17', ] # test as False self._testAdmxPolicy(r'Windows Components\Windows Update\Configure Automatic Updates', the_policy, the_policy_check) # configure as True for "enable Automatic Updates" test below the_policy = { 'Configure automatic updating': '4 - Auto download and schedule the install', 'Install during automatic maintenance': True, 'Schedule install day': '7 - Every Saturday', 'Schedule install time': '17:00', } the_policy_check = [ r'Computer[\s]*Software\\Policies\\Microsoft\\Windows\\WindowsUpdate\\AU[\s]*NoAutoUpdate[\s]*DWORD:0', r'Computer[\s]*Software\\Policies\\Microsoft\\Windows\\WindowsUpdate\\AU[\s]*AUOptions[\s]*DWORD:4', r'Computer[\s]*Software\\Policies\\Microsoft\\Windows\\WindowsUpdate\\AU[\s]*AutomaticMaintenanceEnabled[\s]*DWORD:1\s*', r'Computer[\s]*Software\\Policies\\Microsoft\\Windows\\WindowsUpdate\\AU[\s]*ScheduledInstallDay[\s]*DWORD:7', r'Computer[\s]*Software\\Policies\\Microsoft\\Windows\\WindowsUpdate\\AU[\s]*ScheduledInstallTime[\s]*DWORD:17', ] # enable Automatic Updates self._testAdmxPolicy(r'Windows Components\Windows Update\Configure Automatic Updates', the_policy, the_policy_check) # disable Configure Automatic Updates self._testAdmxPolicy(r'Windows Components\Windows Update\Configure Automatic Updates', 'Disabled', [ r'Computer[\s]*Software\\Policies\\Microsoft\\Windows\\WindowsUpdate\\AU[\s]*NoAutoUpdate[\s]*DWORD:1', r'Computer[\s]*Software\\Policies\\Microsoft\\Windows\\WindowsUpdate\\AU[\s]*AUOptions[\s]*DELETE', r'Computer[\s]*Software\\Policies\\Microsoft\\Windows\\WindowsUpdate\\AU[\s]*AutomaticMaintenanceEnabled[\s]*DELETE', r'Computer[\s]*Software\\Policies\\Microsoft\\Windows\\WindowsUpdate\\AU[\s]*ScheduledInstallDay[\s]*DELETE', r'Computer[\s]*Software\\Policies\\Microsoft\\Windows\\WindowsUpdate\\AU[\s]*ScheduledInstallTime[\s]*DELETE', r'Computer[\s]*Software\\Policies\\Microsoft\\Windows\\WindowsUpdate\\AU[\s]*AllowMUUpdateService[\s]*DELETE' ]) # set Configure Automatic Updates to 'Not Configured' self._testAdmxPolicy(r'Windows Components\Windows Update\Configure Automatic Updates', 'Not Configured', [r'; Source file: c:\\windows\\system32\\grouppolicy\\machine\\registry.pol[\s]*; PARSING COMPLETED.']) @pytest.mark.destructive_test def test_set_computer_policy_ClipboardRedirection(self): ''' Test setting/unsetting/changing ClipboardRedirection policy ''' # Enable/Disable/Not Configured "Do not allow Clipboard redirection" self._testAdmxPolicy(r'Windows Components\Remote Desktop Services\Remote Desktop Session Host\Device and Resource Redirection\Do not allow Clipboard redirection', 'Enabled', [r'Computer[\s]*Software\\Policies\\Microsoft\\Windows NT\\Terminal Services[\s]*fDisableClip[\s]*DWORD:1']) self._testAdmxPolicy(r'Windows Components\Remote Desktop Services\Remote Desktop Session Host\Device and Resource Redirection\Do not allow Clipboard redirection', 'Disabled', [r'Computer[\s]*Software\\Policies\\Microsoft\\Windows NT\\Terminal Services[\s]*fDisableClip[\s]*DWORD:0']) self._testAdmxPolicy(r'Windows Components\Remote Desktop Services\Remote Desktop Session Host\Device and Resource Redirection\Do not allow Clipboard redirection', 'Not Configured', [r'; Source file: c:\\windows\\system32\\grouppolicy\\machine\\registry.pol[\s]*; PARSING COMPLETED.']) @pytest.mark.destructive_test def test_set_computer_policy_PasswordComplexity(self): ''' Test setting/unsetting/changing PasswordComplexity ''' # disable PasswordComplexity self._testSeceditPolicy('Password must meet complexity requirements', 'Disabled', [r'^PasswordComplexity = 0']) # enable PasswordComplexity self._testSeceditPolicy('PasswordComplexity', 'Enabled', [r'^PasswordComplexity = 1']) @pytest.mark.destructive_test def test_set_computer_policy_PasswordLen(self): ''' Test setting/unsetting/changing PasswordLength ''' # set Minimum password length self._testSeceditPolicy('Minimum password length', 10, [r'^MinimumPasswordLength = 10']) # set MinimumPasswordLength = 0 self._testSeceditPolicy('MinPasswordLen', 0, [r'^MinimumPasswordLength = 0']) @pytest.mark.destructive_test def test_set_computer_policy_SeNetworkLogonRight(self): ''' Test setting/unsetting/changing PasswordLength ''' # set SeNetworkLogonRight to only Administrators self._testSeceditPolicy('Access this computer from the network', ['Administrators'], [r'^SeNetworkLogonRight = \*S-1-5-32-544'], cumulative_rights_assignments=False) # set SeNetworkLogonRight back to the default self._testSeceditPolicy('SeNetworkLogonRight', ['Everyone', 'Administrators', 'Users', 'Backup Operators'], [r'^SeNetworkLogonRight = \*S-1-1-0,\*S-1-5-32-544,\*S-1-5-32-545,\*S-1-5-32-551']) @pytest.mark.destructive_test def test_set_computer_policy_multipleAdmxPolicies(self): ''' Tests setting several ADMX policies in succession and validating the configuration w/lgop ''' # set one policy self._testAdmxPolicy(r'Windows Components\Remote Desktop Services\Remote Desktop Session Host\Device and Resource Redirection\Do not allow Clipboard redirection', 'Disabled', [r'Computer[\s]*Software\\Policies\\Microsoft\\Windows NT\\Terminal Services[\s]*fDisableClip[\s]*DWORD:0']) # set another policy and make sure both this policy and the previous are okay self._testAdmxPolicy('RA_Unsolicit', { 'Configure Offer Remote Access': 'Enabled', 'Permit remote control of this computer': 'Allow helpers to remotely control the computer', 'Helpers': ['administrators', 'user1'] }, [ r'Computer[\s]*Software\\Policies\\Microsoft\\Windows NT\\Terminal Services[\s]*fDisableClip[\s]*DWORD:0', r'Computer[\s]*Software\\policies\\Microsoft\\Windows NT\\Terminal Services\\RAUnsolicit[\s]*user1[\s]*SZ:user1[\s]*', r'Computer[\s]*Software\\policies\\Microsoft\\Windows NT\\Terminal Services\\RAUnsolicit[\s]*administrators[\s]*SZ:administrators[\s]*', r'Computer[\s]*Software\\policies\\Microsoft\\Windows NT\\Terminal Services[\s]*fAllowUnsolicited[\s]*DWORD:1', r'Computer[\s]*Software\\policies\\Microsoft\\Windows NT\\Terminal Services[\s]*fAllowUnsolicitedFullControl[\s]*DWORD:1', ]) # Configure Automatic Updates and validate everything is still okay self._testAdmxPolicy(r'Windows Components\Windows Update\Configure Automatic Updates', 'Disabled', [ r'Computer[\s]*Software\\Policies\\Microsoft\\Windows NT\\Terminal Services[\s]*fDisableClip[\s]*DWORD:0', r'Computer[\s]*Software\\policies\\Microsoft\\Windows NT\\Terminal Services\\RAUnsolicit[\s]*user1[\s]*SZ:user1[\s]*', r'Computer[\s]*Software\\policies\\Microsoft\\Windows NT\\Terminal Services\\RAUnsolicit[\s]*administrators[\s]*SZ:administrators[\s]*', r'Computer[\s]*Software\\policies\\Microsoft\\Windows NT\\Terminal Services[\s]*fAllowUnsolicited[\s]*DWORD:1', r'Computer[\s]*Software\\policies\\Microsoft\\Windows NT\\Terminal Services[\s]*fAllowUnsolicitedFullControl[\s]*DWORD:1', r'Computer[\s]*Software\\Policies\\Microsoft\\Windows\\WindowsUpdate\\AU[\s]*NoAutoUpdate[\s]*DWORD:1', r'Computer[\s]*Software\\Policies\\Microsoft\\Windows\\WindowsUpdate\\AU[\s]*AUOptions[\s]*DELETE', r'Computer[\s]*Software\\Policies\\Microsoft\\Windows\\WindowsUpdate\\AU[\s]*AutomaticMaintenanceEnabled[\s]*DELETE', r'Computer[\s]*Software\\Policies\\Microsoft\\Windows\\WindowsUpdate\\AU[\s]*ScheduledInstallDay[\s]*DELETE', r'Computer[\s]*Software\\Policies\\Microsoft\\Windows\\WindowsUpdate\\AU[\s]*ScheduledInstallTime[\s]*DELETE', r'Computer[\s]*Software\\Policies\\Microsoft\\Windows\\WindowsUpdate\\AU[\s]*AllowMUUpdateService[\s]*DELETE' ]) @pytest.mark.destructive_test def test_set_computer_policy_DisableDomainCreds(self): ''' Tests Enable/Disable of DisableDomainCreds policy ''' self._testRegistryPolicy('DisableDomainCreds', 'Enabled', 'HKEY_LOCAL_MACHINE', 'SYSTEM\\CurrentControlSet\\Control\\Lsa', 'DisableDomainCreds', 1) self._testRegistryPolicy( 'Network access: Do not allow storage of passwords and credentials for network authentication', 'Disabled', 'HKEY_LOCAL_MACHINE', 'SYSTEM\\CurrentControlSet\\Control\\Lsa', 'DisableDomainCreds', 0) @pytest.mark.destructive_test def test_set_computer_policy_ForceGuest(self): ''' Tests changing ForceGuest policy ''' self._testRegistryPolicy('ForceGuest', 'Guest only - local users authenticate as Guest', 'HKEY_LOCAL_MACHINE', 'SYSTEM\\CurrentControlSet\\Control\\Lsa', 'ForceGuest', 1) self._testRegistryPolicy( 'Network access: Sharing and security model for local accounts', 'Classic - local users authenticate as themselves', 'HKEY_LOCAL_MACHINE', 'SYSTEM\\CurrentControlSet\\Control\\Lsa', 'ForceGuest', 0) @pytest.mark.destructive_test def test_set_computer_policy_DisableUXWUAccess(self): ''' Tests changing DisableUXWUAccess #50079 shows using the 'Remove access to use all Windows Update features' failed Policy only exists on 2016 ''' valid_osreleases = ['2016Server'] if self.osrelease not in valid_osreleases: self.skipTest('DisableUXWUAccess policy is only applicable if the osrelease grain is {0}'.format(' or '.join(valid_osreleases))) else: self._testAdmxPolicy(r'DisableUXWUAccess', 'Enabled', [r'Computer[\s]*Software\\Policies\\Microsoft\\Windows\\WindowsUpdate[\s]*SetDisableUXWUAccess[\s]*DWORD:1']) self._testAdmxPolicy(r'Remove access to use all Windows Update features', 'Disabled', [r'Computer[\s]*Software\\Policies\\Microsoft\\Windows\\WindowsUpdate[\s]*SetDisableUXWUAccess[\s]*DWORD:0']) self._testAdmxPolicy(r'Windows Components\Windows Update\Remove access to use all Windows Update features', 'Not Configured', [r'; Source file: c:\\windows\\system32\\grouppolicy\\machine\\registry.pol[\s]*; PARSING COMPLETED.']) @pytest.mark.destructive_test def test_set_computer_policy_Access_data_sources_across_domains(self): ''' Tests that a policy that has multiple names ''' self._testAdmxPolicy(r'Access data sources across domains', 'Enabled', [], assert_true=False) self._testAdmxPolicy(r'Windows Components\Internet Explorer\Internet Control Panel\Security Page\Internet Zone\Access data sources across domains', {'Access data sources across domains': 'Prompt'}, [r'Computer[\s]*Software\\Policies\\Microsoft\\Windows\\CurrentVersion\\Internet Settings\\Zones\\3[\s]*1406[\s]*DWORD:1']) self._testAdmxPolicy(r'Windows Components\Internet Explorer\Internet Control Panel\Security Page\Internet Zone\Access data sources across domains', {'Access data sources across domains': 'Enable'}, [r'Computer[\s]*Software\\Policies\\Microsoft\\Windows\\CurrentVersion\\Internet Settings\\Zones\\3[\s]*1406[\s]*DWORD:0']) self._testAdmxPolicy(r'Windows Components\Internet Explorer\Internet Control Panel\Security Page\Internet Zone\Access data sources across domains', 'Disabled', [r'Computer[\s]*Software\\Policies\\Microsoft\\Windows\\CurrentVersion\\Internet Settings\\Zones\\3[\s]*1406[\s]*DELETE']) @pytest.mark.destructive_test def test_set_computer_policy_ActiveHours(self): ''' Test configuring the ActiveHours policy, #47784 Only applies to 2016Server # activehours.sls active_hours_policy: lgpo.set: - computer_policy: 'ActiveHours': 'ActiveHoursStartTime': '8 AM' 'ActiveHoursEndTime': '7 PM' ''' valid_osreleases = ['2016Server'] if self.osrelease not in valid_osreleases: self.skipTest('ActiveHours policy is only applicable if the osrelease grain is {0}'.format(' or '.join(valid_osreleases))) else: self._testAdmxPolicy(r'ActiveHours', {'ActiveHoursStartTime': '8 AM', 'ActiveHoursEndTime': '7 PM'}, [ r'Computer[\s]*Software\\Policies\\Microsoft\\Windows\\WindowsUpdate[\s]*SetActiveHours[\s]*DWORD:1', r'Computer[\s]*Software\\Policies\\Microsoft\\Windows\\WindowsUpdate[\s]*ActiveHoursStart[\s]*DWORD:8', r'Computer[\s]*Software\\Policies\\Microsoft\\Windows\\WindowsUpdate[\s]*ActiveHoursEnd[\s]*DWORD:19' ]) self._testAdmxPolicy(r'ActiveHours', {'ActiveHoursStartTime': '5 AM', 'ActiveHoursEndTime': '10 PM'}, [ r'Computer[\s]*Software\\Policies\\Microsoft\\Windows\\WindowsUpdate[\s]*SetActiveHours[\s]*DWORD:1', r'Computer[\s]*Software\\Policies\\Microsoft\\Windows\\WindowsUpdate[\s]*ActiveHoursStart[\s]*DWORD:5', r'Computer[\s]*Software\\Policies\\Microsoft\\Windows\\WindowsUpdate[\s]*ActiveHoursEnd[\s]*DWORD:22' ]) self._testAdmxPolicy('Turn off auto-restart for updates during active hours', 'Disabled', [ r'Computer[\s]*Software\\Policies\\Microsoft\\Windows\\WindowsUpdate[\s]*SetActiveHours[\s]*DWORD:0', r'Computer[\s]*Software\\Policies\\Microsoft\\Windows\\WindowsUpdate[\s]*ActiveHoursStart[\s]*DELETE', r'Computer[\s]*Software\\Policies\\Microsoft\\Windows\\WindowsUpdate[\s]*ActiveHoursEnd[\s]*DELETE' ]) self._testAdmxPolicy(r'Windows Components\Windows Update\Turn off auto-restart for updates during active hours', 'Not Configured', [r'; Source file: c:\\windows\\system32\\grouppolicy\\machine\\registry.pol[\s]*; PARSING COMPLETED.']) @pytest.mark.destructive_test def test_set_computer_policy_AllowTelemetry(self): ''' Tests that a the AllowTelemetry policy is applied correctly and that it doesn't appear in subsequent group policy states as having changed ''' valid_osreleases = ['10', '2016Server', '2019Server'] if self.osrelease not in valid_osreleases: self.skipTest('Allow Telemetry policy is only applicable if the ' 'osrelease grain is {0}'.format(' or '.join(valid_osreleases))) else: self._testAdmxPolicy( 'Allow Telemetry', {'AllowTelemetry': '1 - Basic'}, [r'Software\\Policies\\Microsoft\\Windows\\DataCollection[\s]*AllowTelemetry[\s]*DWORD:1'], assert_true=True) result = self.run_function( 'state.single', ['lgpo.set'], name='state', computer_policy={ 'Disable pre-release features or settings': 'Disabled' } ) name = 'lgpo_|-state_|-state_|-set' expected = { 'new': { 'Computer Configuration': { 'Windows Components\\Data Collection and Preview Builds\\Disable pre-release features or settings': 'Disabled'}}, 'old': {'Computer Configuration': {}}} self.assertDictEqual(result[name]['changes'], expected) def tearDown(self): ''' tearDown method, runs after each test ''' self.run_state( 'file.absent', name='c:\\windows\\system32\\grouppolicy\\machine\\registry.pol') self.run_state( 'file.absent', name='c:\\windows\\system32\\grouppolicy\\user\\registry.pol')