salt/modules/rdp.py
# -*- coding: utf-8 -*-
'''
Manage RDP Service on Windows servers
'''
from __future__ import absolute_import, unicode_literals, print_function
# Import python libs
import logging
import re
# Import Salt libs
import salt.utils.platform
from salt.utils.decorators import depends
try:
from pywintypes import error as PyWinError
import win32ts
_HAS_WIN32TS_DEPENDENCIES = True
except ImportError:
_HAS_WIN32TS_DEPENDENCIES = False
_LOG = logging.getLogger(__name__)
def __virtual__():
'''
Only works on Windows systems
'''
if salt.utils.platform.is_windows():
return 'rdp'
return (False, 'Module only works on Windows.')
def _parse_return_code_powershell(string):
'''
return from the input string the return code of the powershell command
'''
regex = re.search(r'ReturnValue\s*: (\d*)', string)
if not regex:
return (False, 'Could not parse PowerShell return code.')
else:
return int(regex.group(1))
def _psrdp(cmd):
'''
Create a Win32_TerminalServiceSetting WMI Object as $RDP and execute the
command cmd returns the STDOUT of the command
'''
rdp = ('$RDP = Get-WmiObject -Class Win32_TerminalServiceSetting '
'-Namespace root\\CIMV2\\TerminalServices -Computer . '
'-Authentication 6 -ErrorAction Stop')
return __salt__['cmd.run']('{0} ; {1}'.format(rdp, cmd),
shell='powershell', python_shell=True)
def enable():
'''
Enable RDP the service on the server
CLI Example:
.. code-block:: bash
salt '*' rdp.enable
'''
return _parse_return_code_powershell(
_psrdp('$RDP.SetAllowTsConnections(1,1)')) == 0
def disable():
'''
Disable RDP the service on the server
CLI Example:
.. code-block:: bash
salt '*' rdp.disable
'''
return _parse_return_code_powershell(
_psrdp('$RDP.SetAllowTsConnections(0,1)')) == 0
def status():
'''
Show if rdp is enabled on the server
CLI Example:
.. code-block:: bash
salt '*' rdp.status
'''
out = int(_psrdp('echo $RDP.AllowTSConnections').strip())
return out != 0
@depends(_HAS_WIN32TS_DEPENDENCIES)
def list_sessions(logged_in_users_only=False):
'''
List information about the sessions.
.. versionadded:: 2016.11.0
:param logged_in_users_only: If True, only return sessions with users logged in.
:return: A list containing dictionaries of session information.
CLI Example:
.. code-block:: bash
salt '*' rdp.list_sessions
'''
ret = list()
server = win32ts.WTS_CURRENT_SERVER_HANDLE
protocols = {win32ts.WTS_PROTOCOL_TYPE_CONSOLE: 'console',
win32ts.WTS_PROTOCOL_TYPE_ICA: 'citrix',
win32ts.WTS_PROTOCOL_TYPE_RDP: 'rdp'}
statuses = {win32ts.WTSActive: 'active', win32ts.WTSConnected: 'connected',
win32ts.WTSConnectQuery: 'connect_query', win32ts.WTSShadow: 'shadow',
win32ts.WTSDisconnected: 'disconnected', win32ts.WTSIdle: 'idle',
win32ts.WTSListen: 'listen', win32ts.WTSReset: 'reset',
win32ts.WTSDown: 'down', win32ts.WTSInit: 'init'}
for session in win32ts.WTSEnumerateSessions(server):
user = win32ts.WTSQuerySessionInformation(server, session['SessionId'],
win32ts.WTSUserName) or None
protocol_id = win32ts.WTSQuerySessionInformation(server, session['SessionId'],
win32ts.WTSClientProtocolType)
status_id = win32ts.WTSQuerySessionInformation(server, session['SessionId'],
win32ts.WTSConnectState)
protocol = protocols.get(protocol_id, 'unknown')
connection_status = statuses.get(status_id, 'unknown')
station = session['WinStationName'] or 'Disconnected'
connection_info = {'connection_status': connection_status, 'protocol': protocol,
'session_id': session['SessionId'], 'station': station,
'user': user}
if logged_in_users_only:
if user:
ret.append(connection_info)
else:
ret.append(connection_info)
if not ret:
_LOG.warning('No sessions found.')
return sorted(ret, key=lambda k: k['session_id'])
@depends(_HAS_WIN32TS_DEPENDENCIES)
def get_session(session_id):
'''
Get information about a session.
.. versionadded:: 2016.11.0
:param session_id: The numeric Id of the session.
:return: A dictionary of session information.
CLI Example:
.. code-block:: bash
salt '*' rdp.get_session session_id
salt '*' rdp.get_session 99
'''
ret = dict()
sessions = list_sessions()
session = [item for item in sessions if item['session_id'] == session_id]
if session:
ret = session[0]
if not ret:
_LOG.warning('No session found for id: %s', session_id)
return ret
@depends(_HAS_WIN32TS_DEPENDENCIES)
def disconnect_session(session_id):
'''
Disconnect a session.
.. versionadded:: 2016.11.0
:param session_id: The numeric Id of the session.
:return: A boolean representing whether the disconnect succeeded.
CLI Example:
.. code-block:: bash
salt '*' rdp.disconnect_session session_id
salt '*' rdp.disconnect_session 99
'''
try:
win32ts.WTSDisconnectSession(win32ts.WTS_CURRENT_SERVER_HANDLE, session_id, True)
except PyWinError as error:
_LOG.error('Error calling WTSDisconnectSession: %s', error)
return False
return True
@depends(_HAS_WIN32TS_DEPENDENCIES)
def logoff_session(session_id):
'''
Initiate the logoff of a session.
.. versionadded:: 2016.11.0
:param session_id: The numeric Id of the session.
:return: A boolean representing whether the logoff succeeded.
CLI Example:
.. code-block:: bash
salt '*' rdp.logoff_session session_id
salt '*' rdp.logoff_session 99
'''
try:
win32ts.WTSLogoffSession(win32ts.WTS_CURRENT_SERVER_HANDLE, session_id, True)
except PyWinError as error:
_LOG.error('Error calling WTSLogoffSession: %s', error)
return False
return True