mirror of
https://github.com/saltstack/salt.git
synced 2025-04-17 10:10:20 +00:00
Merge pull request #46565 from twangboy/win_fix_cmd_powershell_2018.3
Create reg salt util (2018.3)
This commit is contained in:
commit
0faced1d54
8 changed files with 1204 additions and 727 deletions
|
@ -74,9 +74,8 @@ if salt.utils.platform.is_windows():
|
|||
import wmi # pylint: disable=import-error
|
||||
import salt.utils.winapi
|
||||
import win32api
|
||||
import salt.modules.reg
|
||||
import salt.utils.win_reg
|
||||
HAS_WMI = True
|
||||
__salt__['reg.read_value'] = salt.modules.reg.read_value
|
||||
except ImportError:
|
||||
log.exception(
|
||||
'Unable to import Python wmi module, some core grains '
|
||||
|
@ -101,10 +100,10 @@ def _windows_cpudata():
|
|||
grains['num_cpus'] = int(os.environ['NUMBER_OF_PROCESSORS'])
|
||||
except ValueError:
|
||||
grains['num_cpus'] = 1
|
||||
grains['cpu_model'] = __salt__['reg.read_value'](
|
||||
"HKEY_LOCAL_MACHINE",
|
||||
"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0",
|
||||
"ProcessorNameString").get('vdata')
|
||||
grains['cpu_model'] = salt.utils.win_reg.read_value(
|
||||
hive="HKEY_LOCAL_MACHINE",
|
||||
key="HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0",
|
||||
vname="ProcessorNameString").get('vdata')
|
||||
return grains
|
||||
|
||||
|
||||
|
|
|
@ -12,7 +12,6 @@ import functools
|
|||
import glob
|
||||
import logging
|
||||
import os
|
||||
import platform
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
|
@ -37,6 +36,7 @@ import salt.utils.timed_subprocess
|
|||
import salt.utils.user
|
||||
import salt.utils.versions
|
||||
import salt.utils.vt
|
||||
import salt.utils.win_reg
|
||||
import salt.grains.extra
|
||||
from salt.ext import six
|
||||
from salt.exceptions import CommandExecutionError, TimedProcTimeoutError, \
|
||||
|
@ -2839,9 +2839,9 @@ def shell_info(shell, list_modules=False):
|
|||
# Ensure ret['installed'] always as a value of True, False or None (not sure)
|
||||
ret = {'installed': False}
|
||||
if salt.utils.platform.is_windows() and shell == 'powershell':
|
||||
pw_keys = __salt__['reg.list_keys'](
|
||||
'HKEY_LOCAL_MACHINE',
|
||||
'Software\\Microsoft\\PowerShell')
|
||||
pw_keys = salt.utils.win_reg.list_keys(
|
||||
hive='HKEY_LOCAL_MACHINE',
|
||||
key='Software\\Microsoft\\PowerShell')
|
||||
pw_keys.sort(key=int)
|
||||
if len(pw_keys) == 0:
|
||||
return {
|
||||
|
@ -2850,16 +2850,16 @@ def shell_info(shell, list_modules=False):
|
|||
'installed': False,
|
||||
}
|
||||
for reg_ver in pw_keys:
|
||||
install_data = __salt__['reg.read_value'](
|
||||
'HKEY_LOCAL_MACHINE',
|
||||
'Software\\Microsoft\\PowerShell\\{0}'.format(reg_ver),
|
||||
'Install')
|
||||
install_data = salt.utils.win_reg.read_value(
|
||||
hive='HKEY_LOCAL_MACHINE',
|
||||
key='Software\\Microsoft\\PowerShell\\{0}'.format(reg_ver),
|
||||
vname='Install')
|
||||
if install_data.get('vtype') == 'REG_DWORD' and \
|
||||
install_data.get('vdata') == 1:
|
||||
details = __salt__['reg.list_values'](
|
||||
'HKEY_LOCAL_MACHINE',
|
||||
'Software\\Microsoft\\PowerShell\\{0}\\'
|
||||
'PowerShellEngine'.format(reg_ver))
|
||||
details = salt.utils.win_reg.list_values(
|
||||
hive='HKEY_LOCAL_MACHINE',
|
||||
key='Software\\Microsoft\\PowerShell\\{0}\\'
|
||||
'PowerShellEngine'.format(reg_ver))
|
||||
|
||||
# reset data, want the newest version details only as powershell
|
||||
# is backwards compatible
|
||||
|
@ -3138,11 +3138,9 @@ def powershell(cmd,
|
|||
python_shell = True
|
||||
|
||||
# Append PowerShell Object formatting
|
||||
# ConvertTo-JSON is only available on Versions of Windows greater than
|
||||
# `7.1.7600`. We have to use `platform.version` instead of `__grains__` here
|
||||
# because this function is called by `salt/grains/core.py` before
|
||||
# `__grains__` is populated
|
||||
if salt.utils.versions.version_cmp(platform.version(), '7.1.7600') == 1:
|
||||
# ConvertTo-JSON is only available on PowerShell 3.0 and later
|
||||
psversion = shell_info('powershell')['psversion']
|
||||
if salt.utils.versions.version_cmp(psversion, '2.0') == 1:
|
||||
cmd += ' | ConvertTo-JSON'
|
||||
if depth is not None:
|
||||
cmd += ' -Depth {0}'.format(depth)
|
||||
|
|
|
@ -28,26 +28,12 @@ Values/Entries are name/data pairs. There can be many values in a key. The
|
|||
from __future__ import absolute_import, print_function, unicode_literals
|
||||
|
||||
# Import python libs
|
||||
import sys
|
||||
import logging
|
||||
from salt.ext.six.moves import range # pylint: disable=W0622,import-error
|
||||
|
||||
# Import third party libs
|
||||
try:
|
||||
import win32api
|
||||
import win32con
|
||||
import pywintypes
|
||||
HAS_WINDOWS_MODULES = True
|
||||
except ImportError:
|
||||
HAS_WINDOWS_MODULES = False
|
||||
|
||||
# Import Salt libs
|
||||
import salt.utils.platform
|
||||
import salt.utils.stringutils
|
||||
import salt.utils.win_functions
|
||||
from salt.exceptions import CommandExecutionError
|
||||
|
||||
PY2 = sys.version_info[0] == 2
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
# Define the module's virtual name
|
||||
|
@ -62,99 +48,13 @@ def __virtual__():
|
|||
return (False, 'reg execution module failed to load: '
|
||||
'The module will only run on Windows systems')
|
||||
|
||||
if not HAS_WINDOWS_MODULES:
|
||||
if 'reg.read_value' not in __utils__:
|
||||
return (False, 'reg execution module failed to load: '
|
||||
'One of the following libraries did not load: '
|
||||
'win32con, win32api, pywintypes')
|
||||
'The reg salt util is unavailable')
|
||||
|
||||
return __virtualname__
|
||||
|
||||
|
||||
def _to_mbcs(vdata):
|
||||
'''
|
||||
Converts unicode to to current users character encoding. Use this for values
|
||||
returned by reg functions
|
||||
'''
|
||||
return salt.utils.stringutils.to_unicode(vdata, 'mbcs')
|
||||
|
||||
|
||||
def _to_unicode(vdata):
|
||||
'''
|
||||
Converts from current users character encoding to unicode. Use this for
|
||||
parameters being pass to reg functions
|
||||
'''
|
||||
# None does not convert to Unicode
|
||||
if vdata is None:
|
||||
return None
|
||||
return salt.utils.stringutils.to_unicode(vdata, 'utf-8')
|
||||
|
||||
|
||||
class Registry(object): # pylint: disable=R0903
|
||||
'''
|
||||
Delay usage until this module is used
|
||||
'''
|
||||
def __init__(self):
|
||||
self.hkeys = {
|
||||
'HKEY_CURRENT_CONFIG': win32con.HKEY_CURRENT_CONFIG,
|
||||
'HKEY_CLASSES_ROOT': win32con.HKEY_CLASSES_ROOT,
|
||||
'HKEY_CURRENT_USER': win32con.HKEY_CURRENT_USER,
|
||||
'HKEY_LOCAL_MACHINE': win32con.HKEY_LOCAL_MACHINE,
|
||||
'HKEY_USERS': win32con.HKEY_USERS,
|
||||
'HKCC': win32con.HKEY_CURRENT_CONFIG,
|
||||
'HKCR': win32con.HKEY_CLASSES_ROOT,
|
||||
'HKCU': win32con.HKEY_CURRENT_USER,
|
||||
'HKLM': win32con.HKEY_LOCAL_MACHINE,
|
||||
'HKU': win32con.HKEY_USERS,
|
||||
}
|
||||
self.vtype = {
|
||||
'REG_BINARY': win32con.REG_BINARY,
|
||||
'REG_DWORD': win32con.REG_DWORD,
|
||||
'REG_EXPAND_SZ': win32con.REG_EXPAND_SZ,
|
||||
'REG_MULTI_SZ': win32con.REG_MULTI_SZ,
|
||||
'REG_SZ': win32con.REG_SZ,
|
||||
'REG_QWORD': win32con.REG_QWORD
|
||||
}
|
||||
self.opttype = {
|
||||
'REG_OPTION_NON_VOLATILE': 0,
|
||||
'REG_OPTION_VOLATILE': 1
|
||||
}
|
||||
# Return Unicode due to from __future__ import unicode_literals
|
||||
self.vtype_reverse = {
|
||||
win32con.REG_BINARY: 'REG_BINARY',
|
||||
win32con.REG_DWORD: 'REG_DWORD',
|
||||
win32con.REG_EXPAND_SZ: 'REG_EXPAND_SZ',
|
||||
win32con.REG_MULTI_SZ: 'REG_MULTI_SZ',
|
||||
win32con.REG_SZ: 'REG_SZ',
|
||||
win32con.REG_QWORD: 'REG_QWORD'
|
||||
}
|
||||
self.opttype_reverse = {
|
||||
0: 'REG_OPTION_NON_VOLATILE',
|
||||
1: 'REG_OPTION_VOLATILE'
|
||||
}
|
||||
# delete_key_recursive uses this to check the subkey contains enough \
|
||||
# as we do not want to remove all or most of the registry
|
||||
self.subkey_slash_check = {
|
||||
win32con.HKEY_CURRENT_USER: 0,
|
||||
win32con.HKEY_LOCAL_MACHINE: 1,
|
||||
win32con.HKEY_USERS: 1,
|
||||
win32con.HKEY_CURRENT_CONFIG: 1,
|
||||
win32con.HKEY_CLASSES_ROOT: 1
|
||||
}
|
||||
|
||||
self.registry_32 = {
|
||||
True: win32con.KEY_READ | win32con.KEY_WOW64_32KEY,
|
||||
False: win32con.KEY_READ,
|
||||
}
|
||||
|
||||
def __getattr__(self, k):
|
||||
try:
|
||||
return self.hkeys[k]
|
||||
except KeyError:
|
||||
msg = 'No hkey named \'{0}. Try one of {1}\''
|
||||
hkeys = ', '.join(self.hkeys)
|
||||
raise CommandExecutionError(msg.format(k, hkeys))
|
||||
|
||||
|
||||
def key_exists(hive, key, use_32bit_registry=False):
|
||||
'''
|
||||
Check that the key is found in the registry. This refers to keys and not
|
||||
|
@ -167,23 +67,9 @@ def key_exists(hive, key, use_32bit_registry=False):
|
|||
:return: Returns True if found, False if not found
|
||||
:rtype: bool
|
||||
'''
|
||||
local_hive = _to_unicode(hive)
|
||||
local_key = _to_unicode(key)
|
||||
|
||||
registry = Registry()
|
||||
hkey = registry.hkeys[local_hive]
|
||||
access_mask = registry.registry_32[use_32bit_registry]
|
||||
|
||||
try:
|
||||
handle = win32api.RegOpenKeyEx(hkey, local_key, 0, access_mask)
|
||||
win32api.RegCloseKey(handle)
|
||||
return True
|
||||
except WindowsError: # pylint: disable=E0602
|
||||
return False
|
||||
except pywintypes.error as exc:
|
||||
if exc.winerror == 2:
|
||||
return False
|
||||
raise
|
||||
return __utils__['reg.key_exists'](hive=hive,
|
||||
key=key,
|
||||
use_32bit_registry=use_32bit_registry)
|
||||
|
||||
|
||||
def broadcast_change():
|
||||
|
@ -228,32 +114,9 @@ def list_keys(hive, key=None, use_32bit_registry=False):
|
|||
|
||||
salt '*' reg.list_keys HKLM 'SOFTWARE'
|
||||
'''
|
||||
|
||||
local_hive = _to_unicode(hive)
|
||||
local_key = _to_unicode(key)
|
||||
|
||||
registry = Registry()
|
||||
hkey = registry.hkeys[local_hive]
|
||||
access_mask = registry.registry_32[use_32bit_registry]
|
||||
|
||||
subkeys = []
|
||||
try:
|
||||
handle = win32api.RegOpenKeyEx(hkey, local_key, 0, access_mask)
|
||||
|
||||
for i in range(win32api.RegQueryInfoKey(handle)[0]):
|
||||
subkey = win32api.RegEnumKey(handle, i)
|
||||
if PY2:
|
||||
subkeys.append(_to_mbcs(subkey))
|
||||
else:
|
||||
subkeys.append(subkey)
|
||||
|
||||
handle.Close()
|
||||
|
||||
except pywintypes.error: # pylint: disable=E0602
|
||||
log.debug(r'Cannot find key: %s\%s', hive, key, exc_info=True)
|
||||
return False, r'Cannot find key: {0}\{1}'.format(hive, key)
|
||||
|
||||
return subkeys
|
||||
return __utils__['reg.list_keys'](hive=hive,
|
||||
key=key,
|
||||
use_32bit_registry=use_32bit_registry)
|
||||
|
||||
|
||||
def list_values(hive, key=None, use_32bit_registry=False, include_default=True):
|
||||
|
@ -285,44 +148,10 @@ def list_values(hive, key=None, use_32bit_registry=False, include_default=True):
|
|||
|
||||
salt '*' reg.list_values HKLM 'SYSTEM\\CurrentControlSet\\Services\\Tcpip'
|
||||
'''
|
||||
local_hive = _to_unicode(hive)
|
||||
local_key = _to_unicode(key)
|
||||
|
||||
registry = Registry()
|
||||
hkey = registry.hkeys[local_hive]
|
||||
access_mask = registry.registry_32[use_32bit_registry]
|
||||
handle = None
|
||||
values = list()
|
||||
|
||||
try:
|
||||
handle = win32api.RegOpenKeyEx(hkey, local_key, 0, access_mask)
|
||||
|
||||
for i in range(win32api.RegQueryInfoKey(handle)[1]):
|
||||
vname, vdata, vtype = win32api.RegEnumValue(handle, i)
|
||||
|
||||
if not vname:
|
||||
vname = "(Default)"
|
||||
|
||||
value = {'hive': local_hive,
|
||||
'key': local_key,
|
||||
'vname': _to_mbcs(vname),
|
||||
'vtype': registry.vtype_reverse[vtype],
|
||||
'success': True}
|
||||
# Only convert text types to unicode
|
||||
if vtype == win32con.REG_MULTI_SZ:
|
||||
value['vdata'] = [_to_mbcs(i) for i in vdata]
|
||||
elif vtype in [win32con.REG_SZ, win32con.REG_EXPAND_SZ]:
|
||||
value['vdata'] = _to_mbcs(vdata)
|
||||
else:
|
||||
value['vdata'] = vdata
|
||||
values.append(value)
|
||||
except pywintypes.error as exc: # pylint: disable=E0602
|
||||
log.debug(r'Cannot find key: %s\%s', hive, key, exc_info=True)
|
||||
return False, r'Cannot find key: {0}\{1}'.format(hive, key)
|
||||
finally:
|
||||
if handle:
|
||||
handle.Close()
|
||||
return values
|
||||
return __utils__['reg.list_values'](hive=hive,
|
||||
key=key,
|
||||
use_32bit_registry=use_32bit_registry,
|
||||
include_default=include_default)
|
||||
|
||||
|
||||
def read_value(hive, key, vname=None, use_32bit_registry=False):
|
||||
|
@ -362,60 +191,10 @@ def read_value(hive, key, vname=None, use_32bit_registry=False):
|
|||
|
||||
salt '*' reg.read_value HKEY_LOCAL_MACHINE 'SOFTWARE\Salt' 'version'
|
||||
'''
|
||||
# If no name is passed, the default value of the key will be returned
|
||||
# The value name is Default
|
||||
|
||||
# Setup the return array
|
||||
local_hive = _to_unicode(hive)
|
||||
local_key = _to_unicode(key)
|
||||
local_vname = _to_unicode(vname)
|
||||
|
||||
ret = {'hive': local_hive,
|
||||
'key': local_key,
|
||||
'vname': local_vname,
|
||||
'vdata': None,
|
||||
'success': True}
|
||||
|
||||
if not vname:
|
||||
ret['vname'] = '(Default)'
|
||||
|
||||
registry = Registry()
|
||||
hkey = registry.hkeys[local_hive]
|
||||
access_mask = registry.registry_32[use_32bit_registry]
|
||||
|
||||
try:
|
||||
handle = win32api.RegOpenKeyEx(hkey, local_key, 0, access_mask)
|
||||
try:
|
||||
# RegQueryValueEx returns and accepts unicode data
|
||||
vdata, vtype = win32api.RegQueryValueEx(handle, local_vname)
|
||||
if vdata or vdata in [0, '']:
|
||||
# Only convert text types to unicode
|
||||
ret['vtype'] = registry.vtype_reverse[vtype]
|
||||
if vtype == win32con.REG_MULTI_SZ:
|
||||
ret['vdata'] = [_to_mbcs(i) for i in vdata]
|
||||
elif vtype in [win32con.REG_SZ, win32con.REG_EXPAND_SZ]:
|
||||
ret['vdata'] = _to_mbcs(vdata)
|
||||
else:
|
||||
ret['vdata'] = vdata
|
||||
else:
|
||||
ret['comment'] = 'Empty Value'
|
||||
except WindowsError: # pylint: disable=E0602
|
||||
ret['vdata'] = ('(value not set)')
|
||||
ret['vtype'] = 'REG_SZ'
|
||||
except pywintypes.error as exc: # pylint: disable=E0602
|
||||
msg = 'Cannot find {0} in {1}\\{2}' \
|
||||
''.format(local_vname, local_hive, local_key)
|
||||
log.trace(exc)
|
||||
log.trace(msg)
|
||||
ret['comment'] = msg
|
||||
ret['success'] = False
|
||||
except pywintypes.error as exc: # pylint: disable=E0602
|
||||
msg = 'Cannot find key: {0}\\{1}'.format(local_hive, local_key)
|
||||
log.trace(exc)
|
||||
log.trace(msg)
|
||||
ret['comment'] = msg
|
||||
ret['success'] = False
|
||||
return ret
|
||||
return __utils__['reg.read_value'](hive=hive,
|
||||
key=key,
|
||||
vname=vname,
|
||||
use_32bit_registry=use_32bit_registry)
|
||||
|
||||
|
||||
def set_value(hive,
|
||||
|
@ -519,49 +298,13 @@ def set_value(hive,
|
|||
salt '*' reg.set_value HKEY_LOCAL_MACHINE 'SOFTWARE\\Salt' 'version' '2015.5.2' \\
|
||||
vtype=REG_LIST vdata='[a,b,c]'
|
||||
'''
|
||||
local_hive = _to_unicode(hive)
|
||||
local_key = _to_unicode(key)
|
||||
local_vname = _to_unicode(vname)
|
||||
local_vtype = _to_unicode(vtype)
|
||||
|
||||
registry = Registry()
|
||||
hkey = registry.hkeys[local_hive]
|
||||
vtype_value = registry.vtype[local_vtype]
|
||||
access_mask = registry.registry_32[use_32bit_registry] | win32con.KEY_ALL_ACCESS
|
||||
|
||||
# Check data type and cast to expected type
|
||||
# int will automatically become long on 64bit numbers
|
||||
# https://www.python.org/dev/peps/pep-0237/
|
||||
|
||||
# String Types to Unicode
|
||||
if vtype_value in [win32con.REG_SZ, win32con.REG_EXPAND_SZ]:
|
||||
local_vdata = _to_unicode(vdata)
|
||||
# Don't touch binary...
|
||||
elif vtype_value == win32con.REG_BINARY:
|
||||
local_vdata = vdata
|
||||
# Make sure REG_MULTI_SZ is a list of strings
|
||||
elif vtype_value == win32con.REG_MULTI_SZ:
|
||||
local_vdata = [_to_unicode(i) for i in vdata]
|
||||
# Everything else is int
|
||||
else:
|
||||
local_vdata = int(vdata)
|
||||
|
||||
if volatile:
|
||||
create_options = registry.opttype['REG_OPTION_VOLATILE']
|
||||
else:
|
||||
create_options = registry.opttype['REG_OPTION_NON_VOLATILE']
|
||||
|
||||
try:
|
||||
handle, _ = win32api.RegCreateKeyEx(hkey, local_key, access_mask,
|
||||
Options=create_options)
|
||||
win32api.RegSetValueEx(handle, local_vname, 0, vtype_value, local_vdata)
|
||||
win32api.RegFlushKey(handle)
|
||||
win32api.RegCloseKey(handle)
|
||||
broadcast_change()
|
||||
return True
|
||||
except (win32api.error, SystemError, ValueError, TypeError): # pylint: disable=E0602
|
||||
log.exception('Encountered error setting registry value')
|
||||
return False
|
||||
return __utils__['reg.set_value'](hive=hive,
|
||||
key=key,
|
||||
vname=vname,
|
||||
vdata=vdata,
|
||||
vtype=vtype,
|
||||
use_32bit_registry=use_32bit_registry,
|
||||
volatile=volatile)
|
||||
|
||||
|
||||
def delete_key_recursive(hive, key, use_32bit_registry=False):
|
||||
|
@ -596,73 +339,9 @@ def delete_key_recursive(hive, key, use_32bit_registry=False):
|
|||
|
||||
salt '*' reg.delete_key_recursive HKLM SOFTWARE\\salt
|
||||
'''
|
||||
|
||||
local_hive = _to_unicode(hive)
|
||||
local_key = _to_unicode(key)
|
||||
|
||||
# Instantiate the registry object
|
||||
registry = Registry()
|
||||
hkey = registry.hkeys[local_hive]
|
||||
key_path = local_key
|
||||
access_mask = registry.registry_32[use_32bit_registry] | win32con.KEY_ALL_ACCESS
|
||||
|
||||
if not key_exists(local_hive, local_key, use_32bit_registry):
|
||||
return False
|
||||
|
||||
if (len(key) > 1) and (key.count('\\', 1) < registry.subkey_slash_check[hkey]):
|
||||
log.error(
|
||||
'Hive:%s Key:%s; key is too close to root, not safe to remove',
|
||||
hive, key
|
||||
)
|
||||
return False
|
||||
|
||||
# Functions for traversing the registry tree
|
||||
def _subkeys(_key):
|
||||
'''
|
||||
Enumerate keys
|
||||
'''
|
||||
i = 0
|
||||
while True:
|
||||
try:
|
||||
subkey = win32api.RegEnumKey(_key, i)
|
||||
yield subkey
|
||||
i += 1
|
||||
except pywintypes.error: # pylint: disable=E0602
|
||||
break
|
||||
|
||||
def _traverse_registry_tree(_hkey, _keypath, _ret, _access_mask):
|
||||
'''
|
||||
Traverse the registry tree i.e. dive into the tree
|
||||
'''
|
||||
_key = win32api.RegOpenKeyEx(_hkey, _keypath, 0, _access_mask)
|
||||
for subkeyname in _subkeys(_key):
|
||||
subkeypath = r'{0}\{1}'.format(_keypath, subkeyname)
|
||||
_ret = _traverse_registry_tree(_hkey, subkeypath, _ret, access_mask)
|
||||
_ret.append(subkeypath)
|
||||
return _ret
|
||||
|
||||
# Get a reverse list of registry keys to be deleted
|
||||
key_list = []
|
||||
key_list = _traverse_registry_tree(hkey, key_path, key_list, access_mask)
|
||||
# Add the top level key last, all subkeys must be deleted first
|
||||
key_list.append(key_path)
|
||||
|
||||
ret = {'Deleted': [],
|
||||
'Failed': []}
|
||||
|
||||
# Delete all sub_keys
|
||||
for sub_key_path in key_list:
|
||||
try:
|
||||
key_handle = win32api.RegOpenKeyEx(hkey, sub_key_path, 0, access_mask)
|
||||
win32api.RegDeleteKey(key_handle, '')
|
||||
ret['Deleted'].append(r'{0}\{1}'.format(hive, sub_key_path))
|
||||
except WindowsError as exc: # pylint: disable=E0602
|
||||
log.error(exc, exc_info=True)
|
||||
ret['Failed'].append(r'{0}\{1} {2}'.format(hive, sub_key_path, exc))
|
||||
|
||||
broadcast_change()
|
||||
|
||||
return ret
|
||||
return __utils__['reg.delete_key_recursive'](hive=hive,
|
||||
key=key,
|
||||
use_32bit_registry=use_32bit_registry)
|
||||
|
||||
|
||||
def delete_value(hive, key, vname=None, use_32bit_registry=False):
|
||||
|
@ -694,27 +373,10 @@ def delete_value(hive, key, vname=None, use_32bit_registry=False):
|
|||
|
||||
salt '*' reg.delete_value HKEY_CURRENT_USER 'SOFTWARE\\Salt' 'version'
|
||||
'''
|
||||
local_hive = _to_unicode(hive)
|
||||
local_key = _to_unicode(key)
|
||||
local_vname = _to_unicode(vname)
|
||||
|
||||
registry = Registry()
|
||||
hkey = registry.hkeys[local_hive]
|
||||
access_mask = registry.registry_32[use_32bit_registry] | win32con.KEY_ALL_ACCESS
|
||||
|
||||
try:
|
||||
handle = win32api.RegOpenKeyEx(hkey, local_key, 0, access_mask)
|
||||
win32api.RegDeleteValue(handle, local_vname)
|
||||
win32api.RegCloseKey(handle)
|
||||
broadcast_change()
|
||||
return True
|
||||
except WindowsError as exc: # pylint: disable=E0602
|
||||
log.error(exc, exc_info=True)
|
||||
log.error('Hive: %s', local_hive)
|
||||
log.error('Key: %s', local_key)
|
||||
log.error('ValueName: %s', local_vname)
|
||||
log.error('32bit Reg: %s', use_32bit_registry)
|
||||
return False
|
||||
return __utils__['reg.delete_value'](hive=hive,
|
||||
key=key,
|
||||
vname=vname,
|
||||
use_32bit_registry=use_32bit_registry)
|
||||
|
||||
|
||||
def import_file(source, use_32bit_registry=False):
|
||||
|
|
|
@ -68,19 +68,19 @@ def __virtual__():
|
|||
'''
|
||||
Load this state if the reg module exists
|
||||
'''
|
||||
if 'reg.read_value' not in __salt__:
|
||||
if 'reg.read_value' not in __utils__:
|
||||
return (False, 'reg state module failed to load: '
|
||||
'missing module function: reg.read_value')
|
||||
|
||||
if 'reg.set_value' not in __salt__:
|
||||
if 'reg.set_value' not in __utils__:
|
||||
return (False, 'reg state module failed to load: '
|
||||
'missing module function: reg.set_value')
|
||||
|
||||
if 'reg.delete_value' not in __salt__:
|
||||
if 'reg.delete_value' not in __utils__:
|
||||
return (False, 'reg state module failed to load: '
|
||||
'missing module function: reg.delete_value')
|
||||
|
||||
if 'reg.delete_key_recursive' not in __salt__:
|
||||
if 'reg.delete_key_recursive' not in __utils__:
|
||||
return (False, 'reg state module failed to load: '
|
||||
'missing module function: reg.delete_key_recursive')
|
||||
|
||||
|
@ -181,10 +181,10 @@ def present(name,
|
|||
hive, key = _parse_key(name)
|
||||
|
||||
# Determine what to do
|
||||
reg_current = __salt__['reg.read_value'](hive=hive,
|
||||
key=key,
|
||||
vname=vname,
|
||||
use_32bit_registry=use_32bit_registry)
|
||||
reg_current = __utils__['reg.read_value'](hive=hive,
|
||||
key=key,
|
||||
vname=vname,
|
||||
use_32bit_registry=use_32bit_registry)
|
||||
|
||||
if vdata == reg_current['vdata'] and reg_current['success']:
|
||||
ret['comment'] = '{0} in {1} is already configured' \
|
||||
|
@ -208,12 +208,12 @@ def present(name,
|
|||
return ret
|
||||
|
||||
# Configure the value
|
||||
ret['result'] = __salt__['reg.set_value'](hive=hive,
|
||||
key=key,
|
||||
vname=vname,
|
||||
vdata=vdata,
|
||||
vtype=vtype,
|
||||
use_32bit_registry=use_32bit_registry)
|
||||
ret['result'] = __utils__['reg.set_value'](hive=hive,
|
||||
key=key,
|
||||
vname=vname,
|
||||
vdata=vdata,
|
||||
vtype=vtype,
|
||||
use_32bit_registry=use_32bit_registry)
|
||||
|
||||
if not ret['result']:
|
||||
ret['changes'] = {}
|
||||
|
@ -271,10 +271,10 @@ def absent(name, vname=None, use_32bit_registry=False):
|
|||
hive, key = _parse_key(name)
|
||||
|
||||
# Determine what to do
|
||||
reg_check = __salt__['reg.read_value'](hive=hive,
|
||||
key=key,
|
||||
vname=vname,
|
||||
use_32bit_registry=use_32bit_registry)
|
||||
reg_check = __utils__['reg.read_value'](hive=hive,
|
||||
key=key,
|
||||
vname=vname,
|
||||
use_32bit_registry=use_32bit_registry)
|
||||
if not reg_check['success'] or reg_check['vdata'] == '(value not set)':
|
||||
ret['comment'] = '{0} is already absent'.format(name)
|
||||
return ret
|
||||
|
@ -289,10 +289,10 @@ def absent(name, vname=None, use_32bit_registry=False):
|
|||
return ret
|
||||
|
||||
# Delete the value
|
||||
ret['result'] = __salt__['reg.delete_value'](hive=hive,
|
||||
key=key,
|
||||
vname=vname,
|
||||
use_32bit_registry=use_32bit_registry)
|
||||
ret['result'] = __utils__['reg.delete_value'](hive=hive,
|
||||
key=key,
|
||||
vname=vname,
|
||||
use_32bit_registry=use_32bit_registry)
|
||||
if not ret['result']:
|
||||
ret['changes'] = {}
|
||||
ret['comment'] = r'Failed to remove {0} from {1}'.format(key, hive)
|
||||
|
@ -349,9 +349,9 @@ def key_absent(name, use_32bit_registry=False):
|
|||
hive, key = _parse_key(name)
|
||||
|
||||
# Determine what to do
|
||||
if not __salt__['reg.read_value'](hive=hive,
|
||||
key=key,
|
||||
use_32bit_registry=use_32bit_registry)['success']:
|
||||
if not __utils__['reg.read_value'](hive=hive,
|
||||
key=key,
|
||||
use_32bit_registry=use_32bit_registry)['success']:
|
||||
ret['comment'] = '{0} is already absent'.format(name)
|
||||
return ret
|
||||
|
||||
|
@ -366,12 +366,12 @@ def key_absent(name, use_32bit_registry=False):
|
|||
return ret
|
||||
|
||||
# Delete the value
|
||||
__salt__['reg.delete_key_recursive'](hive=hive,
|
||||
key=key,
|
||||
use_32bit_registry=use_32bit_registry)
|
||||
if __salt__['reg.read_value'](hive=hive,
|
||||
key=key,
|
||||
use_32bit_registry=use_32bit_registry)['success']:
|
||||
__utils__['reg.delete_key_recursive'](hive=hive,
|
||||
key=key,
|
||||
use_32bit_registry=use_32bit_registry)
|
||||
if __utils__['reg.read_value'](hive=hive,
|
||||
key=key,
|
||||
use_32bit_registry=use_32bit_registry)['success']:
|
||||
ret['result'] = False
|
||||
ret['changes'] = {}
|
||||
ret['comment'] = 'Failed to remove registry key {0}'.format(name)
|
||||
|
|
720
salt/utils/win_reg.py
Normal file
720
salt/utils/win_reg.py
Normal file
|
@ -0,0 +1,720 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
'''
|
||||
Manage the Windows registry
|
||||
|
||||
-----
|
||||
Hives
|
||||
-----
|
||||
Hives are the main sections of the registry and all begin with the word HKEY.
|
||||
- HKEY_LOCAL_MACHINE
|
||||
- HKEY_CURRENT_USER
|
||||
- HKEY_USER
|
||||
|
||||
----
|
||||
Keys
|
||||
----
|
||||
Keys are the folders in the registry. Keys can have many nested subkeys. Keys
|
||||
can have a value assigned to them under the (Default)
|
||||
|
||||
-----------------
|
||||
Values or Entries
|
||||
-----------------
|
||||
Values/Entries are name/data pairs. There can be many values in a key. The
|
||||
(Default) value corresponds to the Key, the rest are their own value pairs.
|
||||
|
||||
:depends: - PyWin32
|
||||
'''
|
||||
# When production windows installer is using Python 3, Python 2 code can be removed
|
||||
from __future__ import absolute_import, print_function, unicode_literals
|
||||
|
||||
# Import python libs
|
||||
import sys
|
||||
import logging
|
||||
from salt.ext.six.moves import range # pylint: disable=W0622,import-error
|
||||
|
||||
# Import third party libs
|
||||
try:
|
||||
import win32gui
|
||||
import win32api
|
||||
import win32con
|
||||
HAS_WINDOWS_MODULES = True
|
||||
except ImportError:
|
||||
HAS_WINDOWS_MODULES = False
|
||||
|
||||
# Import Salt libs
|
||||
import salt.utils.platform
|
||||
import salt.utils.stringutils
|
||||
from salt.exceptions import CommandExecutionError
|
||||
|
||||
PY2 = sys.version_info[0] == 2
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
# Define the module's virtual name
|
||||
__virtualname__ = 'reg'
|
||||
|
||||
|
||||
def __virtual__():
|
||||
'''
|
||||
Only works on Windows systems with the PyWin32
|
||||
'''
|
||||
if not salt.utils.platform.is_windows():
|
||||
return (False, 'reg execution module failed to load: '
|
||||
'The module will only run on Windows systems')
|
||||
|
||||
if not HAS_WINDOWS_MODULES:
|
||||
return (False, 'reg execution module failed to load: '
|
||||
'One of the following libraries did not load: '
|
||||
'win32gui, win32con, win32api')
|
||||
|
||||
return __virtualname__
|
||||
|
||||
|
||||
def _to_mbcs(vdata):
|
||||
'''
|
||||
Converts unicode to to current users character encoding. Use this for values
|
||||
returned by reg functions
|
||||
'''
|
||||
return salt.utils.stringutils.to_unicode(vdata, 'mbcs')
|
||||
|
||||
|
||||
def _to_unicode(vdata):
|
||||
'''
|
||||
Converts from current users character encoding to unicode. Use this for
|
||||
parameters being pass to reg functions
|
||||
'''
|
||||
# None does not convert to Unicode
|
||||
if vdata is None:
|
||||
return None
|
||||
return salt.utils.stringutils.to_unicode(vdata, 'utf-8')
|
||||
|
||||
|
||||
class Registry(object): # pylint: disable=R0903
|
||||
'''
|
||||
Delay usage until this module is used
|
||||
'''
|
||||
def __init__(self):
|
||||
self.hkeys = {
|
||||
'HKEY_CURRENT_CONFIG': win32con.HKEY_CURRENT_CONFIG,
|
||||
'HKEY_CLASSES_ROOT': win32con.HKEY_CLASSES_ROOT,
|
||||
'HKEY_CURRENT_USER': win32con.HKEY_CURRENT_USER,
|
||||
'HKEY_LOCAL_MACHINE': win32con.HKEY_LOCAL_MACHINE,
|
||||
'HKEY_USERS': win32con.HKEY_USERS,
|
||||
'HKCC': win32con.HKEY_CURRENT_CONFIG,
|
||||
'HKCR': win32con.HKEY_CLASSES_ROOT,
|
||||
'HKCU': win32con.HKEY_CURRENT_USER,
|
||||
'HKLM': win32con.HKEY_LOCAL_MACHINE,
|
||||
'HKU': win32con.HKEY_USERS,
|
||||
}
|
||||
self.vtype = {
|
||||
'REG_BINARY': win32con.REG_BINARY,
|
||||
'REG_DWORD': win32con.REG_DWORD,
|
||||
'REG_EXPAND_SZ': win32con.REG_EXPAND_SZ,
|
||||
'REG_MULTI_SZ': win32con.REG_MULTI_SZ,
|
||||
'REG_SZ': win32con.REG_SZ,
|
||||
'REG_QWORD': win32con.REG_QWORD
|
||||
}
|
||||
self.opttype = {
|
||||
'REG_OPTION_NON_VOLATILE': 0,
|
||||
'REG_OPTION_VOLATILE': 1
|
||||
}
|
||||
# Return Unicode due to from __future__ import unicode_literals
|
||||
self.vtype_reverse = {
|
||||
win32con.REG_BINARY: 'REG_BINARY',
|
||||
win32con.REG_DWORD: 'REG_DWORD',
|
||||
win32con.REG_EXPAND_SZ: 'REG_EXPAND_SZ',
|
||||
win32con.REG_MULTI_SZ: 'REG_MULTI_SZ',
|
||||
win32con.REG_SZ: 'REG_SZ',
|
||||
win32con.REG_QWORD: 'REG_QWORD'
|
||||
}
|
||||
self.opttype_reverse = {
|
||||
0: 'REG_OPTION_NON_VOLATILE',
|
||||
1: 'REG_OPTION_VOLATILE'
|
||||
}
|
||||
# delete_key_recursive uses this to check the subkey contains enough \
|
||||
# as we do not want to remove all or most of the registry
|
||||
self.subkey_slash_check = {
|
||||
win32con.HKEY_CURRENT_USER: 0,
|
||||
win32con.HKEY_LOCAL_MACHINE: 1,
|
||||
win32con.HKEY_USERS: 1,
|
||||
win32con.HKEY_CURRENT_CONFIG: 1,
|
||||
win32con.HKEY_CLASSES_ROOT: 1
|
||||
}
|
||||
|
||||
self.registry_32 = {
|
||||
True: win32con.KEY_READ | win32con.KEY_WOW64_32KEY,
|
||||
False: win32con.KEY_READ,
|
||||
}
|
||||
|
||||
def __getattr__(self, k):
|
||||
try:
|
||||
return self.hkeys[k]
|
||||
except KeyError:
|
||||
msg = 'No hkey named \'{0}. Try one of {1}\''
|
||||
hkeys = ', '.join(self.hkeys)
|
||||
raise CommandExecutionError(msg.format(k, hkeys))
|
||||
|
||||
|
||||
def key_exists(hive, key, use_32bit_registry=False):
|
||||
'''
|
||||
Check that the key is found in the registry
|
||||
|
||||
:param str hive: The hive to connect to.
|
||||
:param str key: The key to check
|
||||
:param bool use_32bit_registry: Look in the 32bit portion of the registry
|
||||
|
||||
:return: Returns True if found, False if not found
|
||||
:rtype: bool
|
||||
'''
|
||||
local_hive = _to_unicode(hive)
|
||||
local_key = _to_unicode(key)
|
||||
|
||||
registry = Registry()
|
||||
hkey = registry.hkeys[local_hive]
|
||||
access_mask = registry.registry_32[use_32bit_registry]
|
||||
|
||||
try:
|
||||
handle = win32api.RegOpenKeyEx(hkey, local_key, 0, access_mask)
|
||||
win32api.RegCloseKey(handle)
|
||||
return True
|
||||
except Exception: # pylint: disable=E0602
|
||||
return False
|
||||
|
||||
|
||||
def broadcast_change():
|
||||
'''
|
||||
Refresh the windows environment.
|
||||
|
||||
Returns (bool): True if successful, otherwise False
|
||||
|
||||
CLI Example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
salt '*' reg.broadcast_change
|
||||
'''
|
||||
# https://msdn.microsoft.com/en-us/library/windows/desktop/ms644952(v=vs.85).aspx
|
||||
_, res = win32gui.SendMessageTimeout(
|
||||
win32con.HWND_BROADCAST, win32con.WM_SETTINGCHANGE, 0, 0,
|
||||
win32con.SMTO_ABORTIFHUNG, 5000)
|
||||
return not bool(res)
|
||||
|
||||
|
||||
def list_keys(hive, key=None, use_32bit_registry=False):
|
||||
'''
|
||||
Enumerates the subkeys in a registry key or hive.
|
||||
|
||||
:param str hive: The name of the hive. Can be one of the following
|
||||
|
||||
- HKEY_LOCAL_MACHINE or HKLM
|
||||
- HKEY_CURRENT_USER or HKCU
|
||||
- HKEY_USER or HKU
|
||||
- HKEY_CLASSES_ROOT or HKCR
|
||||
- HKEY_CURRENT_CONFIG or HKCC
|
||||
|
||||
:param str key: The key (looks like a path) to the value name. If a key is
|
||||
not passed, the keys under the hive will be returned.
|
||||
|
||||
:param bool use_32bit_registry: Accesses the 32bit portion of the registry
|
||||
on 64 bit installations. On 32bit machines this is ignored.
|
||||
|
||||
:return: A list of keys/subkeys under the hive or key.
|
||||
:rtype: list
|
||||
|
||||
CLI Example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
salt '*' reg.list_keys HKLM 'SOFTWARE'
|
||||
'''
|
||||
|
||||
local_hive = _to_unicode(hive)
|
||||
local_key = _to_unicode(key)
|
||||
|
||||
registry = Registry()
|
||||
hkey = registry.hkeys[local_hive]
|
||||
access_mask = registry.registry_32[use_32bit_registry]
|
||||
|
||||
subkeys = []
|
||||
try:
|
||||
handle = win32api.RegOpenKeyEx(hkey, local_key, 0, access_mask)
|
||||
|
||||
for i in range(win32api.RegQueryInfoKey(handle)[0]):
|
||||
subkey = win32api.RegEnumKey(handle, i)
|
||||
if PY2:
|
||||
subkeys.append(_to_mbcs(subkey))
|
||||
else:
|
||||
subkeys.append(subkey)
|
||||
|
||||
handle.Close()
|
||||
|
||||
except Exception: # pylint: disable=E0602
|
||||
log.debug(r'Cannot find key: %s\%s', hive, key, exc_info=True)
|
||||
return False, r'Cannot find key: {0}\{1}'.format(hive, key)
|
||||
|
||||
return subkeys
|
||||
|
||||
|
||||
def list_values(hive, key=None, use_32bit_registry=False, include_default=True):
|
||||
'''
|
||||
Enumerates the values in a registry key or hive.
|
||||
|
||||
:param str hive: The name of the hive. Can be one of the following
|
||||
|
||||
- HKEY_LOCAL_MACHINE or HKLM
|
||||
- HKEY_CURRENT_USER or HKCU
|
||||
- HKEY_USER or HKU
|
||||
- HKEY_CLASSES_ROOT or HKCR
|
||||
- HKEY_CURRENT_CONFIG or HKCC
|
||||
|
||||
:param str key: The key (looks like a path) to the value name. If a key is
|
||||
not passed, the values under the hive will be returned.
|
||||
|
||||
:param bool use_32bit_registry: Accesses the 32bit portion of the registry
|
||||
on 64 bit installations. On 32bit machines this is ignored.
|
||||
|
||||
:param bool include_default: Toggle whether to include the '(Default)' value.
|
||||
|
||||
:return: A list of values under the hive or key.
|
||||
:rtype: list
|
||||
|
||||
CLI Example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
salt '*' reg.list_values HKLM 'SYSTEM\\CurrentControlSet\\Services\\Tcpip'
|
||||
'''
|
||||
local_hive = _to_unicode(hive)
|
||||
local_key = _to_unicode(key)
|
||||
|
||||
registry = Registry()
|
||||
hkey = registry.hkeys[local_hive]
|
||||
access_mask = registry.registry_32[use_32bit_registry]
|
||||
handle = None
|
||||
values = list()
|
||||
|
||||
try:
|
||||
handle = win32api.RegOpenKeyEx(hkey, local_key, 0, access_mask)
|
||||
|
||||
for i in range(win32api.RegQueryInfoKey(handle)[1]):
|
||||
vname, vdata, vtype = win32api.RegEnumValue(handle, i)
|
||||
|
||||
if not vname:
|
||||
vname = "(Default)"
|
||||
|
||||
value = {'hive': local_hive,
|
||||
'key': local_key,
|
||||
'vname': _to_mbcs(vname),
|
||||
'vtype': registry.vtype_reverse[vtype],
|
||||
'success': True}
|
||||
# Only convert text types to unicode
|
||||
if vtype == win32con.REG_MULTI_SZ:
|
||||
value['vdata'] = [_to_mbcs(i) for i in vdata]
|
||||
elif vtype in [win32con.REG_SZ, win32con.REG_EXPAND_SZ]:
|
||||
value['vdata'] = _to_mbcs(vdata)
|
||||
else:
|
||||
value['vdata'] = vdata
|
||||
values.append(value)
|
||||
except Exception as exc: # pylint: disable=E0602
|
||||
log.debug(r'Cannot find key: %s\%s', hive, key, exc_info=True)
|
||||
return False, r'Cannot find key: {0}\{1}'.format(hive, key)
|
||||
finally:
|
||||
if handle:
|
||||
handle.Close()
|
||||
return values
|
||||
|
||||
|
||||
def read_value(hive, key, vname=None, use_32bit_registry=False):
|
||||
r'''
|
||||
Reads a registry value entry or the default value for a key.
|
||||
|
||||
:param str hive: The name of the hive. Can be one of the following
|
||||
|
||||
- HKEY_LOCAL_MACHINE or HKLM
|
||||
- HKEY_CURRENT_USER or HKCU
|
||||
- HKEY_USER or HKU
|
||||
- HKEY_CLASSES_ROOT or HKCR
|
||||
- HKEY_CURRENT_CONFIG or HKCC
|
||||
|
||||
:param str key: The key (looks like a path) to the value name.
|
||||
|
||||
:param str vname: The value name. These are the individual name/data pairs
|
||||
under the key. If not passed, the key (Default) value will be returned
|
||||
|
||||
:param bool use_32bit_registry: Accesses the 32bit portion of the registry
|
||||
on 64bit installations. On 32bit machines this is ignored.
|
||||
|
||||
:return: A dictionary containing the passed settings as well as the
|
||||
value_data if successful. If unsuccessful, sets success to False.
|
||||
|
||||
:rtype: dict
|
||||
|
||||
If vname is not passed:
|
||||
|
||||
- Returns the first unnamed value (Default) as a string.
|
||||
- Returns none if first unnamed value is empty.
|
||||
- Returns False if key not found.
|
||||
|
||||
CLI Example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
salt '*' reg.read_value HKEY_LOCAL_MACHINE 'SOFTWARE\Salt' 'version'
|
||||
'''
|
||||
# If no name is passed, the default value of the key will be returned
|
||||
# The value name is Default
|
||||
|
||||
# Setup the return array
|
||||
local_hive = _to_unicode(hive)
|
||||
local_key = _to_unicode(key)
|
||||
local_vname = _to_unicode(vname)
|
||||
|
||||
ret = {'hive': local_hive,
|
||||
'key': local_key,
|
||||
'vname': local_vname,
|
||||
'vdata': None,
|
||||
'success': True}
|
||||
|
||||
if not vname:
|
||||
ret['vname'] = '(Default)'
|
||||
|
||||
registry = Registry()
|
||||
hkey = registry.hkeys[local_hive]
|
||||
access_mask = registry.registry_32[use_32bit_registry]
|
||||
|
||||
try:
|
||||
handle = win32api.RegOpenKeyEx(hkey, local_key, 0, access_mask)
|
||||
try:
|
||||
# RegQueryValueEx returns and accepts unicode data
|
||||
vdata, vtype = win32api.RegQueryValueEx(handle, local_vname)
|
||||
if vdata or vdata in [0, '']:
|
||||
# Only convert text types to unicode
|
||||
ret['vtype'] = registry.vtype_reverse[vtype]
|
||||
if vtype == win32con.REG_MULTI_SZ:
|
||||
ret['vdata'] = [_to_mbcs(i) for i in vdata]
|
||||
elif vtype in [win32con.REG_SZ, win32con.REG_EXPAND_SZ]:
|
||||
ret['vdata'] = _to_mbcs(vdata)
|
||||
else:
|
||||
ret['vdata'] = vdata
|
||||
else:
|
||||
ret['comment'] = 'Empty Value'
|
||||
except Exception as exc:
|
||||
if exc.winerror == 2 and vname is None:
|
||||
ret['vdata'] = ('(value not set)')
|
||||
ret['vtype'] = 'REG_SZ'
|
||||
else:
|
||||
msg = 'Cannot find {0} in {1}\\{2}' \
|
||||
''.format(local_vname, local_hive, local_key)
|
||||
log.trace(exc)
|
||||
log.trace(msg)
|
||||
ret['comment'] = msg
|
||||
ret['success'] = False
|
||||
except Exception as exc: # pylint: disable=E0602
|
||||
msg = 'Cannot find key: {0}\\{1}'.format(local_hive, local_key)
|
||||
log.trace(exc)
|
||||
log.trace(msg)
|
||||
ret['comment'] = msg
|
||||
ret['success'] = False
|
||||
return ret
|
||||
|
||||
|
||||
def set_value(hive,
|
||||
key,
|
||||
vname=None,
|
||||
vdata=None,
|
||||
vtype='REG_SZ',
|
||||
use_32bit_registry=False,
|
||||
volatile=False):
|
||||
'''
|
||||
Sets a registry value entry or the default value for a key.
|
||||
|
||||
:param str hive: The name of the hive. Can be one of the following
|
||||
|
||||
- HKEY_LOCAL_MACHINE or HKLM
|
||||
- HKEY_CURRENT_USER or HKCU
|
||||
- HKEY_USER or HKU
|
||||
- HKEY_CLASSES_ROOT or HKCR
|
||||
- HKEY_CURRENT_CONFIG or HKCC
|
||||
|
||||
:param str key: The key (looks like a path) to the value name.
|
||||
|
||||
:param str vname: The value name. These are the individual name/data pairs
|
||||
under the key. If not passed, the key (Default) value will be set.
|
||||
|
||||
:param object vdata: The value data to be set.
|
||||
What the type of this parameter
|
||||
should be is determined by the value of the vtype
|
||||
parameter. The correspondence
|
||||
is as follows:
|
||||
|
||||
.. glossary::
|
||||
|
||||
REG_BINARY
|
||||
binary data (i.e. str in python version < 3 and bytes in version >=3)
|
||||
REG_DWORD
|
||||
int
|
||||
REG_EXPAND_SZ
|
||||
str
|
||||
REG_MULTI_SZ
|
||||
list of objects of type str
|
||||
REG_SZ
|
||||
str
|
||||
|
||||
:param str vtype: The value type.
|
||||
The possible values of the vtype parameter are indicated
|
||||
above in the description of the vdata parameter.
|
||||
|
||||
:param bool use_32bit_registry: Sets the 32bit portion of the registry on
|
||||
64bit installations. On 32bit machines this is ignored.
|
||||
|
||||
:param bool volatile: When this parameter has a value of True, the registry key will be
|
||||
made volatile (i.e. it will not persist beyond a system reset or shutdown).
|
||||
This parameter only has an effect when a key is being created and at no
|
||||
other time.
|
||||
|
||||
:return: Returns True if successful, False if not
|
||||
:rtype: bool
|
||||
|
||||
CLI Example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
salt '*' reg.set_value HKEY_LOCAL_MACHINE 'SOFTWARE\\Salt' 'version' '2015.5.2'
|
||||
|
||||
This function is strict about the type of vdata. For instance the
|
||||
the next example will fail because vtype has a value of REG_SZ and vdata
|
||||
has a type of int (as opposed to str as expected).
|
||||
|
||||
CLI Example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
salt '*' reg.set_value HKEY_LOCAL_MACHINE 'SOFTWARE\\Salt' 'version' '2015.5.2' \\
|
||||
vtype=REG_SZ vdata=0
|
||||
|
||||
However, this next example where vdata is properly quoted should succeed.
|
||||
|
||||
CLI Example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
salt '*' reg.set_value HKEY_LOCAL_MACHINE 'SOFTWARE\\Salt' 'version' '2015.5.2' \\
|
||||
vtype=REG_SZ vdata="'0'"
|
||||
|
||||
An example of using vtype REG_BINARY is as follows:
|
||||
|
||||
CLI Example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
salt '*' reg.set_value HKEY_LOCAL_MACHINE 'SOFTWARE\\Salt' 'version' '2015.5.2' \\
|
||||
vtype=REG_BINARY vdata='!!binary d2hhdCdzIHRoZSBwb2ludA=='
|
||||
|
||||
An example of using vtype REG_LIST is as follows:
|
||||
|
||||
CLI Example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
salt '*' reg.set_value HKEY_LOCAL_MACHINE 'SOFTWARE\\Salt' 'version' '2015.5.2' \\
|
||||
vtype=REG_LIST vdata='[a,b,c]'
|
||||
'''
|
||||
local_hive = _to_unicode(hive)
|
||||
local_key = _to_unicode(key)
|
||||
local_vname = _to_unicode(vname)
|
||||
local_vtype = _to_unicode(vtype)
|
||||
|
||||
registry = Registry()
|
||||
hkey = registry.hkeys[local_hive]
|
||||
vtype_value = registry.vtype[local_vtype]
|
||||
access_mask = registry.registry_32[use_32bit_registry] | win32con.KEY_ALL_ACCESS
|
||||
|
||||
# Check data type and cast to expected type
|
||||
# int will automatically become long on 64bit numbers
|
||||
# https://www.python.org/dev/peps/pep-0237/
|
||||
|
||||
# String Types to Unicode
|
||||
if vtype_value in [win32con.REG_SZ, win32con.REG_EXPAND_SZ]:
|
||||
local_vdata = _to_unicode(vdata)
|
||||
# Don't touch binary...
|
||||
elif vtype_value == win32con.REG_BINARY:
|
||||
local_vdata = vdata
|
||||
# Make sure REG_MULTI_SZ is a list of strings
|
||||
elif vtype_value == win32con.REG_MULTI_SZ:
|
||||
local_vdata = [_to_unicode(i) for i in vdata]
|
||||
# Everything else is int
|
||||
else:
|
||||
local_vdata = int(vdata)
|
||||
|
||||
if volatile:
|
||||
create_options = registry.opttype['REG_OPTION_VOLATILE']
|
||||
else:
|
||||
create_options = registry.opttype['REG_OPTION_NON_VOLATILE']
|
||||
|
||||
try:
|
||||
handle, _ = win32api.RegCreateKeyEx(hkey, local_key, access_mask,
|
||||
Options=create_options)
|
||||
win32api.RegSetValueEx(handle, local_vname, 0, vtype_value, local_vdata)
|
||||
win32api.RegFlushKey(handle)
|
||||
win32api.RegCloseKey(handle)
|
||||
broadcast_change()
|
||||
return True
|
||||
except (win32api.error, SystemError, ValueError, TypeError): # pylint: disable=E0602
|
||||
log.exception('Encountered error setting registry value')
|
||||
return False
|
||||
|
||||
|
||||
def delete_key_recursive(hive, key, use_32bit_registry=False):
|
||||
'''
|
||||
.. versionadded:: 2015.5.4
|
||||
|
||||
Delete a registry key to include all subkeys.
|
||||
|
||||
:param hive: The name of the hive. Can be one of the following
|
||||
|
||||
- HKEY_LOCAL_MACHINE or HKLM
|
||||
- HKEY_CURRENT_USER or HKCU
|
||||
- HKEY_USER or HKU
|
||||
- HKEY_CLASSES_ROOT or HKCR
|
||||
- HKEY_CURRENT_CONFIG or HKCC
|
||||
|
||||
:param key: The key to remove (looks like a path)
|
||||
|
||||
:param bool use_32bit_registry: Deletes the 32bit portion of the registry on
|
||||
64bit installations. On 32bit machines this is ignored.
|
||||
|
||||
:return: A dictionary listing the keys that deleted successfully as well as
|
||||
those that failed to delete.
|
||||
:rtype: dict
|
||||
|
||||
The following example will remove ``salt`` and all its subkeys from the
|
||||
``SOFTWARE`` key in ``HKEY_LOCAL_MACHINE``:
|
||||
|
||||
CLI Example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
salt '*' reg.delete_key_recursive HKLM SOFTWARE\\salt
|
||||
'''
|
||||
|
||||
local_hive = _to_unicode(hive)
|
||||
local_key = _to_unicode(key)
|
||||
|
||||
# Instantiate the registry object
|
||||
registry = Registry()
|
||||
hkey = registry.hkeys[local_hive]
|
||||
key_path = local_key
|
||||
access_mask = registry.registry_32[use_32bit_registry] | win32con.KEY_ALL_ACCESS
|
||||
|
||||
if not key_exists(local_hive, local_key, use_32bit_registry):
|
||||
return False
|
||||
|
||||
if (len(key) > 1) and (key.count('\\', 1) < registry.subkey_slash_check[hkey]):
|
||||
log.error(
|
||||
'Hive:%s Key:%s; key is too close to root, not safe to remove',
|
||||
hive, key
|
||||
)
|
||||
return False
|
||||
|
||||
# Functions for traversing the registry tree
|
||||
def _subkeys(_key):
|
||||
'''
|
||||
Enumerate keys
|
||||
'''
|
||||
i = 0
|
||||
while True:
|
||||
try:
|
||||
subkey = win32api.RegEnumKey(_key, i)
|
||||
yield _to_mbcs(subkey)
|
||||
i += 1
|
||||
except Exception: # pylint: disable=E0602
|
||||
break
|
||||
|
||||
def _traverse_registry_tree(_hkey, _keypath, _ret, _access_mask):
|
||||
'''
|
||||
Traverse the registry tree i.e. dive into the tree
|
||||
'''
|
||||
_key = win32api.RegOpenKeyEx(_hkey, _keypath, 0, _access_mask)
|
||||
for subkeyname in _subkeys(_key):
|
||||
subkeypath = '{0}\\{1}'.format(_keypath, subkeyname)
|
||||
_ret = _traverse_registry_tree(_hkey, subkeypath, _ret, access_mask)
|
||||
_ret.append(subkeypath)
|
||||
return _ret
|
||||
|
||||
# Get a reverse list of registry keys to be deleted
|
||||
key_list = []
|
||||
key_list = _traverse_registry_tree(hkey, key_path, key_list, access_mask)
|
||||
# Add the top level key last, all subkeys must be deleted first
|
||||
key_list.append(key_path)
|
||||
|
||||
ret = {'Deleted': [],
|
||||
'Failed': []}
|
||||
|
||||
# Delete all sub_keys
|
||||
for sub_key_path in key_list:
|
||||
try:
|
||||
key_handle = win32api.RegOpenKeyEx(hkey, sub_key_path, 0, access_mask)
|
||||
win32api.RegDeleteKey(key_handle, '')
|
||||
ret['Deleted'].append(r'{0}\{1}'.format(hive, sub_key_path))
|
||||
except WindowsError as exc: # pylint: disable=E0602
|
||||
log.error(exc, exc_info=True)
|
||||
ret['Failed'].append(r'{0}\{1} {2}'.format(hive, sub_key_path, exc))
|
||||
|
||||
broadcast_change()
|
||||
|
||||
return ret
|
||||
|
||||
|
||||
def delete_value(hive, key, vname=None, use_32bit_registry=False):
|
||||
'''
|
||||
Delete a registry value entry or the default value for a key.
|
||||
|
||||
:param str hive: The name of the hive. Can be one of the following
|
||||
|
||||
- HKEY_LOCAL_MACHINE or HKLM
|
||||
- HKEY_CURRENT_USER or HKCU
|
||||
- HKEY_USER or HKU
|
||||
- HKEY_CLASSES_ROOT or HKCR
|
||||
- HKEY_CURRENT_CONFIG or HKCC
|
||||
|
||||
:param str key: The key (looks like a path) to the value name.
|
||||
|
||||
:param str vname: The value name. These are the individual name/data pairs
|
||||
under the key. If not passed, the key (Default) value will be deleted.
|
||||
|
||||
:param bool use_32bit_registry: Deletes the 32bit portion of the registry on
|
||||
64bit installations. On 32bit machines this is ignored.
|
||||
|
||||
:return: Returns True if successful, None if the value didn't exist, and
|
||||
False if unsuccessful
|
||||
:rtype: bool
|
||||
|
||||
CLI Example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
salt '*' reg.delete_value HKEY_CURRENT_USER 'SOFTWARE\\Salt' 'version'
|
||||
'''
|
||||
local_hive = _to_unicode(hive)
|
||||
local_key = _to_unicode(key)
|
||||
local_vname = _to_unicode(vname)
|
||||
|
||||
registry = Registry()
|
||||
hkey = registry.hkeys[local_hive]
|
||||
access_mask = registry.registry_32[use_32bit_registry] | win32con.KEY_ALL_ACCESS
|
||||
|
||||
try:
|
||||
handle = win32api.RegOpenKeyEx(hkey, local_key, 0, access_mask)
|
||||
win32api.RegDeleteValue(handle, local_vname)
|
||||
win32api.RegCloseKey(handle)
|
||||
broadcast_change()
|
||||
return True
|
||||
except Exception as exc: # pylint: disable=E0602
|
||||
if exc.winerror == 2:
|
||||
return None
|
||||
else:
|
||||
log.error(exc, exc_info=True)
|
||||
log.error('Hive: %s', local_hive)
|
||||
log.error('Key: %s', local_key)
|
||||
log.error('ValueName: %s', local_vname)
|
||||
log.error('32bit Reg: %s', use_32bit_registry)
|
||||
return False
|
|
@ -1,301 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
'''
|
||||
:synopsis: Unit Tests for Windows Registry Module 'module.reg'
|
||||
:platform: Windows
|
||||
:maturity: develop
|
||||
:codeauthor: Damon Atkins <https://github.com/damon-atkins>
|
||||
versionadded:: 2016.11.0
|
||||
'''
|
||||
# Import Python future libs
|
||||
from __future__ import absolute_import, print_function, unicode_literals
|
||||
# Import Python Libs
|
||||
import sys
|
||||
import time
|
||||
# Import Salt Testing Libs
|
||||
from tests.support.unit import TestCase, skipIf
|
||||
from tests.support.helpers import destructiveTest
|
||||
# Import Salt Libs
|
||||
import salt.modules.reg as win_mod_reg
|
||||
from salt.ext import six
|
||||
try:
|
||||
from salt.ext.six.moves import winreg as _winreg # pylint: disable=import-error,no-name-in-module
|
||||
NO_WINDOWS_MODULES = False
|
||||
except ImportError:
|
||||
NO_WINDOWS_MODULES = True
|
||||
|
||||
PY2 = sys.version_info[0] == 2
|
||||
# The following used to make sure we are not
|
||||
# testing already existing data
|
||||
# Note strftime returns a str, so we need to make it unicode
|
||||
TIMEINT = int(time.time())
|
||||
|
||||
if PY2:
|
||||
TIME_INT_UNICODE = six.text_type(TIMEINT)
|
||||
TIMESTR = time.strftime('%X %x %Z').decode('utf-8')
|
||||
else:
|
||||
TIMESTR = time.strftime('%X %x %Z')
|
||||
TIME_INT_UNICODE = str(TIMEINT) # pylint: disable=R0204
|
||||
|
||||
|
||||
# we do not need to prefix this with u, as we are
|
||||
# using from __future__ import unicode_literals
|
||||
UNICODETEST_WITH_SIGNS = 'Testing Unicode \N{COPYRIGHT SIGN},\N{TRADE MARK SIGN},\N{REGISTERED SIGN} '+TIMESTR
|
||||
UNICODETEST_WITHOUT_SIGNS = 'Testing Unicode'+TIMESTR
|
||||
UNICODE_TEST_KEY = 'UnicodeKey \N{TRADE MARK SIGN} '+TIME_INT_UNICODE
|
||||
UNICODE_TEST_KEY_DEL = 'Delete Me \N{TRADE MARK SIGN} '+TIME_INT_UNICODE
|
||||
|
||||
|
||||
@skipIf(NO_WINDOWS_MODULES, 'requires Windows OS to test Windows registry')
|
||||
class RegWinTestCase(TestCase):
|
||||
'''
|
||||
Test cases for salt.modules.reg
|
||||
'''
|
||||
|
||||
@skipIf(not sys.platform.startswith("win"), "requires Windows OS")
|
||||
def test_read_reg_plain(self):
|
||||
'''
|
||||
Test - Read a registry value from a subkey using Pythen 2 Strings or
|
||||
Pythen 3 Bytes
|
||||
'''
|
||||
if not PY2:
|
||||
self.skipTest('Invalid for Python Version 2')
|
||||
|
||||
subkey = b'Software\\Microsoft\\Windows NT\\CurrentVersion'
|
||||
vname = b'PathName'
|
||||
handle = _winreg.OpenKey(
|
||||
_winreg.HKEY_LOCAL_MACHINE,
|
||||
subkey,
|
||||
0,
|
||||
_winreg.KEY_ALL_ACCESS
|
||||
)
|
||||
(current_vdata, dummy_current_vtype) = _winreg.QueryValueEx(handle, vname)
|
||||
_winreg.CloseKey(handle)
|
||||
|
||||
test_vdata = win_mod_reg.read_value(b'HKEY_LOCAL_MACHINE', subkey, vname)[b'vdata']
|
||||
self.assertEqual(
|
||||
test_vdata, current_vdata)
|
||||
|
||||
@skipIf(not sys.platform.startswith("win"), "requires Windows OS")
|
||||
def test_read_reg_unicode(self):
|
||||
'''
|
||||
Test - Read a registry value from a subkey using Pythen 2 Unicode
|
||||
or Pythen 3 Str i.e. Unicode
|
||||
'''
|
||||
subkey = 'Software\\Microsoft\\Windows NT\\CurrentVersion'
|
||||
vname = 'PathName'
|
||||
handle = _winreg.OpenKey(
|
||||
_winreg.HKEY_LOCAL_MACHINE,
|
||||
subkey,
|
||||
0,
|
||||
_winreg.KEY_ALL_ACCESS
|
||||
)
|
||||
(current_vdata, dummy_current_vtype) = _winreg.QueryValueEx(handle, vname)
|
||||
_winreg.CloseKey(handle)
|
||||
|
||||
test_vdata = win_mod_reg.read_value(
|
||||
'HKEY_LOCAL_MACHINE',
|
||||
subkey,
|
||||
vname)['vdata']
|
||||
self.assertEqual(test_vdata, current_vdata)
|
||||
|
||||
@skipIf(not sys.platform.startswith("win"), "requires Windows OS")
|
||||
def test_list_keys_fail(self):
|
||||
'''
|
||||
Test - Read list the keys under a subkey which does not exist.
|
||||
'''
|
||||
subkey = 'ThisIsJunkItDoesNotExistIhope'
|
||||
test_list = win_mod_reg.list_keys('HKEY_LOCAL_MACHINE', subkey)
|
||||
# returns a tuple with first item false, and second item a reason
|
||||
test = isinstance(test_list, tuple) and (not test_list[0])
|
||||
self.assertTrue(test)
|
||||
|
||||
@skipIf(not sys.platform.startswith("win"), "requires Windows OS")
|
||||
def test_list_keys(self):
|
||||
'''
|
||||
Test - Read list the keys under a subkey
|
||||
'''
|
||||
subkey = 'Software\\Microsoft\\Windows NT\\CurrentVersion'
|
||||
test_list = win_mod_reg.list_keys('HKEY_LOCAL_MACHINE', subkey)
|
||||
test = len(test_list) > 5 # Their should be a lot more than 5 items
|
||||
self.assertTrue(test)
|
||||
|
||||
@skipIf(not sys.platform.startswith("win"), "requires Windows OS")
|
||||
def test_list_values_fail(self):
|
||||
'''
|
||||
Test - List the values under a subkey which does not exist.
|
||||
'''
|
||||
subkey = 'ThisIsJunkItDoesNotExistIhope'
|
||||
test_list = win_mod_reg.list_values('HKEY_LOCAL_MACHINE', subkey)
|
||||
# returns a tuple with first item false, and second item a reason
|
||||
test = isinstance(test_list, tuple) and (not test_list[0])
|
||||
self.assertTrue(test)
|
||||
|
||||
@skipIf(not sys.platform.startswith("win"), "requires Windows OS")
|
||||
def test_list_values(self):
|
||||
'''
|
||||
Test - List the values under a subkey.
|
||||
'''
|
||||
subkey = r'Software\Microsoft\Windows NT\CurrentVersion'
|
||||
test_list = win_mod_reg.list_values('HKEY_LOCAL_MACHINE', subkey)
|
||||
test = len(test_list) > 5 # There should be a lot more than 5 items
|
||||
self.assertTrue(test)
|
||||
|
||||
# Not considering this destructive as its writing to a private space
|
||||
@skipIf(not sys.platform.startswith("win"), "requires Windows OS")
|
||||
def test_set_value_unicode(self):
|
||||
'''
|
||||
Test - set a registry plain text subkey name to a unicode string value
|
||||
'''
|
||||
vname = 'TestUniccodeString'
|
||||
subkey = 'Software\\SaltStackTest'
|
||||
test1_success = False
|
||||
test2_success = False
|
||||
test1_success = win_mod_reg.set_value(
|
||||
'HKEY_LOCAL_MACHINE',
|
||||
subkey,
|
||||
vname,
|
||||
UNICODETEST_WITH_SIGNS
|
||||
)
|
||||
# Now use _winreg direct to see if it worked as expected
|
||||
if test1_success:
|
||||
handle = _winreg.OpenKey(
|
||||
_winreg.HKEY_LOCAL_MACHINE,
|
||||
subkey,
|
||||
0,
|
||||
_winreg.KEY_ALL_ACCESS
|
||||
)
|
||||
(current_vdata, dummy_current_vtype) = _winreg.QueryValueEx(handle, vname)
|
||||
_winreg.CloseKey(handle)
|
||||
test2_success = (current_vdata == UNICODETEST_WITH_SIGNS)
|
||||
self.assertTrue(test1_success and test2_success)
|
||||
|
||||
@skipIf(not sys.platform.startswith("win"), "requires Windows OS")
|
||||
def test_set_value_unicode_key(self):
|
||||
'''
|
||||
Test - set a registry Unicode subkey name with unicode characters within
|
||||
to a integer
|
||||
'''
|
||||
test_success = win_mod_reg.set_value(
|
||||
'HKEY_LOCAL_MACHINE',
|
||||
'Software\\SaltStackTest',
|
||||
UNICODE_TEST_KEY,
|
||||
TIMEINT,
|
||||
'REG_DWORD'
|
||||
)
|
||||
self.assertTrue(test_success)
|
||||
|
||||
@skipIf(not sys.platform.startswith("win"), "requires Windows OS")
|
||||
def test_del_value(self):
|
||||
'''
|
||||
Test - Create Directly and Delete with salt a registry value
|
||||
'''
|
||||
subkey = 'Software\\SaltStackTest'
|
||||
vname = UNICODE_TEST_KEY_DEL
|
||||
vdata = 'I will be deleted'
|
||||
if PY2:
|
||||
handle = _winreg.CreateKeyEx(
|
||||
_winreg.HKEY_LOCAL_MACHINE,
|
||||
subkey.encode('mbcs'),
|
||||
0,
|
||||
_winreg.KEY_ALL_ACCESS
|
||||
)
|
||||
_winreg.SetValueEx(
|
||||
handle,
|
||||
vname.encode('mbcs'),
|
||||
0,
|
||||
_winreg.REG_SZ,
|
||||
vdata.encode('mbcs')
|
||||
)
|
||||
else:
|
||||
handle = _winreg.CreateKeyEx(
|
||||
_winreg.HKEY_LOCAL_MACHINE,
|
||||
subkey,
|
||||
0,
|
||||
_winreg.KEY_ALL_ACCESS
|
||||
)
|
||||
_winreg.SetValueEx(handle, vname, 0, _winreg.REG_SZ, vdata)
|
||||
_winreg.CloseKey(handle)
|
||||
# time.sleep(15) # delays for 15 seconds
|
||||
test_success = win_mod_reg.delete_value(
|
||||
'HKEY_LOCAL_MACHINE',
|
||||
subkey,
|
||||
vname
|
||||
)
|
||||
self.assertTrue(test_success)
|
||||
|
||||
@skipIf(not sys.platform.startswith("win"), "requires Windows OS")
|
||||
def test_del_key_recursive_user(self):
|
||||
'''
|
||||
Test - Create directly key/value pair and Delete recusivly with salt
|
||||
'''
|
||||
subkey = 'Software\\SaltStackTest'
|
||||
vname = UNICODE_TEST_KEY_DEL
|
||||
vdata = 'I will be deleted recursive'
|
||||
if PY2:
|
||||
handle = _winreg.CreateKeyEx(
|
||||
_winreg.HKEY_CURRENT_USER,
|
||||
subkey.encode('mbcs'),
|
||||
0,
|
||||
_winreg.KEY_ALL_ACCESS
|
||||
)
|
||||
_winreg.SetValueEx(
|
||||
handle,
|
||||
vname.encode('mbcs'),
|
||||
0,
|
||||
_winreg.REG_SZ,
|
||||
vdata.encode('mbcs')
|
||||
)
|
||||
else:
|
||||
handle = _winreg.CreateKeyEx(
|
||||
_winreg.HKEY_CURRENT_USER,
|
||||
subkey,
|
||||
0,
|
||||
_winreg.KEY_ALL_ACCESS
|
||||
)
|
||||
_winreg.SetValueEx(handle, vname, 0, _winreg.REG_SZ, vdata)
|
||||
_winreg.CloseKey(handle)
|
||||
# time.sleep(15) # delays for 15 seconds so you can run regedit & watch it happen
|
||||
test_success = win_mod_reg.delete_key_recursive('HKEY_CURRENT_USER', subkey)
|
||||
self.assertTrue(test_success)
|
||||
|
||||
@skipIf(not sys.platform.startswith("win"), "requires Windows OS")
|
||||
@destructiveTest
|
||||
def test_del_key_recursive_machine(self):
|
||||
'''
|
||||
This is a DESTRUCTIVE TEST it creates a new registry entry.
|
||||
And then destroys the registry entry recusively , however it is completed in its own space
|
||||
within the registry. We mark this as destructiveTest as it has the potential
|
||||
to detroy a machine if salt reg code has a large error in it.
|
||||
'''
|
||||
subkey = 'Software\\SaltStackTest'
|
||||
vname = UNICODE_TEST_KEY_DEL
|
||||
vdata = 'I will be deleted recursive'
|
||||
if PY2:
|
||||
handle = _winreg.CreateKeyEx(
|
||||
_winreg.HKEY_LOCAL_MACHINE,
|
||||
subkey.encode('mbcs'),
|
||||
0,
|
||||
_winreg.KEY_ALL_ACCESS
|
||||
)
|
||||
_winreg.SetValueEx(
|
||||
handle,
|
||||
vname.encode('mbcs'),
|
||||
0,
|
||||
_winreg.REG_SZ,
|
||||
vdata.encode('mbcs')
|
||||
)
|
||||
else:
|
||||
handle = _winreg.CreateKeyEx(
|
||||
_winreg.HKEY_LOCAL_MACHINE,
|
||||
subkey,
|
||||
0,
|
||||
_winreg.KEY_ALL_ACCESS
|
||||
)
|
||||
_winreg.SetValueEx(handle, vname, 0, _winreg.REG_SZ, vdata)
|
||||
_winreg.CloseKey(handle)
|
||||
# time.sleep(15) # delays for 15 seconds so you can run regedit and watch it happen
|
||||
test_success = win_mod_reg.delete_key_recursive('HKEY_LOCAL_MACHINE', subkey)
|
||||
self.assertTrue(test_success)
|
||||
|
||||
# pylint: disable=W0511
|
||||
# TODO: Test other hives, other than HKEY_LOCAL_MACHINE and HKEY_CURRENT_USER
|
|
@ -17,9 +17,11 @@ from tests.support.mock import (
|
|||
|
||||
# Import Salt Libs
|
||||
import salt.states.reg as reg
|
||||
import salt.utils.platform
|
||||
|
||||
|
||||
@skipIf(NO_MOCK, NO_MOCK_REASON)
|
||||
@skipIf(not salt.utils.platform.is_windows(), 'System is not Windows')
|
||||
class RegTestCase(TestCase, LoaderModuleMockMixin):
|
||||
'''
|
||||
Test cases for salt.states.reg
|
||||
|
@ -46,7 +48,7 @@ class RegTestCase(TestCase, LoaderModuleMockMixin):
|
|||
{'vdata': 'a', 'success': True},
|
||||
{'vdata': 'a', 'success': True}])
|
||||
mock_t = MagicMock(return_value=True)
|
||||
with patch.dict(reg.__salt__, {'reg.read_value': mock_read,
|
||||
with patch.dict(reg.__utils__, {'reg.read_value': mock_read,
|
||||
'reg.set_value': mock_t}):
|
||||
self.assertDictEqual(reg.present(name,
|
||||
vname=vname,
|
||||
|
@ -92,17 +94,17 @@ class RegTestCase(TestCase, LoaderModuleMockMixin):
|
|||
mock_read_false = MagicMock(return_value={'success': False, 'vdata': False})
|
||||
|
||||
mock_t = MagicMock(return_value=True)
|
||||
with patch.dict(reg.__salt__, {'reg.read_value': mock_read_false,
|
||||
with patch.dict(reg.__utils__, {'reg.read_value': mock_read_false,
|
||||
'reg.delete_value': mock_t}):
|
||||
self.assertDictEqual(reg.absent(name, vname), ret)
|
||||
|
||||
with patch.dict(reg.__salt__, {'reg.read_value': mock_read_true}):
|
||||
with patch.dict(reg.__utils__, {'reg.read_value': mock_read_true}):
|
||||
with patch.dict(reg.__opts__, {'test': True}):
|
||||
ret.update({'comment': '', 'result': None,
|
||||
'changes': {'reg': {'Will remove': {'Entry': vname, 'Key': name}}}})
|
||||
self.assertDictEqual(reg.absent(name, vname), ret)
|
||||
|
||||
with patch.dict(reg.__salt__, {'reg.read_value': mock_read_true,
|
||||
with patch.dict(reg.__utils__, {'reg.read_value': mock_read_true,
|
||||
'reg.delete_value': mock_t}):
|
||||
with patch.dict(reg.__opts__, {'test': False}):
|
||||
ret.update({'result': True,
|
||||
|
|
397
tests/unit/utils/test_win_reg.py
Normal file
397
tests/unit/utils/test_win_reg.py
Normal file
|
@ -0,0 +1,397 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Import Python Libs
|
||||
from __future__ import absolute_import, unicode_literals, print_function
|
||||
|
||||
# Import Salt Testing Libs
|
||||
from tests.support.helpers import destructiveTest, generate_random_name
|
||||
from tests.support.mock import NO_MOCK, NO_MOCK_REASON, patch
|
||||
from tests.support.unit import TestCase, skipIf
|
||||
|
||||
# Import Salt Libs
|
||||
import salt.utils.platform
|
||||
import salt.utils.win_reg as win_reg
|
||||
|
||||
UNICODE_KEY = 'Unicode Key \N{TRADE MARK SIGN}'
|
||||
UNICODE_VALUE = 'Unicode Value ' \
|
||||
'\N{COPYRIGHT SIGN},\N{TRADE MARK SIGN},\N{REGISTERED SIGN}'
|
||||
FAKE_KEY = 'SOFTWARE\\{0}'.format(generate_random_name('SaltTesting-'))
|
||||
|
||||
|
||||
@skipIf(NO_MOCK, NO_MOCK_REASON)
|
||||
@skipIf(not salt.utils.platform.is_windows(), 'System is not Windows')
|
||||
class WinFunctionsTestCase(TestCase):
|
||||
'''
|
||||
Test cases for salt.utils.win_reg
|
||||
'''
|
||||
def test_broadcast_change_success(self):
|
||||
'''
|
||||
Tests the broadcast_change function
|
||||
'''
|
||||
with patch('win32gui.SendMessageTimeout', return_value=('', 0)):
|
||||
self.assertEqual(win_reg.broadcast_change(), True)
|
||||
|
||||
def test_broadcast_change_fail(self):
|
||||
'''
|
||||
Tests the broadcast_change function failure
|
||||
'''
|
||||
with patch('win32gui.SendMessageTimeout', return_value=('', 1)):
|
||||
self.assertEqual(win_reg.broadcast_change(), False)
|
||||
|
||||
def test_key_exists_existing(self):
|
||||
'''
|
||||
Tests the key exists function using a well known registry key
|
||||
'''
|
||||
self.assertEqual(
|
||||
win_reg.key_exists(
|
||||
hive='HKLM',
|
||||
key='SOFTWARE\\Microsoft'
|
||||
),
|
||||
True
|
||||
)
|
||||
|
||||
def test_key_exists_non_existing(self):
|
||||
'''
|
||||
Tests the key exists function using a non existing registry key
|
||||
'''
|
||||
self.assertEqual(
|
||||
win_reg.key_exists(
|
||||
hive='HKLM',
|
||||
key=FAKE_KEY
|
||||
),
|
||||
False
|
||||
)
|
||||
|
||||
def test_list_keys_existing(self):
|
||||
'''
|
||||
Test the list_keys function using a well known registry key
|
||||
'''
|
||||
self.assertIn(
|
||||
'Microsoft',
|
||||
win_reg.list_keys(
|
||||
hive='HKLM',
|
||||
key='SOFTWARE'
|
||||
)
|
||||
)
|
||||
|
||||
def test_list_keys_non_existing(self):
|
||||
'''
|
||||
Test the list_keys function using a non existing registry key
|
||||
'''
|
||||
expected = (False, 'Cannot find key: HKLM\\{0}'.format(FAKE_KEY))
|
||||
self.assertEqual(
|
||||
win_reg.list_keys(
|
||||
hive='HKLM',
|
||||
key=FAKE_KEY
|
||||
),
|
||||
expected
|
||||
)
|
||||
|
||||
def test_list_values_existing(self):
|
||||
'''
|
||||
Test the list_values function using a well known registry key
|
||||
'''
|
||||
values = win_reg.list_values(
|
||||
hive='HKLM',
|
||||
key='SOFTWARE\\Microsoft\\Windows\\CurrentVersion'
|
||||
)
|
||||
keys = []
|
||||
for value in values:
|
||||
keys.append(value['vname'])
|
||||
self.assertIn('ProgramFilesDir', keys)
|
||||
|
||||
def test_list_values_non_existing(self):
|
||||
'''
|
||||
Test the list_values function using a non existing registry key
|
||||
'''
|
||||
expected = (False, 'Cannot find key: HKLM\\{0}'.format(FAKE_KEY))
|
||||
self.assertEqual(
|
||||
win_reg.list_values(
|
||||
hive='HKLM',
|
||||
key=FAKE_KEY
|
||||
),
|
||||
expected
|
||||
)
|
||||
|
||||
def test_read_value_existing(self):
|
||||
'''
|
||||
Test the read_value function using a well known registry value
|
||||
'''
|
||||
ret = win_reg.read_value(
|
||||
hive='HKLM',
|
||||
key='SOFTWARE\\Microsoft\\Windows\\CurrentVersion',
|
||||
vname='ProgramFilesPath'
|
||||
)
|
||||
self.assertEqual(ret['vdata'], '%ProgramFiles%')
|
||||
|
||||
def test_read_value_default(self):
|
||||
'''
|
||||
Test the read_value function reading the default value using a well
|
||||
known registry key
|
||||
'''
|
||||
ret = win_reg.read_value(
|
||||
hive='HKLM',
|
||||
key='SOFTWARE\\Microsoft\\Windows\\CurrentVersion'
|
||||
)
|
||||
self.assertEqual(ret['vdata'], '(value not set)')
|
||||
|
||||
def test_read_value_non_existing(self):
|
||||
'''
|
||||
Test the read_value function using a non existing value pair
|
||||
'''
|
||||
expected = {
|
||||
'comment': 'Cannot find fake_name in HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion',
|
||||
'vdata': None,
|
||||
'vname': 'fake_name',
|
||||
'success': False,
|
||||
'hive': 'HKLM',
|
||||
'key': 'SOFTWARE\\Microsoft\\Windows\\CurrentVersion'
|
||||
}
|
||||
self.assertEqual(
|
||||
win_reg.read_value(
|
||||
hive='HKLM',
|
||||
key='SOFTWARE\\Microsoft\\Windows\\CurrentVersion',
|
||||
vname='fake_name'
|
||||
),
|
||||
expected
|
||||
)
|
||||
|
||||
def test_read_value_non_existing_key(self):
|
||||
'''
|
||||
Test the read_value function using a non existing registry key
|
||||
'''
|
||||
expected = {
|
||||
'comment': 'Cannot find key: HKLM\\{0}'.format(FAKE_KEY),
|
||||
'vdata': None,
|
||||
'vname': 'fake_name',
|
||||
'success': False,
|
||||
'hive': 'HKLM',
|
||||
'key': FAKE_KEY
|
||||
}
|
||||
self.assertEqual(
|
||||
win_reg.read_value(
|
||||
hive='HKLM',
|
||||
key=FAKE_KEY,
|
||||
vname='fake_name'
|
||||
),
|
||||
expected
|
||||
)
|
||||
|
||||
@destructiveTest
|
||||
def test_set_value(self):
|
||||
'''
|
||||
Test the set_value function
|
||||
'''
|
||||
try:
|
||||
self.assertTrue(
|
||||
win_reg.set_value(
|
||||
hive='HKLM',
|
||||
key=FAKE_KEY,
|
||||
vname='fake_name',
|
||||
vdata='fake_data'
|
||||
)
|
||||
)
|
||||
expected = {
|
||||
'hive': 'HKLM',
|
||||
'key': FAKE_KEY,
|
||||
'success': True,
|
||||
'vdata': 'fake_data',
|
||||
'vname': 'fake_name',
|
||||
'vtype': 'REG_SZ'
|
||||
}
|
||||
self.assertEqual(
|
||||
win_reg.read_value(
|
||||
hive='HKLM',
|
||||
key=FAKE_KEY,
|
||||
vname='fake_name'
|
||||
),
|
||||
expected
|
||||
)
|
||||
finally:
|
||||
win_reg.delete_key_recursive(hive='HKLM', key=FAKE_KEY)
|
||||
|
||||
@destructiveTest
|
||||
def test_set_value_default(self):
|
||||
'''
|
||||
Test the set_value function on the default value
|
||||
'''
|
||||
try:
|
||||
self.assertTrue(
|
||||
win_reg.set_value(
|
||||
hive='HKLM',
|
||||
key=FAKE_KEY,
|
||||
vdata='fake_default_data'
|
||||
)
|
||||
)
|
||||
expected = {
|
||||
'hive': 'HKLM',
|
||||
'key': FAKE_KEY,
|
||||
'success': True,
|
||||
'vdata': 'fake_default_data',
|
||||
'vname': '(Default)',
|
||||
'vtype': 'REG_SZ'
|
||||
}
|
||||
self.assertEqual(
|
||||
win_reg.read_value(
|
||||
hive='HKLM',
|
||||
key=FAKE_KEY,
|
||||
),
|
||||
expected
|
||||
)
|
||||
finally:
|
||||
win_reg.delete_key_recursive(hive='HKLM', key=FAKE_KEY)
|
||||
|
||||
@destructiveTest
|
||||
def test_set_value_unicode_key(self):
|
||||
'''
|
||||
Test the set_value function on a unicode key
|
||||
'''
|
||||
try:
|
||||
self.assertTrue(
|
||||
win_reg.set_value(
|
||||
hive='HKLM',
|
||||
key='{0}\\{1}'.format(FAKE_KEY, UNICODE_KEY),
|
||||
vname='fake_name',
|
||||
vdata='fake_value'
|
||||
)
|
||||
)
|
||||
expected = {
|
||||
'hive': 'HKLM',
|
||||
'key': '{0}\\{1}'.format(FAKE_KEY, UNICODE_KEY),
|
||||
'success': True,
|
||||
'vdata': 'fake_value',
|
||||
'vname': 'fake_name',
|
||||
'vtype': 'REG_SZ'
|
||||
}
|
||||
self.assertEqual(
|
||||
win_reg.read_value(
|
||||
hive='HKLM',
|
||||
key='{0}\\{1}'.format(FAKE_KEY, UNICODE_KEY),
|
||||
vname='fake_name'
|
||||
),
|
||||
expected
|
||||
)
|
||||
finally:
|
||||
win_reg.delete_key_recursive(hive='HKLM', key=FAKE_KEY)
|
||||
|
||||
@destructiveTest
|
||||
def test_set_value_unicode_value(self):
|
||||
'''
|
||||
Test the set_value function on a unicode value
|
||||
'''
|
||||
try:
|
||||
self.assertTrue(
|
||||
win_reg.set_value(
|
||||
hive='HKLM',
|
||||
key=FAKE_KEY,
|
||||
vname='fake_unicode',
|
||||
vdata=UNICODE_VALUE
|
||||
)
|
||||
)
|
||||
expected = {
|
||||
'hive': 'HKLM',
|
||||
'key': FAKE_KEY,
|
||||
'success': True,
|
||||
'vdata': UNICODE_VALUE,
|
||||
'vname': 'fake_unicode',
|
||||
'vtype': 'REG_SZ'
|
||||
}
|
||||
self.assertEqual(
|
||||
win_reg.read_value(
|
||||
hive='HKLM',
|
||||
key=FAKE_KEY,
|
||||
vname='fake_unicode'
|
||||
),
|
||||
expected
|
||||
)
|
||||
finally:
|
||||
win_reg.delete_key_recursive(hive='HKLM', key=FAKE_KEY)
|
||||
|
||||
@destructiveTest
|
||||
def test_delete_value(self):
|
||||
'''
|
||||
Test the delete_value function
|
||||
'''
|
||||
try:
|
||||
self.assertTrue(
|
||||
win_reg.set_value(
|
||||
hive='HKLM',
|
||||
key=FAKE_KEY,
|
||||
vname='fake_name',
|
||||
vdata='fake_data'
|
||||
)
|
||||
)
|
||||
self.assertTrue(
|
||||
win_reg.delete_value(
|
||||
hive='HKLM',
|
||||
key=FAKE_KEY,
|
||||
vname='fake_name'
|
||||
)
|
||||
)
|
||||
finally:
|
||||
win_reg.delete_key_recursive(hive='HKLM', key=FAKE_KEY)
|
||||
|
||||
def test_delete_value_non_existing(self):
|
||||
'''
|
||||
Test the delete_value function on non existing value
|
||||
'''
|
||||
self.assertEqual(
|
||||
win_reg.delete_value(
|
||||
hive='HKLM',
|
||||
key=FAKE_KEY,
|
||||
vname='fake_name'
|
||||
),
|
||||
None
|
||||
)
|
||||
|
||||
@destructiveTest
|
||||
def test_delete_value_unicode(self):
|
||||
'''
|
||||
Test the delete_value function on a unicode value
|
||||
'''
|
||||
try:
|
||||
self.assertTrue(
|
||||
win_reg.set_value(
|
||||
hive='HKLM',
|
||||
key=FAKE_KEY,
|
||||
vname='fake_unicode',
|
||||
vdata=UNICODE_VALUE
|
||||
)
|
||||
)
|
||||
self.assertTrue(
|
||||
win_reg.delete_value(
|
||||
hive='HKLM',
|
||||
key=FAKE_KEY,
|
||||
vname='fake_unicode'
|
||||
)
|
||||
)
|
||||
finally:
|
||||
win_reg.delete_key_recursive(hive='HKLM', key=FAKE_KEY)
|
||||
|
||||
@destructiveTest
|
||||
def test_delete_key_unicode(self):
|
||||
'''
|
||||
Test the delete_value function on value within a unicode key
|
||||
'''
|
||||
try:
|
||||
self.assertTrue(
|
||||
win_reg.set_value(
|
||||
hive='HKLM',
|
||||
key='{0}\\{1}'.format(FAKE_KEY, UNICODE_KEY),
|
||||
vname='fake_name',
|
||||
vdata='fake_value'
|
||||
)
|
||||
)
|
||||
expected = {
|
||||
'Deleted': ['HKLM\\{0}\\{1}\\'.format(FAKE_KEY, UNICODE_KEY)],
|
||||
'Failed': []
|
||||
}
|
||||
self.assertEqual(
|
||||
win_reg.delete_key_recursive(
|
||||
hive='HKLM',
|
||||
key='{0}\\{1}\\'.format(FAKE_KEY, UNICODE_KEY),
|
||||
),
|
||||
expected
|
||||
)
|
||||
finally:
|
||||
win_reg.delete_key_recursive(hive='HKLM', key=FAKE_KEY)
|
Loading…
Add table
Reference in a new issue