├── requirements.txt ├── MANIFEST.in ├── tests └── __init__.py ├── .flake8 ├── screenconnect ├── error.py ├── __init__.py ├── events.py ├── enumerations.py ├── session_group.py ├── session.py └── api.py ├── LICENSE ├── .gitignore ├── setup.py └── README.md /requirements.txt: -------------------------------------------------------------------------------- 1 | requests 2 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include *.txt *.md 2 | -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- 1 | """ Tests for screenconnect """ 2 | -------------------------------------------------------------------------------- /.flake8: -------------------------------------------------------------------------------- 1 | [flake8] 2 | exclude = __pycache__ 3 | max-line-length = 88 4 | -------------------------------------------------------------------------------- /screenconnect/error.py: -------------------------------------------------------------------------------- 1 | """Errors specific to this library""" 2 | 3 | 4 | class ScreenConnectError(Exception): 5 | """ Base class for ScreenConnect errors """ 6 | 7 | @property 8 | def message(self): 9 | """ Returns provided message to construct error """ 10 | return self.args[0] 11 | -------------------------------------------------------------------------------- /screenconnect/__init__.py: -------------------------------------------------------------------------------- 1 | """ A library that provides a Python interface to the ScreenConnect API """ 2 | 3 | from .session import Session 4 | from .session_group import SessionGroup 5 | from .enumerations import SessionType 6 | from .api import ScreenConnect 7 | 8 | 9 | __version__ = "0.1.0" 10 | 11 | 12 | __all__ = [ 13 | "Session", 14 | "SessionGroup", 15 | "SessionType", 16 | "ScreenConnect" 17 | ] 18 | -------------------------------------------------------------------------------- /screenconnect/events.py: -------------------------------------------------------------------------------- 1 | """ Objects for the Session Events that can occur in ScreenConnect""" 2 | 3 | 4 | class SessionEvent: 5 | """ Object to describe events attributed to a ScreenConnect 6 | Session 7 | """ 8 | 9 | def __init__(self, **kwargs): 10 | 11 | """ 12 | - id 13 | - event type 14 | - time 15 | - host 16 | - data 17 | 18 | """ 19 | 20 | super().__init__(**kwargs) 21 | 22 | 23 | class SessionConnectionEvent(SessionEvent): 24 | """ Object that extends SessionEvent by having an associated 25 | Connection 26 | """ 27 | 28 | def __init__(self, **kwargs): 29 | """ 30 | - connection 31 | """ 32 | 33 | super().__init__(**kwargs) 34 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Jacob Turpin 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | env/ 12 | build/ 13 | develop-eggs/ 14 | dist/ 15 | downloads/ 16 | eggs/ 17 | .eggs/ 18 | lib/ 19 | lib64/ 20 | parts/ 21 | sdist/ 22 | var/ 23 | *.egg-info/ 24 | .installed.cfg 25 | *.egg 26 | 27 | # PyInstaller 28 | # Usually these files are written by a python script from a template 29 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 30 | *.manifest 31 | *.spec 32 | 33 | # Installer logs 34 | pip-log.txt 35 | pip-delete-this-directory.txt 36 | 37 | # Unit test / coverage reports 38 | htmlcov/ 39 | .tox/ 40 | .coverage 41 | .coverage.* 42 | .cache 43 | nosetests.xml 44 | coverage.xml 45 | *,cover 46 | .hypothesis/ 47 | 48 | # Translations 49 | *.mo 50 | *.pot 51 | 52 | # Django stuff: 53 | *.log 54 | 55 | # Sphinx documentation 56 | docs/_build/ 57 | 58 | # PyBuilder 59 | target/ 60 | 61 | #Ipython Notebook 62 | .ipynb_checkpoints 63 | 64 | # Files for testing locally 65 | *debug.py 66 | 67 | #Pycharm Files 68 | .idea/* 69 | 70 | # Virtual Environment 71 | .venv 72 | -------------------------------------------------------------------------------- /screenconnect/enumerations.py: -------------------------------------------------------------------------------- 1 | from enum import Enum 2 | 3 | 4 | # Update to SessionEventType 5 | class SessionEvent(Enum): 6 | """ Enums for Session Events """ 7 | 8 | Connected = 10 9 | Disconnected = 11 10 | 11 | CreatedSession = 20 12 | EndedSession = 21 13 | 14 | InitiatedJoin = 30 15 | InvitedGuest = 31 16 | AddedNote = 32 17 | 18 | QueuedReinstall = 40 19 | QueuedUninstall = 41 20 | QueuedInvalidateLicense = 42 21 | QueuedWake = 43 22 | QueuedCommand = 44 23 | QueuedMessage = 45 24 | QueuedGuestInfoUpdate = 46 25 | QueuedTool = 47 26 | QueuedForceDisconnect = 48 27 | 28 | ProcessedReinstall = 50 29 | ProcessedUninstall = 51 30 | ProcessedInvalidateLicense = 52 31 | ProcessedWake = 53 32 | ProcessedCommand = 54 33 | ProcessedMessage = 55 34 | ProcessedGuestInfoUpdate = 56 35 | ProcessedTool = 57 36 | ProcessedForceDisconnect = 58 37 | 38 | ModifiedName = 60 39 | ModifiedIsPublic = 61 40 | ModifiedCode = 62 41 | ModifiedHost = 63 42 | ModifiedCustomProperty = 64 43 | 44 | RanCommand = 70 45 | SentMessage = 71 46 | 47 | SentPrintJob = 80 48 | ReceivedPrintJob = 81 49 | CopiedText = 82 50 | CopiedFiles = 83 51 | DraggedFiles = 84 52 | RanFiles = 85 53 | SentFiles = 86 54 | 55 | 56 | class SessionType(Enum): 57 | 58 | Unknown = -1 59 | Support = 0 60 | Meeting = 1 61 | Access = 2 62 | 63 | 64 | class ProcessType(Enum): 65 | 66 | Unknown = 0 67 | Host = 1 68 | Guest = 2 69 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup, find_packages 2 | import re 3 | import os 4 | 5 | 6 | cwd = os.path.dirname(os.path.abspath(__file__)) 7 | 8 | 9 | # obtain version 10 | with open(os.path.join(cwd, "screenconnect", "__init__.py")) as f: 11 | version = re.search(r"__version__\s+=\s+\"(.*)\"", f.read()).group(1) 12 | 13 | 14 | # obtain long description (readme file) 15 | with open(os.path.join(cwd, "README.md")) as readme_file: 16 | long_description = readme_file.read() 17 | 18 | 19 | # obtain requirements 20 | with open(os.path.join(cwd, "requirements.txt")) as reqs_file: 21 | install_requires = reqs_file.read().splitlines() 22 | 23 | 24 | setup( 25 | name="screenconnect", 26 | version=version, 27 | url="https://github.com/jacobeturpin/python-screenconnect", 28 | author="Jacob Turpin", 29 | packages=find_packages(), 30 | license="MIT", 31 | description="A library that provides a Python interface to the ScreenConnect API", 32 | long_description=long_description, 33 | classifiers=[ 34 | "Development Status :: 3 - Alpha", 35 | "License :: OSI Approved :: MIT License", 36 | "Intended Audience :: Developers", 37 | "Operating System :: Microsoft :: Windows", 38 | "Operating System :: MacOS :: MacOS X", 39 | "Operating System :: POSIX", 40 | "Programming Language :: Python :: 3.5", 41 | "Programming Language :: Python :: 3.6", 42 | "Programming Language :: Python :: 3.7", 43 | "Programming Language :: Python :: 3.8", 44 | "Programming Language :: Python :: 3 :: Only", 45 | ], 46 | install_requires=install_requires, 47 | python_requires=">=3.5" 48 | ) 49 | -------------------------------------------------------------------------------- /screenconnect/session_group.py: -------------------------------------------------------------------------------- 1 | """ """ 2 | 3 | from screenconnect.enumerations import SessionType 4 | 5 | 6 | class SessionGroup: 7 | """ Object for interacting with ScreenConnect Session Groups """ 8 | 9 | def __init__(self, api, **kwargs): 10 | """ Instantiates a session group object 11 | 12 | Arguments: 13 | api -- object used to enact any changes/modifications 14 | name -- the name defined for the Session Group 15 | session_type -- the enumeration used to describe the type of session 16 | is_system -- describes whether the Session Group is user-modifiable 17 | session_filter -- definition by which the group is populated 18 | subgroup_expressions -- criteria for any further session organization 19 | """ 20 | 21 | self._api = api 22 | 23 | self.name = kwargs.get("Name") 24 | self.session_type = SessionType(kwargs.get("SessionType")) 25 | self.session_filter = kwargs.get("SessionFilter") 26 | self.subgroup_expressions = kwargs.get("SubgroupExpressions") 27 | 28 | def __repr__(self): 29 | return "{0}(name: {1}, type: {2}, filter: {3})".format( 30 | self.__class__.__name__, self.name, self.session_type, self.session_filter 31 | ) 32 | 33 | def to_dict(self): 34 | """ Returns object as dict """ 35 | return { 36 | "Name": self.name, 37 | "SessionType": self.session_type.value, 38 | "SessionFilter": self.session_filter, 39 | "SubgroupExpressions": self.subgroup_expressions, 40 | } 41 | 42 | def modify(self, **kwargs): 43 | """ Alter the details or settings of the session group """ 44 | pass 45 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # python-screenconnect: An unofficial Python wrapper around the ConnectWise Control (formerly ScreenConnect) API 2 | 3 | *Currently undergoing initial development* 4 | 5 | ## Introduction 6 | 7 | This library provides a pure Python interface for the ConnectWise Control (formerly ScreenConnect) API. Please note, 8 | this project is undergoing initial development. 9 | 10 | ## Notices About Use of this Package 11 | 12 | Two caveats must be made about the use of this package: 13 | 14 | First, this project hooks directly into the various web services that come with a new installation of 15 | ConnectWise Control. However, these APIs are considered to exist for private use by the ConnectWise 16 | Control application. Thus, these APIs are not considered to be stable and may change from 17 | release to release. If needing APIs that are guaranteed to be highly stable, please use the 18 | provided [Extension Development framework](https://docs.connectwise.com/ConnectWise_Control_Documentation/Developers) 19 | from the ConnectWise Control team. 20 | 21 | Second, this project is an unofficial implementation. ConnectWise is not officially involved in 22 | this package's development in any capacity, and does not guaranteed long term support. For all other questions 23 | about use please consult the [project license](LICENSE). 24 | 25 | ## Requirements 26 | 27 | * Python 3.5+ and dependencies listed on `requirements.txt` 28 | * An installed and publicly accessible 29 | [ConnectWise Control](https://www.connectwise.com/software/control) server 30 | 31 | ## Installation 32 | 33 | You can install latest release from PyPI by running: 34 | 35 | ```shell 36 | pip install screenconnect 37 | ``` 38 | 39 | Or if you prefer to install from source, clone this repository and run: 40 | 41 | ```shell 42 | pip install . 43 | ``` 44 | 45 | ## Getting Started 46 | 47 | ```python 48 | >>> import screenconnect 49 | >>> sc = screenconnect.ScreenConnect('https://examplesite.screenconnect.com', auth=('user', 'pass')) 50 | >>> sc.server_version 51 | '6.2.12646.6275' 52 | >>> sc.get_eligible_hosts() 53 | ['Cloud Account Administrator', 'Tech 1', 'Tech 2'] 54 | ``` 55 | 56 | ## Running Tests 57 | 58 | *Coming soon* 59 | -------------------------------------------------------------------------------- /screenconnect/session.py: -------------------------------------------------------------------------------- 1 | """ Session objects """ 2 | 3 | from json import dumps 4 | 5 | from screenconnect.enumerations import SessionEvent, SessionType 6 | 7 | 8 | class Session: 9 | """ Object for interacting with ScreenConnect Sessions """ 10 | 11 | def __init__(self, api, session_id, name, **kwargs): 12 | """ Instantiates a new session object """ 13 | 14 | self._api = api 15 | self.session_id = session_id 16 | self.name = name 17 | 18 | # Need to convert integer into SessionType Enum 19 | self.session_type = SessionType(kwargs.get("SessionType", -1)) 20 | self.host = kwargs.get("host") 21 | self.is_public = kwargs.get("is_public") 22 | self.code = kwargs.get("code") 23 | self.legacy_encryption_key = kwargs.get("legacy_encryption_key") 24 | self.custom_properties = kwargs.get("custom_property_values") 25 | 26 | """ 27 | GuestInfo 28 | GuestInfoUpdateTime 29 | QueuedEventType 30 | QueuedEventHost 31 | QueuedEventData 32 | QueuedEventConnectionID 33 | LastEventTime 34 | IsEnded 35 | Notes 36 | GuestNetworkAddress 37 | GuestClientVersion 38 | Attributes 39 | ActiveConnections 40 | LastAlteredVersion 41 | """ 42 | 43 | self.get_details() 44 | 45 | def __repr__(self): 46 | return "{0}(id: {1}, name: {2}, type: {3})".format( 47 | self.__class__.__name__, self.session_id, self.name, self.session_type.name 48 | ) 49 | 50 | def get_details(self): 51 | """ Gets specific details about session """ 52 | 53 | # path = "/Services/PageService.ashx/GetSessionDetails" 54 | pass 55 | 56 | def modify_details(self, **kwargs): 57 | """ Alter the details or settings of the session """ 58 | 59 | pass 60 | 61 | def _add_event_to_sessions(self, event): 62 | """ Adds a SessionEvent record to one or more Sessions 63 | 64 | ScreenConnect API 65 | 66 | - sessionGroupName 67 | - sessionIDs 68 | - sessionEventType 69 | - data 70 | """ 71 | 72 | path = "/Services/PageService.ashx/AddEventToSessions" 73 | 74 | # Attempting to pass empty session group 75 | # This throws server FaultException b/c SessionGroup doesn't 76 | # exist 77 | 78 | # Just throwing a hard-coded value in here for testing purposes 79 | payload = dumps(["All Sessions", [self.session_id], event.value, ""]) 80 | self._api.make_request("POST", path, data=payload) 81 | 82 | def end(self): 83 | self._add_event_to_sessions(SessionEvent.EndedSession) 84 | 85 | 86 | class SessionGuestInfo: 87 | def __init__(self, **kwargs): 88 | 89 | """ 90 | - guest network address 91 | - guest machine name 92 | - guest machine domain 93 | - guest processor name 94 | - guest processor virtual count 95 | - guest system memory total megabytes 96 | - guest system memory available megabytes 97 | - guest screenshot content type 98 | - guest info update time 99 | - guest screenshot content 100 | - base time 101 | 102 | """ 103 | 104 | super().__init__(**kwargs) 105 | -------------------------------------------------------------------------------- /screenconnect/api.py: -------------------------------------------------------------------------------- 1 | """ A library that provides a Python interface to the ScreenConnect API """ 2 | 3 | import re 4 | from json import dumps 5 | 6 | import requests 7 | 8 | from screenconnect.session import Session 9 | from screenconnect.session_group import SessionGroup 10 | from screenconnect.error import ScreenConnectError 11 | 12 | 13 | class ScreenConnect: 14 | """ A python interface into the ScreenConnect API """ 15 | 16 | def __init__(self, url, auth=None): 17 | """ Instantiate a new ScreenConnect object 18 | 19 | Arguments: 20 | url -- publicly accessible url for the ScreenConnect web server 21 | auth -- (user, pwd) 22 | """ 23 | 24 | # Need to do some basic sanitation to remove unnecessary trailing slash 25 | self.url = url 26 | self.user, self.__pwd = auth 27 | 28 | def __repr__(self): 29 | return "{0}(url: {1}, user: {2})".format( 30 | self.__class__.__name__, self.url, self.user 31 | ) 32 | 33 | @property 34 | def server_version(self): 35 | raw_server = self.make_request("HEAD", return_json=False).headers.get("Server") 36 | 37 | try: 38 | return re.search("ScreenConnect/([0-9][0-9.]*[0-9])*", raw_server).group(1) 39 | except AttributeError: 40 | raise ScreenConnectError("Unable to determine server version") 41 | 42 | def reset_auth_credentials(self, auth=(None, None)): 43 | """ Resets the designated account for authorization 44 | 45 | Argument: 46 | auth -- supplied credentials in (user, pwd); if no credentials 47 | are provided, they will default to none to revoke access 48 | """ 49 | 50 | user, pwd = auth 51 | if self.user == user and self.__pwd == pwd: 52 | return None 53 | self.user, self.__pwd = auth 54 | 55 | def make_request(self, verb, path="", data=None, params=None, return_json=True): 56 | """ Performs request with optional payload to a specified path 57 | 58 | The purpose of 59 | 60 | Arguments: 61 | verb -- HTTP verb to use when making the request 62 | path -- relative path to append to the object's url 63 | data -- optional payload to send with the request 64 | """ 65 | 66 | url = self.url + path 67 | response = requests.request( 68 | verb, url, auth=(self.user, self.__pwd), data=data, params=params 69 | ) 70 | status_code = response.status_code 71 | 72 | if status_code == 200: 73 | return response.json() if return_json else response 74 | elif status_code == 403: 75 | raise ScreenConnectError("Bad or missing credentials provided") 76 | elif status_code == 404: 77 | raise ScreenConnectError("Invalid URL provided") 78 | else: 79 | raise ScreenConnectError("Unknown error") 80 | 81 | # ------------ SESSION METHODS ------------ 82 | 83 | def create_session(self, session_type, name, is_public, code, custom_properties): 84 | """ Creates a new ScreenConnect session 85 | 86 | ScreenConnect API -- ~/Services/PageService.ashx/CreateSession 87 | 88 | Arguments: 89 | session_type -- type of ScreenConnect session 90 | name -- identifying name visible to users 91 | is_public -- boolean value on whether the session can be connected 92 | to form the Guest page 93 | code -- code that can be used to join from the Guest Page if applicable 94 | custom_properties -- list of 8 properties that can be used to define 95 | groups and filters for sessions 96 | """ 97 | 98 | # TODO: propagate missing values to Session object 99 | 100 | path = "/Services/PageService.ashx/CreateSession" 101 | payload = [session_type.value, name, is_public, code, custom_properties] 102 | result = self.make_request("POST", path, data=dumps(payload)) 103 | return Session(self, result, name) 104 | 105 | def get_guest_session_info(self, session_codes=[], session_ids=[], version=0): 106 | """ Retrieves information about a session from the Guest perspective 107 | 108 | ScreenConnect API -- ~/Services/PageService.ashx/GetGuestSessionInfo 109 | 110 | Arguments: 111 | """ 112 | 113 | path = "/Services/PageService.ashx/GetGuestSessionInfo" 114 | payload = [session_codes, session_ids, version] 115 | response = self.make_request("GET", path, data=dumps(payload)) 116 | return [ 117 | Session(self, _["SessionID"], _["Name"], **_) 118 | for _ in response.get("Sessions", []) 119 | ] 120 | 121 | def get_host_session_info( 122 | self, 123 | session_type=0, 124 | session_group_path=[], 125 | session_filter=None, 126 | find_session_id=None, 127 | version=0, 128 | ): 129 | """ Retrieves information about a session from the Host perspective 130 | 131 | ScreenConnect API -- ~/Services/PageService.ashx/GetHostSessionInfo 132 | 133 | Arguments: 134 | """ 135 | 136 | path = "/Services/PageService.ashx/GetHostSessionInfo" 137 | payload = [ 138 | session_type, 139 | session_group_path, 140 | session_filter, 141 | find_session_id, 142 | version, 143 | ] 144 | response = self.make_request("GET", path, data=dumps(payload)) 145 | return [ 146 | Session(self, _["SessionID"], _["Name"], **_) 147 | for _ in response.get("Sessions", []) 148 | ] 149 | 150 | def update_sessions( 151 | self, 152 | session_group_name, 153 | session_ids, 154 | names, 155 | is_publics, 156 | codes, 157 | custom_property_values, 158 | ): 159 | """ Updates one or more ScreenConnect sessions within the same session group; 160 | all lists should be saved in the same respective order 161 | 162 | ScreenConnect API -- ~/Services/PageService.ashx/UpdateSessions 163 | 164 | Arguments: 165 | session_group_name -- name of the session group to which sessions belong 166 | session_ids -- list of session ids for the sessions to update 167 | names -- list of names 168 | is_publics -- list of boolean is_public statuses 169 | codes -- list of join code strings 170 | custom_property_values -- list of custom property value lists 171 | """ 172 | path = "/Services/PageService.ashx/UpdateSessions" 173 | self.make_request("POST", path) 174 | pass 175 | 176 | def transfer_sessions(self, session_group_name, session_ids, to_host): 177 | """ Updates the "ownership" quality of one or more ScreenConnect sessions 178 | within the same session group 179 | 180 | ScreenConnect API -- ~/Services/PageService.ashx/TransferSessions 181 | 182 | Arguments: 183 | session_group_name -- 184 | """ 185 | 186 | path = "/Services/PageService.ashx/TransferSessions" 187 | payload = [session_group_name, session_ids, to_host] 188 | self.make_request("POST", path, data=dumps(payload)) 189 | 190 | # ------------ SESSION GROUP METHODS ------------ 191 | 192 | def get_session_groups(self): 193 | """ Retrieves all session groups """ 194 | 195 | path = "/Services/SessionGroupService.ashx/GetSessionGroups" 196 | result = self.make_request("GET", path) 197 | return [SessionGroup(self, **x) for x in result] 198 | 199 | def save_session_groups(self, session_groups): 200 | """ Saves all session groups """ 201 | 202 | path = "/Services/SessionGroupService.ashx/SaveSessionGroups" 203 | payload = list( 204 | [_.to_dict() for _ in session_groups] 205 | ) # needs to be nested for some reason 206 | self.make_request("POST", path, data=dumps(payload)) 207 | 208 | # ------------ MISC METHODS ------------ 209 | 210 | def get_session_report( 211 | self, 212 | report_type=None, 213 | select_fields=None, 214 | group_fields=None, 215 | report_filter=None, 216 | aggregate_filter=None, 217 | item_limit=None, 218 | transform=True, 219 | ): 220 | """ Get a report based upon session criteria """ 221 | 222 | path = "/Report.json" 223 | 224 | params = { 225 | "ReportType": report_type, 226 | "SelectFields": select_fields, 227 | "GroupFields": group_fields, 228 | "Filter": report_filter, 229 | "AggregateFilter": aggregate_filter, 230 | "ItemLimit": item_limit, 231 | } 232 | 233 | response = self.make_request( 234 | "GET", path, params={k: v for k, v in params.items() if v} 235 | ) 236 | 237 | if transform: 238 | response = [dict(zip(response["FieldNames"], x)) for x in response["Items"]] 239 | 240 | return response 241 | 242 | # ------------ MISC METHODS ------------ 243 | 244 | def send_email(self, to, subject=None, body=None, is_html=False): 245 | """ Sends an email through the ScreenConnect mail service""" 246 | 247 | path = "/Services/MailService.ashx/SendEmail" 248 | payload = dumps([to, subject, body, is_html]) 249 | self.make_request("POST", path, data=payload) 250 | 251 | def get_eligible_hosts(self): 252 | """ Retrieves list of all accounts with login in past 24 hours """ 253 | 254 | path = "/Services/PageService.ashx/GetEligibleHosts" 255 | return self.make_request("GET", path) 256 | 257 | def get_toolbox(self): 258 | """ Retrieves toolbox items """ 259 | 260 | path = "/Services/PageService.ashx/GetToolbox" 261 | return self.make_request("GET", path) 262 | --------------------------------------------------------------------------------