diff --git a/salt/modules/win_groupadd.py b/salt/modules/win_groupadd.py index 90d954316009..5e06e3c1ebc7 100644 --- a/salt/modules/win_groupadd.py +++ b/salt/modules/win_groupadd.py @@ -13,11 +13,11 @@ # Import Salt libs import salt.utils.platform import salt.utils.win_functions +import salt.utils.winapi try: import win32com.client - import pythoncom import pywintypes HAS_DEPENDENCIES = True except ImportError: @@ -43,8 +43,8 @@ def _get_computer_object(): Returns: object: Returns the computer object for the local machine ''' - pythoncom.CoInitialize() - nt = win32com.client.Dispatch('AdsNameSpaces') + with salt.utils.winapi.Com(): + nt = win32com.client.Dispatch('AdsNameSpaces') return nt.GetObject('', 'WinNT://.,computer') @@ -59,8 +59,8 @@ def _get_group_object(name): Returns: object: The specified group object ''' - pythoncom.CoInitialize() - nt = win32com.client.Dispatch('AdsNameSpaces') + with salt.utils.winapi.Com(): + nt = win32com.client.Dispatch('AdsNameSpaces') return nt.GetObject('', 'WinNT://./' + name + ',group') @@ -72,8 +72,8 @@ def _get_all_groups(): Returns: iter: A list of objects for all groups on the machine ''' - pythoncom.CoInitialize() - nt = win32com.client.Dispatch('AdsNameSpaces') + with salt.utils.winapi.Com(): + nt = win32com.client.Dispatch('AdsNameSpaces') results = nt.GetObject('', 'WinNT://.') results.Filter = ['group'] return results diff --git a/salt/modules/win_system.py b/salt/modules/win_system.py index 95bec3b0e9d6..00a328b1c749 100644 --- a/salt/modules/win_system.py +++ b/salt/modules/win_system.py @@ -3,7 +3,6 @@ Module for managing windows systems. :depends: - - pythoncom - pywintypes - win32api - win32con @@ -24,12 +23,12 @@ import salt.utils.functools import salt.utils.locales import salt.utils.platform +import salt.utils.winapi from salt.exceptions import CommandExecutionError # Import 3rd-party Libs from salt.ext import six try: - import pythoncom import wmi import win32net import win32api @@ -516,8 +515,8 @@ def get_system_info(): os_type = {1: 'Work Station', 2: 'Domain Controller', 3: 'Server'} - pythoncom.CoInitialize() - conn = wmi.WMI() + with salt.utils.winapi.Com(): + conn = wmi.WMI() system = conn.Win32_OperatingSystem()[0] ret = {'name': get_computer_name(), 'description': system.Description, @@ -756,8 +755,8 @@ def _join_domain(domain, if not account_exists: join_options |= NETSETUP_ACCOUNT_CREATE - pythoncom.CoInitialize() - conn = wmi.WMI() + with salt.utils.winapi.Com(): + conn = wmi.WMI() comp = conn.Win32_ComputerSystem()[0] # Return the results of the command as an error @@ -848,8 +847,8 @@ def unjoin_domain(username=None, if disable: unjoin_options |= NETSETUP_ACCT_DELETE - pythoncom.CoInitialize() - conn = wmi.WMI() + with salt.utils.winapi.Com(): + conn = wmi.WMI() comp = conn.Win32_ComputerSystem()[0] err = comp.UnjoinDomainOrWorkgroup(Password=password, UserName=username, @@ -892,8 +891,8 @@ def get_domain_workgroup(): salt 'minion-id' system.get_domain_workgroup ''' - pythoncom.CoInitialize() - conn = wmi.WMI() + with salt.utils.winapi.Com(): + conn = wmi.WMI() for computer in conn.Win32_ComputerSystem(): if computer.PartOfDomain: return {'Domain': computer.Domain} diff --git a/salt/modules/win_task.py b/salt/modules/win_task.py index 006c4ea7ea71..afec0a14c93b 100644 --- a/salt/modules/win_task.py +++ b/salt/modules/win_task.py @@ -17,6 +17,7 @@ # Import Salt libs import salt.utils.platform +import salt.utils.winapi # Import 3rd-party libraries try: @@ -333,8 +334,8 @@ def list_tasks(location='\\'): salt 'minion-id' task.list_tasks ''' # Create the task service object - pythoncom.CoInitialize() - task_service = win32com.client.Dispatch("Schedule.Service") + with salt.utils.winapi.Com(): + task_service = win32com.client.Dispatch("Schedule.Service") task_service.Connect() # Get the folder to list tasks from @@ -366,8 +367,8 @@ def list_folders(location='\\'): salt 'minion-id' task.list_folders ''' # Create the task service object - pythoncom.CoInitialize() - task_service = win32com.client.Dispatch("Schedule.Service") + with salt.utils.winapi.Com(): + task_service = win32com.client.Dispatch("Schedule.Service") task_service.Connect() # Get the folder to list folders from @@ -401,8 +402,8 @@ def list_triggers(name, location='\\'): salt 'minion-id' task.list_triggers ''' # Create the task service object - pythoncom.CoInitialize() - task_service = win32com.client.Dispatch("Schedule.Service") + with salt.utils.winapi.Com(): + task_service = win32com.client.Dispatch("Schedule.Service") task_service.Connect() # Get the folder to list folders from @@ -437,8 +438,8 @@ def list_actions(name, location='\\'): salt 'minion-id' task.list_actions ''' # Create the task service object - pythoncom.CoInitialize() - task_service = win32com.client.Dispatch("Schedule.Service") + with salt.utils.winapi.Com(): + task_service = win32com.client.Dispatch("Schedule.Service") task_service.Connect() # Get the folder to list folders from @@ -499,8 +500,8 @@ def create_task(name, return '{0} already exists'.format(name) # connect to the task scheduler - pythoncom.CoInitialize() - task_service = win32com.client.Dispatch("Schedule.Service") + with salt.utils.winapi.Com(): + task_service = win32com.client.Dispatch("Schedule.Service") task_service.Connect() # Create a new task definition @@ -584,8 +585,8 @@ def create_task_from_xml(name, return 'Must specify either xml_text or xml_path' # Create the task service object - pythoncom.CoInitialize() - task_service = win32com.client.Dispatch("Schedule.Service") + with salt.utils.winapi.Com(): + task_service = win32com.client.Dispatch("Schedule.Service") task_service.Connect() # Load xml from file, overrides xml_text @@ -664,8 +665,8 @@ def create_folder(name, location='\\'): return '{0} already exists'.format(name) # Create the task service object - pythoncom.CoInitialize() - task_service = win32com.client.Dispatch("Schedule.Service") + with salt.utils.winapi.Com(): + task_service = win32com.client.Dispatch("Schedule.Service") task_service.Connect() # Get the folder to list folders from @@ -879,8 +880,8 @@ def edit_task(name=None, if name in list_tasks(location): # Connect to the task scheduler - pythoncom.CoInitialize() - task_service = win32com.client.Dispatch("Schedule.Service") + with salt.utils.winapi.Com(): + task_service = win32com.client.Dispatch("Schedule.Service") task_service.Connect() # get the folder to create the task in @@ -1045,8 +1046,8 @@ def delete_task(name, location='\\'): return '{0} not found in {1}'.format(name, location) # connect to the task scheduler - pythoncom.CoInitialize() - task_service = win32com.client.Dispatch("Schedule.Service") + with salt.utils.winapi.Com(): + task_service = win32com.client.Dispatch("Schedule.Service") task_service.Connect() # get the folder to delete the task from @@ -1085,8 +1086,8 @@ def delete_folder(name, location='\\'): return '{0} not found in {1}'.format(name, location) # connect to the task scheduler - pythoncom.CoInitialize() - task_service = win32com.client.Dispatch("Schedule.Service") + with salt.utils.winapi.Com(): + task_service = win32com.client.Dispatch("Schedule.Service") task_service.Connect() # get the folder to delete the folder from @@ -1126,8 +1127,8 @@ def run(name, location='\\'): return '{0} not found in {1}'.format(name, location) # connect to the task scheduler - pythoncom.CoInitialize() - task_service = win32com.client.Dispatch("Schedule.Service") + with salt.utils.winapi.Com(): + task_service = win32com.client.Dispatch("Schedule.Service") task_service.Connect() # get the folder to delete the folder from @@ -1165,8 +1166,8 @@ def run_wait(name, location='\\'): return '{0} not found in {1}'.format(name, location) # connect to the task scheduler - pythoncom.CoInitialize() - task_service = win32com.client.Dispatch("Schedule.Service") + with salt.utils.winapi.Com(): + task_service = win32com.client.Dispatch("Schedule.Service") task_service.Connect() # get the folder to delete the folder from @@ -1222,8 +1223,8 @@ def stop(name, location='\\'): return '{0} not found in {1}'.format(name, location) # connect to the task scheduler - pythoncom.CoInitialize() - task_service = win32com.client.Dispatch("Schedule.Service") + with salt.utils.winapi.Com(): + task_service = win32com.client.Dispatch("Schedule.Service") task_service.Connect() # get the folder to delete the folder from @@ -1268,8 +1269,8 @@ def status(name, location='\\'): return '{0} not found in {1}'.format(name, location) # connect to the task scheduler - pythoncom.CoInitialize() - task_service = win32com.client.Dispatch("Schedule.Service") + with salt.utils.winapi.Com(): + task_service = win32com.client.Dispatch("Schedule.Service") task_service.Connect() # get the folder where the task is defined @@ -1303,8 +1304,8 @@ def info(name, location='\\'): return '{0} not found in {1}'.format(name, location) # connect to the task scheduler - pythoncom.CoInitialize() - task_service = win32com.client.Dispatch("Schedule.Service") + with salt.utils.winapi.Com(): + task_service = win32com.client.Dispatch("Schedule.Service") task_service.Connect() # get the folder to delete the folder from @@ -1493,8 +1494,8 @@ def add_action(name=None, if name in list_tasks(location): # Connect to the task scheduler - pythoncom.CoInitialize() - task_service = win32com.client.Dispatch("Schedule.Service") + with salt.utils.winapi.Com(): + task_service = win32com.client.Dispatch("Schedule.Service") task_service.Connect() # get the folder to create the task in @@ -1600,8 +1601,8 @@ def _clear_actions(name, location='\\'): return '{0} not found in {1}'.format(name, location) # Create the task service object - pythoncom.CoInitialize() - task_service = win32com.client.Dispatch("Schedule.Service") + with salt.utils.winapi.Com(): + task_service = win32com.client.Dispatch("Schedule.Service") task_service.Connect() # Get the actions from the task @@ -1992,8 +1993,8 @@ def add_trigger(name=None, if name in list_tasks(location): # Connect to the task scheduler - pythoncom.CoInitialize() - task_service = win32com.client.Dispatch("Schedule.Service") + with salt.utils.winapi.Com(): + task_service = win32com.client.Dispatch("Schedule.Service") task_service.Connect() # get the folder to create the task in @@ -2169,8 +2170,8 @@ def clear_triggers(name, location='\\'): return '{0} not found in {1}'.format(name, location) # Create the task service object - pythoncom.CoInitialize() - task_service = win32com.client.Dispatch("Schedule.Service") + with salt.utils.winapi.Com(): + task_service = win32com.client.Dispatch("Schedule.Service") task_service.Connect() # Get the triggers from the task diff --git a/salt/modules/win_useradd.py b/salt/modules/win_useradd.py index 69d598606e66..01adfed087a2 100644 --- a/salt/modules/win_useradd.py +++ b/salt/modules/win_useradd.py @@ -9,7 +9,6 @@ `. :depends: - - pythoncom - pywintypes - win32api - win32con @@ -38,6 +37,7 @@ import salt.utils.args import salt.utils.dateutils import salt.utils.platform +import salt.utils.winapi from salt.ext import six from salt.ext.six import string_types from salt.exceptions import CommandExecutionError @@ -47,7 +47,6 @@ try: import pywintypes import wmi - import pythoncom import win32api import win32con import win32net @@ -989,8 +988,8 @@ def rename(name, new_name): # Rename the user account # Connect to WMI - pythoncom.CoInitialize() - c = wmi.WMI(find_classes=0) + with salt.utils.winapi.Com(): + c = wmi.WMI(find_classes=0) # Get the user object try: diff --git a/salt/modules/win_wua.py b/salt/modules/win_wua.py index 736f4a079097..be1c9f475fb7 100644 --- a/salt/modules/win_wua.py +++ b/salt/modules/win_wua.py @@ -63,12 +63,12 @@ import salt.utils.platform import salt.utils.versions import salt.utils.win_update +import salt.utils.winapi from salt.exceptions import CommandExecutionError # Import 3rd-party libs from salt.ext import six try: - import pythoncom import win32com.client HAS_PYWIN32 = True except ImportError: @@ -1057,6 +1057,7 @@ def set_wu_settings(level=None, # work on Windows 10 / Server 2016. It is called in throughout this function # like this: # + # with salt.utils.winapi.Com(): # obj_au = win32com.client.Dispatch('Microsoft.Update.AutoUpdate') # obj_au_settings = obj_au.Settings # obj_au_settings.Save() @@ -1077,10 +1078,10 @@ def set_wu_settings(level=None, ret = {'Success': True} # Initialize the PyCom system - pythoncom.CoInitialize() + with salt.utils.winapi.Com(): - # Create an AutoUpdate object - obj_au = win32com.client.Dispatch('Microsoft.Update.AutoUpdate') + # Create an AutoUpdate object + obj_au = win32com.client.Dispatch('Microsoft.Update.AutoUpdate') # Create an AutoUpdate Settings Object obj_au_settings = obj_au.Settings @@ -1174,7 +1175,8 @@ def set_wu_settings(level=None, if msupdate is not None: # Microsoft Update requires special handling # First load the MS Update Service Manager - obj_sm = win32com.client.Dispatch('Microsoft.Update.ServiceManager') + with salt.utils.winapi.Com(): + obj_sm = win32com.client.Dispatch('Microsoft.Update.ServiceManager') # Give it a bogus name obj_sm.ClientApplicationID = "My App" @@ -1275,10 +1277,9 @@ def get_wu_settings(): 'Saturday'] # Initialize the PyCom system - pythoncom.CoInitialize() - - # Create an AutoUpdate object - obj_au = win32com.client.Dispatch('Microsoft.Update.AutoUpdate') + with salt.utils.winapi.Com(): + # Create an AutoUpdate object + obj_au = win32com.client.Dispatch('Microsoft.Update.AutoUpdate') # Create an AutoUpdate Settings Object obj_au_settings = obj_au.Settings @@ -1312,8 +1313,10 @@ def _get_msupdate_status(): ''' # To get the status of Microsoft Update we actually have to check the # Microsoft Update Service Manager - # Create a ServiceManager Object - obj_sm = win32com.client.Dispatch('Microsoft.Update.ServiceManager') + # Initialize the PyCom system + with salt.utils.winapi.Com(): + # Create a ServiceManager Object + obj_sm = win32com.client.Dispatch('Microsoft.Update.ServiceManager') # Return a collection of loaded Services col_services = obj_sm.Services diff --git a/salt/states/file.py b/salt/states/file.py index 8b58ae7136ef..4ce720e97a9b 100644 --- a/salt/states/file.py +++ b/salt/states/file.py @@ -298,6 +298,7 @@ def run(): if salt.utils.platform.is_windows(): import salt.utils.win_dacl import salt.utils.win_functions + import salt.utils.winapi # Import 3rd-party libs from salt.ext import six @@ -1207,7 +1208,8 @@ def _shortcut_check(name, ), pchanges if os.path.isfile(name): - shell = win32com.client.Dispatch("WScript.Shell") + with salt.utils.winapi.Com(): + shell = win32com.client.Dispatch("WScript.Shell") scut = shell.CreateShortcut(name) state_checks = [scut.TargetPath.lower() == target.lower()] if arguments is not None: @@ -6851,7 +6853,8 @@ def shortcut( # This will just load the shortcut if it already exists # It won't create the file until calling scut.Save() - shell = win32com.client.Dispatch("WScript.Shell") + with salt.utils.winapi.Com(): + shell = win32com.client.Dispatch("WScript.Shell") scut = shell.CreateShortcut(name) # The shortcut target will automatically be created with its diff --git a/salt/utils/win_update.py b/salt/utils/win_update.py index 6769607f9edb..3b33333fa729 100644 --- a/salt/utils/win_update.py +++ b/salt/utils/win_update.py @@ -10,6 +10,7 @@ # Import Salt libs import salt.utils.args import salt.utils.data +import salt.utils.winapi from salt.ext import six from salt.ext.six.moves import range from salt.exceptions import CommandExecutionError @@ -17,7 +18,6 @@ # Import 3rd-party libs try: import win32com.client - import pythoncom import pywintypes HAS_PYWIN32 = True except ImportError: @@ -68,7 +68,8 @@ def __init__(self): Initialize the updates collection. Can be accessed via ``Updates.updates`` ''' - self.updates = win32com.client.Dispatch('Microsoft.Update.UpdateColl') + with salt.utils.winapi.Com(): + self.updates = win32com.client.Dispatch('Microsoft.Update.UpdateColl') def count(self): ''' @@ -274,13 +275,13 @@ def __init__(self): Need to look at the possibility of loading this into ``__context__`` ''' # Initialize the PyCom system - pythoncom.CoInitialize() + with salt.utils.winapi.Com(): - # Create a session with the Windows Update Agent - self._session = win32com.client.Dispatch('Microsoft.Update.Session') + # Create a session with the Windows Update Agent + self._session = win32com.client.Dispatch('Microsoft.Update.Session') - # Create Collection for Updates - self._updates = win32com.client.Dispatch('Microsoft.Update.UpdateColl') + # Create Collection for Updates + self._updates = win32com.client.Dispatch('Microsoft.Update.UpdateColl') self.refresh() @@ -572,7 +573,8 @@ def download(self, updates): # Initialize the downloader object and list collection downloader = self._session.CreateUpdateDownloader() self._session.ClientApplicationID = 'Salt: Download Update' - download_list = win32com.client.Dispatch('Microsoft.Update.UpdateColl') + with salt.utils.winapi.Com(): + download_list = win32com.client.Dispatch('Microsoft.Update.UpdateColl') ret = {'Updates': {}} @@ -683,7 +685,8 @@ def install(self, updates): installer = self._session.CreateUpdateInstaller() self._session.ClientApplicationID = 'Salt: Install Update' - install_list = win32com.client.Dispatch('Microsoft.Update.UpdateColl') + with salt.utils.winapi.Com(): + install_list = win32com.client.Dispatch('Microsoft.Update.UpdateColl') ret = {'Updates': {}} @@ -802,7 +805,8 @@ def uninstall(self, updates): installer = self._session.CreateUpdateInstaller() self._session.ClientApplicationID = 'Salt: Install Update' - uninstall_list = win32com.client.Dispatch('Microsoft.Update.UpdateColl') + with salt.utils.winapi.Com(): + uninstall_list = win32com.client.Dispatch('Microsoft.Update.UpdateColl') ret = {'Updates': {}} @@ -999,8 +1003,7 @@ def needs_reboot(): ''' # Initialize the PyCom system - pythoncom.CoInitialize() - - # Create an AutoUpdate object - obj_sys = win32com.client.Dispatch('Microsoft.Update.SystemInfo') + with salt.utils.winapi.Com(): + # Create an AutoUpdate object + obj_sys = win32com.client.Dispatch('Microsoft.Update.SystemInfo') return salt.utils.data.is_true(obj_sys.RebootRequired) diff --git a/tests/unit/modules/test_win_system.py b/tests/unit/modules/test_win_system.py index a34c148276dc..20171d81755f 100644 --- a/tests/unit/modules/test_win_system.py +++ b/tests/unit/modules/test_win_system.py @@ -38,6 +38,11 @@ def setup_loader_modules(self): now.day, now.hour, now.minute, now.second, now.microsecond]) modules_globals['win32api'] = win32api + win32net = types.ModuleType(str('win32net')) # future lint: disable=blacklisted-function + win32net.NetServerGetInfo = MagicMock() + win32net.NetServerSetInfo = MagicMock() + modules_globals['win32net'] = win32net + return {win_system: modules_globals} def test_halt(self): @@ -177,14 +182,15 @@ def test_set_computer_desc(self): ''' Test to set the Windows computer description ''' - mock = MagicMock(return_value=True) - with patch.dict(win_system.__salt__, {'cmd.run': mock}): - mock = MagicMock(return_value="Salt's comp") - with patch.object(win_system, 'get_computer_desc', mock): - self.assertDictEqual(win_system.set_computer_desc( - "Salt's comp" - ), - {'Computer Description': "Salt's comp"}) + mock = MagicMock() + mock_get_info = MagicMock(return_value={'comment': ''}) + mock_get_desc = MagicMock(return_value="Salt's comp") + with patch('salt.modules.win_system.win32net.NetServerGetInfo', mock_get_info), \ + patch('salt.modules.win_system.win32net.NetServerSetInfo', mock), \ + patch.object(win_system, 'get_computer_desc', mock_get_desc): + self.assertDictEqual( + win_system.set_computer_desc("Salt's comp"), + {'Computer Description': "Salt's comp"}) @skipIf(not win_system.HAS_WIN32NET_MODS, 'this test needs the w32net library') def test_get_computer_desc(self):