Skip to content

Instantly share code, notes, and snippets.

@ayushxx7
Last active January 6, 2023 14:25
Show Gist options
  • Save ayushxx7/0866eb4df97a938d3267a6187dfd5e4e to your computer and use it in GitHub Desktop.
Save ayushxx7/0866eb4df97a938d3267a6187dfd5e4e to your computer and use it in GitHub Desktop.
ExpressVPN Windows Utility to Connect & Disconnect from VPN using Python
import os
import pyautogui
import inspect
import logging
from datetime import date
import time
import win32gui
import win32com.client
class VpnHandler():
def customLogger(logLevel=logging.INFO):
"""Helper function for logging"""
loggerName = inspect.stack()[1][3]
logger = logging.getLogger(loggerName)
if not logger.handlers:
logger.setLevel(logging.INFO)
log_file_path = os.path.join(os.path.abspath(__file__ + '/../../'), 'Logs', f'Logs_{date.today()}.log')
fileHandler = logging.FileHandler(log_file_path, mode='a')
fileHandler.setLevel(logLevel)
streamHandler = logging.StreamHandler()
streamHandler.setLevel(logLevel)
formatter = logging.Formatter('%(asctime)s [%(levelname)4s] %(message)s (%(filename)s:%(lineno)s)',
datefmt='%m/%d/%Y %I:%M:%S %p')
fileHandler.setFormatter(formatter)
streamHandler.setFormatter(formatter)
logger.addHandler(fileHandler)
logger.addHandler(streamHandler)
return logger
def locate_on_screen_using_pyautogui_and_click(self, file_name):
"""Locate {file_name} image and click via pyautogui"""
self.log.info(f"clicking on {file_name}")
path_of_reference = os.path.join(os.path.abspath(__file__ + "/../../"), f"Assets\\{file_name}")
target = pyautogui.locateOnScreen(image=path_of_reference, confidence=0.8)
self.log.info(f'Target Image location: {target}')
time.sleep(5)
pyautogui.click(target)
self.log.info(f'Click action on {file_name} completed')
def locate_on_screen_using_pyautogui(self, file_name):
"""Locate {file_name} image via pyautogui"""
self.log.info(f'locating presence of {file_name} using pyautogui')
path_of_reference = os.path.join(os.path.abspath(__file__ + "/../../"), f"Assets\\{file_name}")
if pyautogui.locateOnScreen(image=path_of_reference, confidence=0.8):
self.log.info('Found!')
return True
else:
return False
def bring_express_vpn_on_top(self):
"""Bring ExpressVPN App on Top
"""
def windowEnumerationHandler(hwnd, top_windows):
top_windows.append((hwnd, win32gui.GetWindowText(hwnd)))
top_windows = []
win32gui.EnumWindows(windowEnumerationHandler, top_windows)
for window_name in top_windows:
if "expressvpn" in window_name[1].lower():
print('ExpressVPN on top')
try:
print(f'Bringing {window_name} to top')
win32gui.ShowWindow(window_name[0], 5)
shell = win32com.client.Dispatch("WScript.Shell")
shell.SendKeys('%')
win32gui.SetForegroundWindow(window_name[0])
return True
except Exception as e:
print(e)
print('Window already on top')
return True
def dynamic_wait(self, wait_for_img, sec=5, reason="Wait until image appears"):
"""Helper function to wait until specified image is found or time limit exceeds"""
try:
self.log.info(f"Dynamic Wait: {reason}")
check_at = time.time() + sec
while time.time() < check_at and not self.locate_on_screen_using_pyautogui(wait_for_img):
self.log.info('wait for image to appear')
time.sleep(2)
if time.time() > check_at:
return False
else:
return True
except Exception as e:
self.log.error(f"Error in dynamic_wait: {e}")
def connect_to_country(self, vpn_image):
"""Connect to specific country via Express VPN
- Open ExpressVPN App via shortcut
- Bring ExpressVPN on Top
- Click on Search by locating image
- Connect to country by double clicking on country by location image
- Wait for connected image to show up
- Wait for 10 seconds after connection
"""
os.startfile(os.path.join(os.path.abspath(__file__+'/../../'), 'utility_exe', 'ExpressVPN.lnk'))
self.log.info('sleep for 5 secs after launching express vpn')
time.sleep(5)
self.bring_express_vpn_on_top()
time.sleep(2)
self.locate_on_screen_using_pyautogui_and_click('vpn_location_selector.png')
self.log.info('sleep for 3 secs after launch country list')
time.sleep(3)
self.locate_on_screen_using_pyautogui_and_click(vpn_image)
pyautogui.doubleClick()
self.dynamic_wait('vpn_connected.png', reason='Waiting for vpn to connect', sec=100)
self.log.info('Wait for 10 secs after connection established')
time.sleep(10)
def disconnect(self):
"""Disconnect from Express VPN
- Bring ExpressVPN on Top
- Click on Connected (button in center) by locating image
- Wait for disconnected image to show up
- Wait for 10 seconds after disconnection
"""
os.startfile(os.path.join(os.path.abspath(__file__+'/../../'), 'utility_exe', 'ExpressVPN.lnk'))
self.log.info('sleep for 5 secs after launching express vpn')
time.sleep(5)
self.bring_express_vpn_on_top()
time.sleep(2)
self.locate_on_screen_using_pyautogui_and_click('vpn_connected.png')
self.dynamic_wait('vpn_disconnected.png', reason='Waiting for vpn to disconnect', sec=60)
self.log.info('Wait for 10 secs after disconnected')
time.sleep(10)
log = customLogger()
def main():
a = VpnHandler()
a.connect_to_country('vpn_taiwan.png')
a.disconnect()
a.connect_to_country('vpn_germany.png')
if __name__ == "__main__":
main()
@thewh1teagle
Copy link

This library talks directly to the express vpn service and works on windows - Evpn

@ayushxx7
Copy link
Author

@thewh1teagle cool stuff, thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment