From e485cc96745cbd119bca30ef386e9f435b741aac Mon Sep 17 00:00:00 2001 From: 2Shirt <2xShirt@gmail.com> Date: Wed, 15 Sep 2021 09:18:02 -0600 Subject: [PATCH] Add Auto Setup scripts --- scripts/auto_setup.py | 176 +++++++++++++++++++++++++ scripts/wk/kit/tools.py | 3 +- scripts/wk/setup/win.py | 283 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 461 insertions(+), 1 deletion(-) create mode 100644 scripts/auto_setup.py create mode 100644 scripts/wk/setup/win.py diff --git a/scripts/auto_setup.py b/scripts/auto_setup.py new file mode 100644 index 00000000..8d87958a --- /dev/null +++ b/scripts/auto_setup.py @@ -0,0 +1,176 @@ +"""Wizard Kit: Auto System Setup Tool""" +# vim: sts=2 sw=2 ts=2 + +import os +import sys + +os.chdir(os.path.dirname(os.path.realpath(__file__))) +sys.path.append(os.getcwd()) +import wk # pylint: disable=wrong-import-position + + +# STATIC VARIABLES +PRESETS = { + 'Additional User': { + 'Configure System': ( + 'Chrome Notifications', + 'Open Shell', + 'uBlock Origin', + 'Enable BSoD MiniDumps', + 'Enable RegBack', + 'Enable System Restore', + 'Set System Restore Size', + 'Enable Windows Updates', + 'Windows Explorer', + ), + 'System Summary': ( + 'Operating System', + 'Windows Activation', + 'Secure Boot', + 'Installed RAM', + 'Storage Volumes', + 'Virus Protection', + 'Partitions 4K Aligned', + ), + }, + 'Hardware': { + 'Configure System': ( + 'Enable BSoD MiniDumps', + 'Enable RegBack', + 'Enable System Restore', + 'Set System Restore Size', + 'Enable Windows Updates', + ), + 'System Information': ( + 'Backup Registry', + ), + 'System Summary': ( + 'Operating System', + 'Windows Activation', + 'Secure Boot', + 'Installed RAM', + 'Storage Volumes', + 'Virus Protection', + 'Partitions 4K Aligned', + ), + 'Run Programs': ( + 'Device Manager', + 'HWiNFO Sensors', + 'XMPlay', + ), + }, + 'Verify': { + 'Configure System': ( + 'Enable BSoD MiniDumps', + 'Enable RegBack', + 'Enable System Restore', + 'Set System Restore Size', + 'Enable Windows Updates', + 'Windows Explorer', + ), + 'System Summary': ( + 'Operating System', + 'Windows Activation', + 'Secure Boot', + 'Installed RAM', + 'Storage Volumes', + 'Virus Protection', + 'Installed Office', + 'Partitions 4K Aligned', + ), + }, + } + +# Classes +class MenuEntry(): + # pylint: disable=too-few-public-methods + """Simple class to allow cleaner code below.""" + def __init__(self, name, function=None, **kwargs): + self.name = name + self.details = { + 'Function': function, + 'Selected': True, + **kwargs, + } + + +# TODO: DELETEME +def no_op(*args): + """No Op""" + +# STATIC VARIABLES +BASE_MENUS = { + 'Groups': { + 'Backup Settings': ( + # Add checks for existing backups and skip if detected + MenuEntry('Backup Browsers', 'auto_backup_browser_profiles'), + MenuEntry('Backup Power Plans', 'auto_backup_power_plans'), + MenuEntry('Reset Power Plans', 'auto_reset_power_plans'), + MenuEntry('Set Custom Power Plan', 'auto_set_custom_power_plan'), + ), + 'Install Software': ( + MenuEntry('Visual C++ Runtimes', no_op), # only 2012, 2013, & 2019 rest are EOL + #MenuEntry('ESET NOD32 Antivirus', no_op), + MenuEntry('LibreOffice', no_op), + MenuEntry('Open Shell Skin', no_op), + MenuEntry('uBlock Origin', no_op), + MenuEntry('Software Bundle', no_op), # include FF x32 -> x64 convertion? + ), + 'Configure System': ( + MenuEntry('Chrome Notifications', no_op), + #MenuEntry('O&O ShutUp 10', no_op), + MenuEntry('Open Shell', no_op), + MenuEntry('uBlock Origin', no_op), + #MenuEntry('Disable Fast Startup', no_op), + MenuEntry('Enable BSoD MiniDumps', no_op), + #MenuEntry('Enable Hibernation', no_op), + MenuEntry('Enable RegBack', 'auto_enable_regback'), + MenuEntry('Enable System Restore', 'auto_system_restore_enable'), + MenuEntry('Set System Restore Size', 'auto_system_restore_set_size'), + MenuEntry('Create System Restore', 'auto_system_restore_create'), + MenuEntry('Enable Windows Updates', 'auto_windows_updates_enable'), + MenuEntry('User Account Control', no_op), + MenuEntry('Windows Activation', no_op), + MenuEntry('Windows Explorer', no_op), + MenuEntry(r'Windows\Temp Fix', no_op), + ), + 'System Information': ( + MenuEntry('AIDA64 Reports', no_op), + MenuEntry('Backup Registry', 'auto_backup_registry'), + MenuEntry('Everything (File List)', no_op), + ), + 'System Summary': ( + MenuEntry('Operating System', no_op), + MenuEntry('Windows Activation', no_op), + MenuEntry('Secure Boot', no_op), + MenuEntry('Installed RAM', no_op), + MenuEntry('Storage Volumes', no_op), + MenuEntry('Virus Protection', no_op), + MenuEntry('Partitions 4K Aligned', no_op), + ), + 'Run Programs': ( + MenuEntry('Device Manager', no_op), + MenuEntry('HWiNFO Sensors', no_op), + #MenuEntry('Snappy Driver Installer', no_op), + MenuEntry('Windows Updates', no_op), + MenuEntry('Windows Activation', no_op), + MenuEntry('XMPlay', no_op), + ), + }, + 'Actions': ( + MenuEntry('Load Preset'), + MenuEntry('Start', Separator=True), + MenuEntry('Quit'), + ), + } + + +if __name__ == '__main__': + try: + wk.setup.win.run_auto_setup(BASE_MENUS, PRESETS) + except KeyboardInterrupt: + wk.std.abort() + except SystemExit: + raise + except: #pylint: disable=bare-except + wk.std.major_exception() diff --git a/scripts/wk/kit/tools.py b/scripts/wk/kit/tools.py index bed41823..092104ca 100644 --- a/scripts/wk/kit/tools.py +++ b/scripts/wk/kit/tools.py @@ -4,6 +4,7 @@ from datetime import datetime, timedelta import logging import pathlib +import platform import sys import requests @@ -15,7 +16,7 @@ from wk.std import GenericError # STATIC VARIABLES -ARCH = '64' if sys.maxsize > 2**32 else '32' +ARCH = '64' if platform.architecture()[0] == '64bit' else '32' LOG = logging.getLogger(__name__) diff --git a/scripts/wk/setup/win.py b/scripts/wk/setup/win.py new file mode 100644 index 00000000..0a28041d --- /dev/null +++ b/scripts/wk/setup/win.py @@ -0,0 +1,283 @@ +"""WizardKit: Setup - Windows""" +# vim: sts=2 sw=2 ts=2 + +import logging +import os +import platform +import re +import sys +import time + +from subprocess import CalledProcessError, DEVNULL + +from wk.cfg.main import KIT_NAME_FULL, KIT_NAME_SHORT +from wk.exe import ( + get_procs, + run_program, + popen_program, + wait_for_procs, + ) +from wk.io import ( + delete_folder, + get_path_obj, + non_clobber_path, + rename_item, + ) +from wk.kit.tools import ( + ARCH, + download_tool, + extract_tool, + get_tool_path, + run_tool, + ) +from wk.log import format_log_path, update_log_path +from wk.os.win import ( + reg_delete_value, + reg_read_value, + reg_set_value, + reg_write_settings, + disable_service, + enable_service, + stop_service, + ) +from wk.repairs.win import ( + auto_backup_registry, + auto_backup_browser_profiles, + auto_backup_power_plans, + auto_reset_power_plans, + auto_set_custom_power_plan, + auto_enable_regback, + auto_system_restore_enable, + auto_system_restore_set_size, + auto_system_restore_create, + auto_windows_updates_enable, + ) +from wk.std import ( + GenericError, + GenericWarning, + Menu, + TryAndPrint, + abort, + ask, + clear_screen, + color_string, + pause, + print_info, + print_standard, + print_warning, + set_title, + show_data, + sleep, + strip_colors, + ) + + +# STATIC VARIABLES +LOG = logging.getLogger(__name__) +CONEMU_EXE = get_tool_path('ConEmu', 'ConEmu', check=False) +IN_CONEMU = 'ConEmuPID' in os.environ +MENU_PRESETS = Menu() +PROGRAMFILES_32 = os.environ.get( + 'PROGRAMFILES(X86)', os.environ.get( + 'PROGRAMFILES', r'C:\Program Files (x86)', + ), + ) +OS_VERSION = float(platform.win32_ver()[0]) +SYSTEMDRIVE = os.environ.get('SYSTEMDRIVE', 'C:') +WIDTH = 50 +TRY_PRINT = TryAndPrint() +TRY_PRINT.width = WIDTH +TRY_PRINT.verbose = True +for error in ('CalledProcessError', 'FileNotFoundError'): + TRY_PRINT.add_error(error) + + +# Auto Setup +def build_menus(base_menus, title, presets): + """Build menus, returns dict.""" + menus = {} + menus['Main'] = Menu(title=f'{title}\n{color_string("Main Menu", "GREEN")}') + + # Main Menu + for entry in base_menus['Actions']: + menus['Main'].add_action(entry.name, entry.details) + for group in base_menus['Groups']: + menus['Main'].add_option(group, {'Selected': True}) + + # Run groups + for group, entries in base_menus['Groups'].items(): + menus[group] = Menu(title=f'{title}\n{color_string(group, "GREEN")}') + for entry in entries: + menus[group].add_option(entry.name, entry.details) + menus[group].add_action('All') + menus[group].add_action('None') + menus[group].add_action('Main Menu', {'Separator': True}) + menus[group].add_action('Quit') + + # Initialize main menu display names + menus['Main'].update() + + # Fix Function references + for group, menu in menus.items(): + if group not in base_menus['Groups']: + continue + for name in menu.options: + _function = menu.options[name]['Function'] + if isinstance(_function, str): + menu.options[name]['Function'] = getattr( + sys.modules[__name__], _function, + ) + + # Update presets Menu + MENU_PRESETS.title = f'{title}\n{color_string("Load Preset", "GREEN")}' + MENU_PRESETS.add_option('Default') + for name in presets: + MENU_PRESETS.add_option(name) + MENU_PRESETS.add_action('Main Menu') + MENU_PRESETS.add_action('Quit') + MENU_PRESETS.update() + + # Done + return menus + + +def load_preset(menus, presets): + """Load menu settings from preset.""" + selection = MENU_PRESETS.simple_select() + + # Exit early + if 'Main Menu' in selection: + return + if 'Quit' in selection: + raise SystemExit + + # Default case + if 'Default' in selection: + for menu in menus.values(): + for name in menu.options: + menu.options[name]['Selected'] = True + return + + # Load preset + preset = presets[selection[0]] + for group, menu in menus.items(): + group_enabled = group in preset + for name in menu.options: + value = group_enabled and name in preset[group] + menu.options[name]['Selected'] = value + + +def run_auto_setup(base_menus, presets): + """Run Auto Setup.""" + update_log_path(dest_name='Auto Setup', timestamp=True) + title = f'{KIT_NAME_FULL}: Auto Setup' + clear_screen() + set_title(title) + print_info(title) + print('') + + # Generate menus + print_standard('Initializing...') + menus = build_menus(base_menus, title, presets) + + # Show Menu + show_main_menu(base_menus, menus, presets) + + # Start setup + clear_screen() + print_standard(title) + print('') + print_info('Running setup') + + # Run setup + for group, menu in menus.items(): + if group in ('Main', 'Options'): + continue + try: + run_group(group, menu) + except KeyboardInterrupt: + abort() + + # Done + print_info('Done') + pause('Press Enter to exit...') + + +def run_group(group, menu): + """Run entries in group if appropriate.""" + print_info(f' {group}') + for name, details in menu.options.items(): + name_str = strip_colors(name) + + # Not selected + if not details.get('Selected', False): + show_data(f'{name_str}...', 'Skipped', 'YELLOW', width=WIDTH) + continue + + # Selected + details['Function'](group, name) + + +def show_main_menu(base_menus, menus, presets): + """Show main menu and handle actions.""" + while True: + update_main_menu(menus) + selection = menus['Main'].simple_select(update=False) + if selection[0] in base_menus['Groups'] or selection[0] == 'Options': + show_sub_menu(menus[selection[0]]) + if selection[0] == 'Load Preset': + load_preset(menus, presets) + elif 'Start' in selection: + break + elif 'Quit' in selection: + raise SystemExit + + +def show_sub_menu(menu): + """Show sub-menu and handle sub-menu actions.""" + while True: + selection = menu.advanced_select() + if 'Main Menu' in selection: + break + if 'Quit' in selection: + raise SystemExit + + # Select all or none + value = 'All' in selection + for name in menu.options: + if not menu.options[name].get('Disabled', False): + menu.options[name]['Selected'] = value + + +def update_main_menu(menus): + """Update main menu based on current selections.""" + index = 1 + skip = 'Reboot' + for name in menus['Main'].options: + checkmark = ' ' + selected = [ + _v['Selected'] for _k, _v in menus[name].options.items() if _k != skip + ] + if all(selected): + checkmark = '✓' + elif any(selected): + checkmark = '-' + display_name = f' {index}: [{checkmark}] {name}' + index += 1 + menus['Main'].options[name]['Display Name'] = display_name + + +# Auto Setup: Wrapper Functions +## TODO + +# Misc Functions +## TODO? + +# Tool Functions +## TODO? + +# OS Built-in Functions +## TODO? + +if __name__ == '__main__': + print("This file is not meant to be called directly.")