diff --git a/.bin/Scripts/functions/activation.py b/.bin/Scripts/functions/activation.py index e10d088c..52ea8ecd 100644 --- a/.bin/Scripts/functions/activation.py +++ b/.bin/Scripts/functions/activation.py @@ -6,9 +6,11 @@ from borrowed import acpi from functions.common import * from os import environ -# Variables + +# STATIC VARIABLES SLMGR = r'{}\System32\slmgr.vbs'.format(environ.get('SYSTEMROOT')) + def activate_with_bios(): """Attempt to activate Windows with a key stored in the BIOS.""" # Code borrowed from https://github.com/aeruder/get_win8key @@ -43,6 +45,7 @@ def activate_with_bios(): if not windows_is_activated(): raise Exception('Activation Failed') + def get_activation_string(): """Get activation status, returns str.""" act_str = subprocess.run( @@ -53,6 +56,7 @@ def get_activation_string(): act_str = act_str[1].strip() return act_str + def windows_is_activated(): """Check if Windows is activated via slmgr.vbs and return bool.""" activation_string = subprocess.run( @@ -62,6 +66,7 @@ def windows_is_activated(): return bool(activation_string and 'permanent' in activation_string) + if __name__ == '__main__': print("This file is not meant to be called directly.") diff --git a/.bin/Scripts/functions/backup.py b/.bin/Scripts/functions/backup.py index f7679db2..ad03f822 100644 --- a/.bin/Scripts/functions/backup.py +++ b/.bin/Scripts/functions/backup.py @@ -4,6 +4,7 @@ import ctypes from functions.disk import * + # Regex REGEX_BAD_PATH_NAMES = re.compile( r'([<>:"/\|\?\*]' @@ -12,6 +13,7 @@ REGEX_BAD_PATH_NAMES = re.compile( r'|[\s\.]+$', re.IGNORECASE) + def backup_partition(disk, par): """Create a backup image of a partition.""" if (par.get('Image Exists', False) @@ -31,6 +33,7 @@ def backup_partition(disk, par): os.makedirs(dest_dir, exist_ok=True) run_program(cmd) + def fix_path(path): """Replace invalid filename characters with underscores.""" local_drive = path[1:2] == ':' @@ -39,6 +42,7 @@ def fix_path(path): new_path = '{}:{}'.format(new_path[0:1], new_path[2:]) return new_path + def get_volume_display_name(mountpoint): """Get display name from volume mountpoint and label, returns str.""" name = mountpoint @@ -67,6 +71,7 @@ def get_volume_display_name(mountpoint): return name + def prep_disk_for_backup(destination, disk, backup_prefix): """Gather details about the disk and its partitions. @@ -143,6 +148,7 @@ def prep_disk_for_backup(destination, disk, backup_prefix): COLORS['YELLOW'], COLORS['CLEAR']) disk['Backup Warnings'] = warnings + def select_backup_destination(auto_select=True): """Select a backup destination from a menu, returns server dict.""" destinations = [s for s in BACKUP_SERVERS if s['Mounted']] @@ -193,6 +199,7 @@ def select_backup_destination(auto_select=True): else: return destinations[int(selection)-1] + def verify_wim_backup(partition): """Verify WIM integrity.""" if not os.path.exists(partition['Image Path']): @@ -205,6 +212,7 @@ def verify_wim_backup(partition): ] run_program(cmd) + if __name__ == '__main__': print("This file is not meant to be called directly.") diff --git a/.bin/Scripts/functions/browsers.py b/.bin/Scripts/functions/browsers.py index 6c93b8cb..e73399bc 100644 --- a/.bin/Scripts/functions/browsers.py +++ b/.bin/Scripts/functions/browsers.py @@ -4,6 +4,7 @@ from functions.common import * from operator import itemgetter + # Define other_results for later try_and_print browser_data = {} other_results = { @@ -16,22 +17,6 @@ other_results = { } } -# Regex -REGEX_BACKUP = re.compile( - r'\.\w*bak.*', - re.IGNORECASE) -REGEX_CHROMIUM_PROFILE = re.compile( - r'^(Default|Profile)', - re.IGNORECASE) -REGEX_CHROMIUM_ITEMS = re.compile( - r'^(Bookmarks|Cookies|Favicons|Google Profile' - r'|History|Login Data|Top Sites|TransportSecurity' - r'|Visited Links|Web Data)', - re.IGNORECASE) -REGEX_MOZILLA = re.compile( - r'^(bookmarkbackups|(cookies|formhistory|places).sqlite' - r'|key3.db|logins.json|persdict.dat)$', - re.IGNORECASE) # STATIC VARIABLES DEFAULT_HOMEPAGE = 'https://www.google.com/' @@ -103,6 +88,25 @@ SUPPORTED_BROWSERS = { }, } + +# Regex +REGEX_BACKUP = re.compile( + r'\.\w*bak.*', + re.IGNORECASE) +REGEX_CHROMIUM_PROFILE = re.compile( + r'^(Default|Profile)', + re.IGNORECASE) +REGEX_CHROMIUM_ITEMS = re.compile( + r'^(Bookmarks|Cookies|Favicons|Google Profile' + r'|History|Login Data|Top Sites|TransportSecurity' + r'|Visited Links|Web Data)', + re.IGNORECASE) +REGEX_MOZILLA = re.compile( + r'^(bookmarkbackups|(cookies|formhistory|places).sqlite' + r'|key3.db|logins.json|persdict.dat)$', + re.IGNORECASE) + + def archive_all_users(): """Create backups for all browsers for all users.""" users_root = r'{}\Users'.format(global_vars['Env']['SYSTEMDRIVE']) @@ -149,6 +153,7 @@ def archive_all_users(): function=run_program, cmd=cmd) print_standard(' ') + def archive_browser(name): """Create backup of Browser saved in the BackupDir.""" source = '{}*'.format(browser_data[name]['user_data_path']) @@ -163,12 +168,14 @@ def archive_browser(name): archive, source] run_program(cmd) + def backup_browsers(): """Create backup of all detected browser profiles.""" for name in [k for k, v in sorted(browser_data.items()) if v['profiles']]: try_and_print(message='{}...'.format(name), function=archive_browser, name=name) + def clean_chromium_profile(profile): """Recreate profile with only the essential user data. @@ -191,6 +198,7 @@ def clean_chromium_profile(profile): shutil.copy(entry.path, r'{}\{}'.format( profile['path'], entry.name)) + def clean_internet_explorer(**kwargs): """Uses the built-in function to reset IE and sets the homepage. @@ -208,6 +216,7 @@ def clean_internet_explorer(**kwargs): except FileNotFoundError: pass + def clean_mozilla_profile(profile): """Recreate profile with only the essential user data. @@ -240,6 +249,7 @@ def clean_mozilla_profile(profile): for k, v in MOZILLA_PREFS.items(): f.write('user_pref("{}", {});\n'.format(k, v)) + def get_browser_details(name): """Get installation and profile details for all supported browsers.""" browser = SUPPORTED_BROWSERS[name].copy() @@ -314,6 +324,7 @@ def get_browser_details(name): elif num_installs > 1 and browser['base'] != 'ie': raise MultipleInstallationsError + def get_chromium_profiles(search_path): """Find any chromium-style profiles and return as a list of dicts.""" profiles = [] @@ -330,6 +341,7 @@ def get_chromium_profiles(search_path): return profiles + def get_ie_homepages(): """Read homepages from the registry and return as a list.""" homepages = [] @@ -354,6 +366,7 @@ def get_ie_homepages(): homepages = [h.replace('{', '').replace('}', '') for h in homepages] return homepages + def get_mozilla_homepages(prefs_path): """Read homepages from prefs.js and return as a list.""" homepages = [] @@ -369,6 +382,7 @@ def get_mozilla_homepages(prefs_path): return homepages + def get_mozilla_profiles(search_path, dev=False): """Find any mozilla-style profiles and return as a list of dicts.""" profiles = [] @@ -393,6 +407,7 @@ def get_mozilla_profiles(search_path, dev=False): return profiles + def install_adblock(indent=8, width=32, just_firefox=False): """Install adblock for all supported browsers.""" for browser in sorted(browser_data): @@ -461,6 +476,7 @@ def install_adblock(indent=8, width=32, just_firefox=False): cs='Done', function=function, cmd=[exe_path, *urls], check=False) + def list_homepages(indent=8, width=32): """List current homepages for reference.""" browser_list = [k for k, v in sorted(browser_data.items()) if v['exe_path']] @@ -491,6 +507,7 @@ def list_homepages(indent=8, width=32): print_standard('{indent}{name:<{width}}{page}'.format( indent=' '*indent, width=width, name=name, page=page)) + def reset_browsers(indent=8, width=32): """Reset all detected browsers to safe defaults.""" browser_list = [k for k, v in sorted(browser_data.items()) if v['profiles']] @@ -508,6 +525,7 @@ def reset_browsers(indent=8, width=32): indent=indent, width=width, function=function, other_results=other_results, profile=profile) + def scan_for_browsers(just_firefox=False): """Scan system for any supported browsers.""" for name, details in sorted(SUPPORTED_BROWSERS.items()): @@ -517,6 +535,7 @@ def scan_for_browsers(just_firefox=False): function=get_browser_details, cs='Detected', other_results=other_results, name=name) + if __name__ == '__main__': print("This file is not meant to be called directly.") diff --git a/.bin/Scripts/functions/cleanup.py b/.bin/Scripts/functions/cleanup.py index 80ffd879..5ee20be1 100644 --- a/.bin/Scripts/functions/cleanup.py +++ b/.bin/Scripts/functions/cleanup.py @@ -2,6 +2,7 @@ from functions.common import * + def cleanup_adwcleaner(): """Move AdwCleaner folders into the ClientDir.""" source_path = r'{SYSTEMDRIVE}\AdwCleaner'.format(**global_vars['Env']) @@ -26,6 +27,7 @@ def cleanup_adwcleaner(): dest_name = non_clobber_rename(dest_name) shutil.move(source_path, dest_name) + def cleanup_cbs(dest_folder): """Safely cleanup a known CBS archive bug under Windows 7. @@ -65,6 +67,7 @@ def cleanup_cbs(dest_folder): r'{}\CbsPersist*'.format(temp_folder)] run_program(cmd) + def cleanup_desktop(): """Move known backup files and reports into the ClientDir.""" dest_folder = r'{LogDir}\Tools'.format(**global_vars) @@ -81,6 +84,7 @@ def cleanup_desktop(): # Remove dir if empty delete_empty_folders(dest_folder) + def delete_empty_folders(folder_path): """Delete all empty folders in path (depth first).""" if not os.path.exists(folder_path) or not os.path.isdir(folder_path): @@ -98,6 +102,7 @@ def delete_empty_folders(folder_path): except OSError: pass + def delete_registry_key(hive, key, recurse=False): """Delete a registry key and all it's subkeys.""" access = winreg.KEY_ALL_ACCESS @@ -117,12 +122,14 @@ def delete_registry_key(hive, key, recurse=False): # Ignore pass + def delete_registry_value(hive, key, value): """Delete a registry value.""" access = winreg.KEY_ALL_ACCESS with winreg.OpenKeyEx(hive, key, 0, access) as k: winreg.DeleteValue(k, value) + if __name__ == '__main__': print("This file is not meant to be called directly.") diff --git a/.bin/Scripts/functions/common.py b/.bin/Scripts/functions/common.py index b82a8918..a0a87b76 100644 --- a/.bin/Scripts/functions/common.py +++ b/.bin/Scripts/functions/common.py @@ -20,9 +20,11 @@ from settings.main import * from settings.tools import * from settings.windows_builds import * + # Global variables global_vars = {} + # STATIC VARIABLES COLORS = { 'CLEAR': '\033[0m', @@ -42,6 +44,7 @@ except NameError: if psutil.WINDOWS: raise + # Error Classes class BIOSKeyNotFoundError(Exception): pass @@ -85,6 +88,7 @@ class SecureBootNotAvailError(Exception): class SecureBootUnknownError(Exception): pass + # General functions def abort(): """Abort script.""" @@ -93,6 +97,7 @@ def abort(): pause(prompt='Press Enter to exit... ') exit_script() + def ask(prompt='Kotaero!'): """Prompt the user with a Y/N question, returns bool.""" answer = None @@ -109,6 +114,7 @@ def ask(prompt='Kotaero!'): print_log(message=message) return answer + def choice(choices, prompt='Kotaero!'): """Prompt the user with a choice question, returns str.""" answer = None @@ -137,6 +143,7 @@ def choice(choices, prompt='Kotaero!'): # Done return answer + def clear_screen(): """Simple wrapper for cls/clear.""" if psutil.WINDOWS: @@ -144,6 +151,7 @@ def clear_screen(): else: os.system('clear') + def convert_to_bytes(size): """Convert human-readable size str to bytes and return an int.""" size = str(size) @@ -165,6 +173,7 @@ def convert_to_bytes(size): return size + def exit_script(return_value=0): """Exits the script after some cleanup and opens the log (if set).""" # Remove dirs (if empty) @@ -192,6 +201,7 @@ def exit_script(return_value=0): # Exit sys.exit(return_value) + def extract_item(item, filter='', silent=False): """Extract item from .cbin into .bin.""" cmd = [ @@ -211,6 +221,7 @@ def extract_item(item, filter='', silent=False): if not silent: print_warning('WARNING: Errors encountered while exctracting data') + def get_process(name=None): """Get process by name, returns psutil.Process obj.""" proc = None @@ -226,6 +237,7 @@ def get_process(name=None): pass return proc + def get_simple_string(prompt='Enter string'): """Get string from user (restricted character set), returns str.""" simple_string = None @@ -235,6 +247,7 @@ def get_simple_string(prompt='Enter string'): simple_string = _input.strip() return simple_string + def get_ticket_number(): """Get TicketNumber from user, save in LogDir, and return as str.""" if not ENABLED_TICKET_NUMBERS: @@ -251,6 +264,7 @@ def get_ticket_number(): f.write(ticket_number) return ticket_number + def human_readable_size(size, decimals=0): """Convert size from bytes to a human-readable format, returns str.""" # Prep string formatting @@ -290,12 +304,14 @@ def human_readable_size(size, decimals=0): return '{size:>{width}.{decimals}f} {units}'.format( size=size, width=width, decimals=decimals, units=units) + def kill_process(name): """Kill any running caffeine.exe processes.""" for proc in psutil.process_iter(): if proc.name() == name: proc.kill() + def major_exception(): """Display traceback and exit""" print_error('Major exception') @@ -319,6 +335,7 @@ def major_exception(): pause('Press Enter to exit...') exit_script(1) + def menu_select( title='[Untitled Menu]', prompt='Please make a selection', secret_actions=[], secret_exit=False, @@ -382,6 +399,7 @@ def menu_select( return answer.upper() + def non_clobber_rename(full_path): """Append suffix to path, if necessary, to avoid clobbering path""" new_path = full_path @@ -392,10 +410,12 @@ def non_clobber_rename(full_path): return new_path + def pause(prompt='Press Enter to continue... '): """Simple pause implementation.""" input(prompt) + def ping(addr='google.com'): """Attempt to ping addr.""" cmd = [ @@ -405,6 +425,7 @@ def ping(addr='google.com'): addr] run_program(cmd) + def popen_program(cmd, pipe=False, minimized=False, shell=False, **kwargs): """Run program and return a subprocess.Popen object.""" cmd_kwargs = {'args': cmd, 'shell': shell} @@ -426,14 +447,17 @@ def popen_program(cmd, pipe=False, minimized=False, shell=False, **kwargs): return subprocess.Popen(**cmd_kwargs) + def print_error(*args, **kwargs): """Prints message to screen in RED.""" print_standard(*args, color=COLORS['RED'], **kwargs) + def print_info(*args, **kwargs): """Prints message to screen in BLUE.""" print_standard(*args, color=COLORS['BLUE'], **kwargs) + def print_standard(message='Generic info', color=None, end='\n', timestamp=True, **kwargs): """Prints message to screen and log (if set).""" @@ -444,14 +468,17 @@ def print_standard(message='Generic info', print(display_message.format(**COLORS), end=end, **kwargs) print_log(message, end, timestamp) + def print_success(*args, **kwargs): """Prints message to screen in GREEN.""" print_standard(*args, color=COLORS['GREEN'], **kwargs) + def print_warning(*args, **kwargs): """Prints message to screen in YELLOW.""" print_standard(*args, color=COLORS['YELLOW'], **kwargs) + def print_log(message='', end='\n', timestamp=True): """Writes message to a log if LogFile is set.""" time_str = time.strftime("%Y-%m-%d %H%M%z: ") if timestamp else '' @@ -463,6 +490,7 @@ def print_log(message='', end='\n', timestamp=True): line = line, end = end)) + def run_program(cmd, args=[], check=True, pipe=True, shell=False, **kwargs): """Run program and return a subprocess.CompletedProcess object.""" if args: @@ -486,6 +514,7 @@ def run_program(cmd, args=[], check=True, pipe=True, shell=False, **kwargs): return subprocess.run(**cmd_kwargs) + def set_title(title='[Some Title]'): """Set title. @@ -493,6 +522,7 @@ def set_title(title='[Some Title]'): global_vars['Title'] = title os.system('title {}'.format(title)) + def show_data( message='[Some message]', data='[Some data]', indent=8, width=32, @@ -509,10 +539,12 @@ def show_data( else: print_standard(message) + def sleep(seconds=2): """Wait for a while.""" time.sleep(seconds) + def stay_awake(): """Prevent the system from sleeping or hibernating.""" # DISABLED due to VCR2008 dependency @@ -529,12 +561,14 @@ def stay_awake(): print_error('ERROR: No caffeine available.') print_warning('Please set the power setting to High Performance.') + def strip_colors(s): """Remove all ASCII color escapes from string, returns str.""" for c in COLORS.values(): s = s.replace(c, '') return s + def get_exception(s): """Get exception by name, returns Exception object.""" try: @@ -544,6 +578,7 @@ def get_exception(s): obj = getattr(sys.modules['builtins'], s) return obj + def try_and_print(message='Trying...', function=None, cs='CS', ns='NS', other_results={}, catch_all=True, print_return=False, silent_function=True, @@ -600,6 +635,7 @@ def try_and_print(message='Trying...', else: return {'CS': not bool(err), 'Error': err, 'Out': out} + def upload_crash_details(): """Upload log and runtime data to the CRASH_SERVER. @@ -611,13 +647,11 @@ def upload_crash_details(): if 'LogFile' in global_vars and global_vars['LogFile']: if ask('Upload crash details to {}?'.format(CRASH_SERVER['Name'])): with open(global_vars['LogFile']) as f: - data = '''{} -############################# -Runtime Details: - -sys.argv: {} - -global_vars: {}'''.format(f.read(), sys.argv, global_vars) + data = '{}\n'.format(f.read()) + data += '#############################\n' + data += 'Runtime Details:\n\n' + data += 'sys.argv: {}\n\n'.format(sys.argv) + data += 'global_vars: {}\n'.format(global_vars) filename = global_vars.get('LogFile', 'Unknown') filename = re.sub(r'.*(\\|/)', '', filename) filename += '.txt' @@ -639,6 +673,7 @@ global_vars: {}'''.format(f.read(), sys.argv, global_vars) # No LogFile defined (or invalid LogFile) raise GenericError + def wait_for_process(name, poll_rate=3): """Wait for process by name.""" running = True @@ -654,6 +689,7 @@ def wait_for_process(name, poll_rate=3): pass sleep(1) + # global_vars functions def init_global_vars(silent=False): """Sets global variables based on system info.""" @@ -687,6 +723,7 @@ def init_global_vars(silent=False): except: major_exception() + def check_os(): """Set OS specific variables.""" tmp = {} @@ -749,6 +786,7 @@ def check_os(): global_vars['OS'] = tmp + def check_tools(): """Set tool variables based on OS bit-depth and tool availability.""" if global_vars['OS'].get('Arch', 32) == 64: @@ -761,6 +799,7 @@ def check_tools(): global_vars['Tools'] = {k: os.path.join(global_vars['BinDir'], v) for (k, v) in global_vars['Tools'].items()} + def clean_env_vars(): """Remove conflicting global_vars and env variables. @@ -769,6 +808,7 @@ def clean_env_vars(): for key in global_vars.keys(): global_vars['Env'].pop(key, None) + def find_bin(): """Find .bin folder in the cwd or it's parents.""" wd = os.getcwd() @@ -785,6 +825,7 @@ def find_bin(): raise BinNotFoundError global_vars['BaseDir'] = base + def make_tmp_dirs(): """Make temp directories.""" os.makedirs(global_vars['BackupDir'], exist_ok=True) @@ -794,6 +835,7 @@ def make_tmp_dirs(): os.makedirs(r'{}\Tools'.format(global_vars['LogDir']), exist_ok=True) os.makedirs(global_vars['TmpDir'], exist_ok=True) + def set_common_vars(): """Set common variables.""" global_vars['Date'] = time.strftime("%Y-%m-%d") @@ -816,6 +858,7 @@ def set_common_vars(): global_vars['TmpDir'] = r'{BinDir}\tmp'.format( **global_vars) + def set_linux_vars(): """Set common variables in a Linux environment. @@ -832,6 +875,7 @@ def set_linux_vars(): 'SevenZip': '7z', } + def set_log_file(log_name): """Sets global var LogFile and creates path as needed.""" folder_path = r'{}\{}'.format(global_vars['LogDir'], KIT_NAME_FULL) @@ -839,6 +883,7 @@ def set_log_file(log_name): os.makedirs(folder_path, exist_ok=True) global_vars['LogFile'] = log_file + if __name__ == '__main__': print("This file is not meant to be called directly.") diff --git a/.bin/Scripts/functions/data.py b/.bin/Scripts/functions/data.py index d6c4ad9b..a151b24c 100644 --- a/.bin/Scripts/functions/data.py +++ b/.bin/Scripts/functions/data.py @@ -7,57 +7,6 @@ from operator import itemgetter from functions.common import * -# Classes -class LocalDisk(): - def __init__(self, disk): - self.disk = disk - self.name = disk.mountpoint.upper() - self.path = self.name - def is_dir(self): - # Should always be true - return True - def is_file(self): - # Should always be false - return False - -class SourceItem(): - def __init__(self, name, path): - self.name = name - self.path = path - -# Regex -REGEX_EXCL_ITEMS = re.compile( - r'^(\.(AppleDB|AppleDesktop|AppleDouble' - r'|com\.apple\.timemachine\.supported|dbfseventsd' - r'|DocumentRevisions-V100.*|DS_Store|fseventsd|PKInstallSandboxManager' - r'|Spotlight.*|SymAV.*|symSchedScanLockxz|TemporaryItems|Trash.*' - r'|vol|VolumeIcon\.icns)|desktop\.(ini|.*DB|.*DF)' - r'|(hiberfil|pagefile)\.sys|lost\+found|Network\.*Trash\.*Folder' - r'|Recycle[dr]|System\.*Volume\.*Information|Temporary\.*Items' - r'|Thumbs\.db)$', - re.IGNORECASE) -REGEX_EXCL_ROOT_ITEMS = re.compile( - r'^(boot(mgr|nxt)$|Config.msi' - r'|(eula|globdata|install|vc_?red)' - r'|.*.sys$|System Volume Information|RECYCLER?|\$Recycle\.bin' - r'|\$?Win(dows(.old.*|\. BT|)$|RE_)|\$GetCurrent|Windows10Upgrade' - r'|PerfLogs|Program Files|SYSTEM.SAV' - r'|.*\.(esd|swm|wim|dd|map|dmg|image)$)', - re.IGNORECASE) -REGEX_INCL_ROOT_ITEMS = re.compile( - r'^(AdwCleaner|(My\s*|)(Doc(uments?( and Settings|)|s?)|Downloads' - r'|Media|Music|Pic(ture|)s?|Vid(eo|)s?)' - r'|{prefix}(-?Info|-?Transfer|)' - r'|(ProgramData|Recovery|Temp.*|Users)$' - r'|.*\.(log|txt|rtf|qb\w*|avi|m4a|m4v|mp4|mkv|jpg|png|tiff?)$)' - r''.format(prefix=KIT_NAME_SHORT), - re.IGNORECASE) -REGEX_WIM_FILE = re.compile( - r'\.wim$', - re.IGNORECASE) -REGEX_WINDOWS_OLD = re.compile( - r'^Win(dows|)\.old', - re.IGNORECASE) # STATIC VARIABLES FAST_COPY_EXCLUDES = [ @@ -116,6 +65,63 @@ SEM_FAILCRITICALERRORS = 1 SEM_NOOPENFILEERRORBOX = 0x8000 SEM_FAIL = SEM_NOOPENFILEERRORBOX | SEM_FAILCRITICALERRORS + +# Regex +REGEX_EXCL_ITEMS = re.compile( + r'^(\.(AppleDB|AppleDesktop|AppleDouble' + r'|com\.apple\.timemachine\.supported|dbfseventsd' + r'|DocumentRevisions-V100.*|DS_Store|fseventsd|PKInstallSandboxManager' + r'|Spotlight.*|SymAV.*|symSchedScanLockxz|TemporaryItems|Trash.*' + r'|vol|VolumeIcon\.icns)|desktop\.(ini|.*DB|.*DF)' + r'|(hiberfil|pagefile)\.sys|lost\+found|Network\.*Trash\.*Folder' + r'|Recycle[dr]|System\.*Volume\.*Information|Temporary\.*Items' + r'|Thumbs\.db)$', + re.IGNORECASE) +REGEX_EXCL_ROOT_ITEMS = re.compile( + r'^(boot(mgr|nxt)$|Config.msi' + r'|(eula|globdata|install|vc_?red)' + r'|.*.sys$|System Volume Information|RECYCLER?|\$Recycle\.bin' + r'|\$?Win(dows(.old.*|\. BT|)$|RE_)|\$GetCurrent|Windows10Upgrade' + r'|PerfLogs|Program Files|SYSTEM.SAV' + r'|.*\.(esd|swm|wim|dd|map|dmg|image)$)', + re.IGNORECASE) +REGEX_INCL_ROOT_ITEMS = re.compile( + r'^(AdwCleaner|(My\s*|)(Doc(uments?( and Settings|)|s?)|Downloads' + r'|Media|Music|Pic(ture|)s?|Vid(eo|)s?)' + r'|{prefix}(-?Info|-?Transfer|)' + r'|(ProgramData|Recovery|Temp.*|Users)$' + r'|.*\.(log|txt|rtf|qb\w*|avi|m4a|m4v|mp4|mkv|jpg|png|tiff?)$)' + r''.format(prefix=KIT_NAME_SHORT), + re.IGNORECASE) +REGEX_WIM_FILE = re.compile( + r'\.wim$', + re.IGNORECASE) +REGEX_WINDOWS_OLD = re.compile( + r'^Win(dows|)\.old', + re.IGNORECASE) + + +# Classes +class LocalDisk(): + def __init__(self, disk): + self.disk = disk + self.name = disk.mountpoint.upper() + self.path = self.name + def is_dir(self): + # Should always be true + return True + def is_file(self): + # Should always be false + return False + + +class SourceItem(): + def __init__(self, name, path): + self.name = name + self.path = path + + +# Functions def cleanup_transfer(dest_path): """Fix attributes and move excluded items to separate folder.""" try: @@ -153,6 +159,7 @@ def cleanup_transfer(dest_path): except Exception: pass + def find_core_storage_volumes(device_path=None): """Try to create block devices for any Apple CoreStorage volumes.""" corestorage_uuid = '53746f72-6167-11aa-aa11-00306543ecac' @@ -216,10 +223,12 @@ def find_core_storage_volumes(device_path=None): cmd = ['sudo', 'dmsetup', 'create', name, dmsetup_cmd_file] run_program(cmd, check=False) + def fix_path_sep(path_str): """Replace non-native and duplicate dir separators, returns str.""" return re.sub(r'(\\|/)+', lambda s: os.sep, path_str) + def is_valid_wim_file(item): """Checks if the item is a valid WIM file, returns bool.""" valid = bool(item.is_file() and REGEX_WIM_FILE.search(item.name)) @@ -233,6 +242,7 @@ def is_valid_wim_file(item): print_log('WARNING: Image "{}" damaged.'.format(item.name)) return valid + def get_mounted_volumes(): """Get mounted volumes, returns dict.""" cmd = [ @@ -250,6 +260,7 @@ def get_mounted_volumes(): mounted_volumes.extend(item.get('children', [])) return {item['source']: item for item in mounted_volumes} + def mount_volumes( all_devices=True, device_path=None, read_write=False, core_storage=True): @@ -342,6 +353,7 @@ def mount_volumes( return report + def mount_backup_shares(read_write=False): """Mount the backup shares unless labeled as already mounted.""" if psutil.LINUX: @@ -363,6 +375,7 @@ def mount_backup_shares(read_write=False): mount_network_share(server, read_write) + def mount_network_share(server, read_write=False): """Mount a network share defined by server.""" if read_write: @@ -415,6 +428,7 @@ def mount_network_share(server, read_write=False): print_info(success) server['Mounted'] = True + def run_fast_copy(items, dest): """Copy items to dest using FastCopy.""" if not items: @@ -427,6 +441,7 @@ def run_fast_copy(items, dest): run_program(cmd) + def run_wimextract(source, items, dest): """Extract items from source WIM to dest folder.""" if not items: @@ -452,6 +467,7 @@ def run_wimextract(source, items, dest): '--nullglob'] run_program(cmd) + def list_source_items(source_obj, rel_path=None): """List items in a dir or WIM, returns list of SourceItem objects.""" items = [] @@ -489,6 +505,7 @@ def list_source_items(source_obj, rel_path=None): # Done return items + def scan_source(source_obj, dest_path, rel_path='', interactive=True): """Scan source for files/folders to transfer, returns list. @@ -572,6 +589,7 @@ def scan_source(source_obj, dest_path, rel_path='', interactive=True): # Done return selected_items + def get_source_item_obj(source_obj, rel_path, item_path): """Check if the item exists, returns SourceItem object or None.""" item_obj = None @@ -611,6 +629,7 @@ def get_source_item_obj(source_obj, rel_path, item_path): item_path)) return item_obj + def select_destination(folder_path, prompt='Select destination'): """Select destination drive, returns path as string.""" disk = select_volume(prompt) @@ -627,6 +646,7 @@ def select_destination(folder_path, prompt='Select destination'): return path + def select_source(backup_prefix): """Select matching backup from BACKUP_SERVERS, returns obj.""" selected_source = None @@ -792,6 +812,7 @@ def select_source(backup_prefix): # Done return selected_source + def select_volume(title='Select disk', auto_select=True): """Select disk from attached disks. returns dict.""" actions = [{'Name': 'Quit', 'Letter': 'Q'}] @@ -829,6 +850,7 @@ def select_volume(title='Select disk', auto_select=True): else: return disks[int(selection)-1] + def set_thread_error_mode(silent=True): """Disable or Enable Windows error message dialogs. @@ -842,6 +864,7 @@ def set_thread_error_mode(silent=True): else: kernel32.SetThreadErrorMode(SEM_NORMAL, ctypes.byref(SEM_NORMAL)) + def transfer_source(source_obj, dest_path, selected_items): """Transfer, or extract, files/folders from source to destination.""" if source_obj.is_dir(): @@ -864,11 +887,13 @@ def transfer_source(source_obj, dest_path, selected_items): print_error('ERROR: Unsupported image: {}'.format(source_obj.path)) raise GenericError + def umount_backup_shares(): """Unmount the backup shares regardless of current status.""" for server in BACKUP_SERVERS: umount_network_share(server) + def umount_network_share(server): """Unmount a network share defined by server.""" cmd = r'net use \\{IP}\{Share} /delete'.format(**server) @@ -882,6 +907,7 @@ def umount_network_share(server): print_info('Umounted {Name}'.format(**server)) server['Mounted'] = False + if __name__ == '__main__': print("This file is not meant to be called directly.") diff --git a/.bin/Scripts/functions/ddrescue.py b/.bin/Scripts/functions/ddrescue.py index e15c0c71..e6def7f2 100644 --- a/.bin/Scripts/functions/ddrescue.py +++ b/.bin/Scripts/functions/ddrescue.py @@ -15,6 +15,7 @@ from functions.hw_diags import * from functions.tmux import * from operator import itemgetter + # STATIC VARIABLES AUTO_PASS_1_THRESHOLD = 95 AUTO_PASS_2_THRESHOLD = 98 @@ -778,6 +779,7 @@ def menu_ddrescue(source_path, dest_path, run_mode): run_program(['tmux', 'kill-window']) exit_script() + def menu_main(state): """Main menu is used to set ddrescue settings.""" title = '{GREEN}ddrescue TUI: Main Menu{CLEAR}\n\n'.format(**COLORS) diff --git a/.bin/Scripts/functions/disk.py b/.bin/Scripts/functions/disk.py index 88b26155..31fe577d 100644 --- a/.bin/Scripts/functions/disk.py +++ b/.bin/Scripts/functions/disk.py @@ -3,6 +3,7 @@ from functions.common import * from settings.partition_uids import * + # Regex REGEX_BAD_PARTITION = re.compile(r'(RAW|Unknown)', re.IGNORECASE) REGEX_DISK_GPT = re.compile( @@ -11,6 +12,7 @@ REGEX_DISK_GPT = re.compile( REGEX_DISK_MBR = re.compile(r'Disk ID: [A-Z0-9]+', re.IGNORECASE) REGEX_DISK_RAW = re.compile(r'Disk ID: 00000000', re.IGNORECASE) + def assign_volume_letters(): """Assign a volume letter to all available volumes.""" remove_volume_letters() @@ -24,6 +26,7 @@ def assign_volume_letters(): # Run run_diskpart(script) + def get_boot_mode(): """Check if the boot mode was UEFI or legacy.""" boot_mode = 'Legacy' @@ -38,6 +41,7 @@ def get_boot_mode(): return boot_mode + def get_disk_details(disk): """Get disk details using DiskPart.""" details = {} @@ -63,6 +67,7 @@ def get_disk_details(disk): return details + def get_disks(): """Get list of attached disks using DiskPart.""" disks = [] @@ -82,6 +87,7 @@ def get_disks(): return disks + def get_partition_details(disk, partition): """Get partition details using DiskPart and fsutil.""" details = {} @@ -161,6 +167,7 @@ def get_partition_details(disk, partition): return details + def get_partitions(disk): """Get list of partition using DiskPart.""" partitions = [] @@ -184,6 +191,7 @@ def get_partitions(disk): return partitions + def get_table_type(disk): """Get disk partition table type using DiskPart.""" part_type = 'Unknown' @@ -206,6 +214,7 @@ def get_table_type(disk): return part_type + def get_volumes(): """Get list of volumes using DiskPart.""" vols = [] @@ -221,10 +230,12 @@ def get_volumes(): return vols + def is_bad_partition(par): """Check if the partition is accessible.""" return 'Letter' not in par or REGEX_BAD_PARTITION.search(par['FileSystem']) + def prep_disk_for_formatting(disk=None): """Gather details about the disk and its partitions.""" disk['Format Warnings'] = '\n' @@ -270,6 +281,7 @@ def prep_disk_for_formatting(disk=None): # For all partitions partition['Display String'] = display + def reassign_volume_letter(letter, new_letter='I'): """Assign a new letter to a volume using DiskPart.""" if not letter: @@ -286,6 +298,7 @@ def reassign_volume_letter(letter, new_letter='I'): else: return new_letter + def remove_volume_letters(keep=None): """Remove all assigned volume letters using DiskPart.""" if not keep: @@ -303,6 +316,7 @@ def remove_volume_letters(keep=None): except subprocess.CalledProcessError: pass + def run_diskpart(script): """Run DiskPart script.""" tempfile = r'{}\diskpart.script'.format(global_vars['Env']['TMP']) @@ -321,6 +335,7 @@ def run_diskpart(script): sleep(2) return result + def scan_disks(): """Get details about the attached disks""" disks = get_disks() @@ -343,6 +358,7 @@ def scan_disks(): # Done return disks + def select_disk(title='Which disk?', disks=[]): """Select a disk from the attached disks""" # Build menu @@ -391,6 +407,7 @@ def select_disk(title='Which disk?', disks=[]): elif (selection == 'M'): raise GenericAbort + if __name__ == '__main__': print("This file is not meant to be called directly.") diff --git a/.bin/Scripts/functions/hw_diags.py b/.bin/Scripts/functions/hw_diags.py index 210ae870..155031ec 100644 --- a/.bin/Scripts/functions/hw_diags.py +++ b/.bin/Scripts/functions/hw_diags.py @@ -8,6 +8,7 @@ from collections import OrderedDict from functions.sensors import * from functions.tmux import * + # STATIC VARIABLES ATTRIBUTES = { 'NVMe': { @@ -83,13 +84,16 @@ TMUX_LAYOUT = OrderedDict({ 'Progress': {'x': SIDE_PANE_WIDTH, 'Check': True}, }) + # Regex REGEX_ERROR_STATUS = re.compile('|'.join(STATUSES['RED'])) + # Error Classes class DeviceTooSmallError(Exception): pass + # Classes class CpuObj(): """Object for tracking CPU specific data.""" @@ -130,6 +134,7 @@ class CpuObj(): return report + class DiskObj(): """Object for tracking disk specific data.""" def __init__(self, disk_path): @@ -487,6 +492,7 @@ class DiskObj(): for t in ['badblocks', 'I/O Benchmark']: self.disable_test(t, 'Denied') + class State(): """Object to track device objects and overall state.""" def __init__(self): @@ -559,6 +565,7 @@ class State(): if not skip_disk: self.disks.append(disk_obj) + class TestObj(): """Object to track test data.""" def __init__(self, dev, label=None, info_label=False): @@ -589,6 +596,7 @@ class TestObj(): self.status = build_status_string( self.label, 'Working', self.info_label) + # Functions def build_outer_panes(state): """Build top and side panes.""" @@ -611,6 +619,7 @@ def build_outer_panes(state): lines=SIDE_PANE_WIDTH, watch=state.progress_out) + def build_status_string(label, status, info_label=False): """Build status string with appropriate colors.""" status_color = COLORS['CLEAR'] @@ -626,6 +635,7 @@ def build_status_string(label, status, info_label=False): s_w=SIDE_PANE_WIDTH-len(label), **COLORS) + def fix_tmux_panes(state, tmux_layout): """Fix pane sizes if the window has been resized.""" needs_fixed = False @@ -669,6 +679,7 @@ def fix_tmux_panes(state, tmux_layout): # Resize pane tmux_resize_pane(pane_id=target, **v) + def generate_horizontal_graph(rates, oneline=False): """Generate horizontal graph from rates, returns list.""" graph = ['', '', '', ''] @@ -714,6 +725,7 @@ def generate_horizontal_graph(rates, oneline=False): else: return graph + def get_graph_step(rate, scale=16): """Get graph step based on rate and scale, returns int.""" m_rate = rate / (1024**2) @@ -726,6 +738,7 @@ def get_graph_step(rate, scale=16): break return step + def get_read_rate(s): """Get read rate in bytes/s from dd progress output.""" real_rate = None @@ -734,6 +747,7 @@ def get_read_rate(s): real_rate = convert_to_bytes(human_rate) return real_rate + def menu_diags(state, args): """Main menu to select and run HW tests.""" args = [a.lower() for a in args] @@ -840,12 +854,14 @@ def menu_diags(state, args): elif selection == 'S': run_hw_tests(state) + def run_audio_test(): """Run audio test.""" clear_screen() run_program(['hw-diags-audio'], check=False, pipe=False) pause('Press Enter to return to main menu... ') + def run_badblocks_test(state, test): """Run a read-only surface scan with badblocks.""" # Bail early @@ -939,6 +955,7 @@ def run_badblocks_test(state, test): # Cleanup tmux_kill_pane(state.panes['badblocks']) + def run_hw_tests(state): """Run enabled hardware tests.""" print_standard('Scanning devices...') @@ -1016,6 +1033,7 @@ def run_hw_tests(state): # Cleanup tmux_kill_pane(*state.panes.values()) + def run_io_benchmark(state, test): """Run a read-only I/O benchmark using dd.""" # Bail early @@ -1173,11 +1191,13 @@ def run_io_benchmark(state, test): # Cleanup tmux_kill_pane(state.panes['io_benchmark']) + def run_keyboard_test(): """Run keyboard test.""" clear_screen() run_program(['xev', '-event', 'keyboard'], check=False, pipe=False) + def run_mprime_test(state, test): """Test CPU with Prime95 and track temps.""" # Bail early @@ -1371,12 +1391,14 @@ def run_mprime_test(state, test): tmux_kill_pane(state.panes['mprime'], state.panes['Temps']) test.monitor_proc.kill() + def run_network_test(): """Run network test.""" clear_screen() run_program(['hw-diags-network'], check=False, pipe=False) pause('Press Enter to return to main menu... ') + def run_nvme_smart_tests(state, test): """Run NVMe or SMART test for test.dev.""" # Bail early @@ -1520,6 +1542,7 @@ def run_nvme_smart_tests(state, test): # Done update_progress_pane(state) + def secret_screensaver(screensaver=None): """Show screensaver.""" if screensaver == 'matrix': @@ -1530,6 +1553,7 @@ def secret_screensaver(screensaver=None): raise Exception('Invalid screensaver') run_program(cmd, check=False, pipe=False) + def show_report(report, log_report=False): """Show report on screen and optionally save to log w/out color.""" for line in report: @@ -1537,6 +1561,7 @@ def show_report(report, log_report=False): if log_report: print_log(strip_colors(line)) + def show_results(state): """Show results for all tests.""" clear_screen() @@ -1564,6 +1589,7 @@ def show_results(state): show_report(disk.generate_disk_report(), log_report=True) print_standard(' ') + def update_main_options(state, selection, main_options): """Update menu and state based on selection.""" index = int(selection) - 1 @@ -1607,6 +1633,7 @@ def update_main_options(state, selection, main_options): # Done return main_options + def update_io_progress(percent, rate, progress_file): """Update I/O progress file.""" bar_color = COLORS['CLEAR'] @@ -1631,6 +1658,7 @@ def update_io_progress(percent, rate, progress_file): with open(progress_file, 'a') as f: f.write(line) + def update_progress_pane(state): """Update progress file for side pane.""" output = [] @@ -1658,6 +1686,7 @@ def update_progress_pane(state): with open(state.progress_out, 'w') as f: f.writelines(output) + if __name__ == '__main__': print("This file is not meant to be called directly.") diff --git a/.bin/Scripts/functions/info.py b/.bin/Scripts/functions/info.py index 70d1062a..adee5f80 100644 --- a/.bin/Scripts/functions/info.py +++ b/.bin/Scripts/functions/info.py @@ -6,15 +6,6 @@ from operator import itemgetter from functions.common import * from functions.activation import * -# Regex -REGEX_OFFICE = re.compile( - r'(Microsoft (Office\s+' - r'(365|Enterprise|Home|Pro(\s|fessional)' - r'|Single|Small|Standard|Starter|Ultimate|system)' - r'|Works[-\s\d]+\d)' - r'|(Libre|Open|Star)\s*Office' - r'|WordPerfect|Gnumeric|Abiword)', - re.IGNORECASE) # STATIC VARIABLES REG_PROFILE_LIST = r'SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList' @@ -55,6 +46,18 @@ SHELL_FOLDERS = { ), } + +# Regex +REGEX_OFFICE = re.compile( + r'(Microsoft (Office\s+' + r'(365|Enterprise|Home|Pro(\s|fessional)' + r'|Single|Small|Standard|Starter|Ultimate|system)' + r'|Works[-\s\d]+\d)' + r'|(Libre|Open|Star)\s*Office' + r'|WordPerfect|Gnumeric|Abiword)', + re.IGNORECASE) + + def backup_file_list(): """Export current file listing for the system.""" extract_item('Everything', silent=True) @@ -66,6 +69,7 @@ def backup_file_list(): global_vars['Env']['SYSTEMDRIVE']] run_program(cmd) + def backup_power_plans(): """Export current power plans.""" os.makedirs(r'{BackupDir}\Power Plans\{Date}'.format( @@ -83,6 +87,7 @@ def backup_power_plans(): cmd = ['powercfg', '-export', out, guid] run_program(cmd, check=False) + def backup_registry(overwrite=False): """Backup registry including user hives.""" extract_item('erunt', silent=True) @@ -97,6 +102,7 @@ def backup_registry(overwrite=False): cmd.append('/noconfirmdelete') run_program(cmd) + def get_folder_size(path): """Get (human-readable) size of folder passed, returns str.""" size = 'Unknown' @@ -119,6 +125,7 @@ def get_folder_size(path): size = human_readable_size(size) return size + def get_installed_antivirus(): """Get list of installed Antivirus programs.""" programs = [] @@ -149,6 +156,7 @@ def get_installed_antivirus(): programs = ['No programs found'] return programs + def get_installed_office(): """Get list of installed Office programs.""" programs = [] @@ -163,6 +171,7 @@ def get_installed_office(): programs = ['No programs found'] return programs + def get_shell_path(folder, user='current'): """Get shell path using knownpaths, returns str. @@ -189,6 +198,7 @@ def get_shell_path(folder, user='current'): return path + def get_user_data_paths(user): """Get user data paths for provided user, returns dict.""" hive_path = user['SID'] @@ -273,6 +283,7 @@ def get_user_data_paths(user): # Done return paths + def get_user_folder_sizes(users): """Update list(users) to include folder paths and sizes.""" extract_item('du', filter='du*', silent=True) @@ -293,6 +304,7 @@ def get_user_folder_sizes(users): u['Extra Folders'][folder]['Size'] = get_folder_size( u['Extra Folders'][folder]['Path']) + def get_user_list(): """Get user list via WMIC, returns list of dicts.""" users = [] @@ -325,6 +337,7 @@ def get_user_list(): # Done return users + def reg_path_exists(hive, path): """Test if specified path exists, returns bool.""" try: @@ -334,6 +347,7 @@ def reg_path_exists(hive, path): else: return True + def run_aida64(): """Run AIDA64 to save system reports.""" extract_item('AIDA64', silent=True) @@ -372,6 +386,7 @@ def run_aida64(): '/TEXT', '/SILENT', '/SAFEST'] run_program(cmd, check=False) + def run_bleachbit(cleaners=None, preview=True): """Run BleachBit preview and save log. @@ -404,6 +419,7 @@ def run_bleachbit(cleaners=None, preview=True): for line in out.stdout.decode().splitlines(): f.write(line.strip() + '\n') + def show_disk_usage(disk): """Show free and used space for a specified disk.""" print_standard('{:5}'.format(disk.device.replace('/', ' ')), @@ -423,6 +439,7 @@ def show_disk_usage(disk): except Exception: print_warning('Unknown', timestamp=False) + def show_free_space(indent=8, width=32): """Show free space info for all fixed disks.""" message = 'Free Space:' @@ -436,6 +453,7 @@ def show_free_space(indent=8, width=32): except Exception: pass + def show_installed_ram(): """Show installed RAM.""" mem = psutil.virtual_memory() @@ -448,6 +466,7 @@ def show_installed_ram(): else: print_error(human_readable_size(mem.total).strip(), timestamp=False) + def show_os_activation(): """Show OS activation info.""" act_str = get_activation_string() @@ -458,6 +477,7 @@ def show_os_activation(): else: print_error(act_str, timestamp=False) + def show_os_name(): """Show extended OS name (including warnings).""" os_name = global_vars['OS']['DisplayName'] @@ -475,6 +495,7 @@ def show_os_name(): else: print_standard(os_name, timestamp=False) + def show_temp_files_size(): """Show total size of temp files identified by BleachBit.""" size = None @@ -488,6 +509,7 @@ def show_temp_files_size(): else: print_standard(size, timestamp=False) + def show_user_data_summary(indent=8, width=32): """Print user data folder sizes for all users.""" users = get_user_list() @@ -520,6 +542,7 @@ def show_user_data_summary(indent=8, width=32): size = folders[folder].get('Size', 'Unknown'), path = folders[folder].get('Path', 'Unknown'))) + if __name__ == '__main__': print("This file is not meant to be called directly.") diff --git a/.bin/Scripts/functions/network.py b/.bin/Scripts/functions/network.py index 80935506..9d9b7af1 100644 --- a/.bin/Scripts/functions/network.py +++ b/.bin/Scripts/functions/network.py @@ -11,6 +11,7 @@ os.chdir(os.path.dirname(os.path.realpath(__file__))) sys.path.append(os.getcwd()) from functions.common import * + # REGEX REGEX_VALID_IP = re.compile( r'(10.\d+.\d+.\d+' @@ -18,6 +19,7 @@ REGEX_VALID_IP = re.compile( r'|192.168.\d+.\d+)', re.IGNORECASE) + def connect_to_network(): """Connect to network if not already connected.""" net_ifs = psutil.net_if_addrs() @@ -38,6 +40,7 @@ def connect_to_network(): function = run_program, cmd = cmd) + def is_connected(): """Check for a valid private IP.""" devs = psutil.net_if_addrs() @@ -49,6 +52,7 @@ def is_connected(): # Else return False + def show_valid_addresses(): """Show all valid private IP addresses assigned to the system.""" devs = psutil.net_if_addrs() @@ -58,6 +62,7 @@ def show_valid_addresses(): # Valid IP found show_data(message=dev, data=family.address) + def speedtest(): """Run a network speedtest using speedtest-cli.""" result = run_program(['speedtest-cli', '--simple']) @@ -67,6 +72,7 @@ def speedtest(): output = [(a, float(b), c) for a, b, c in output] return ['{:10}{:6.2f} {}'.format(*line) for line in output] + if __name__ == '__main__': print("This file is not meant to be called directly.") diff --git a/.bin/Scripts/functions/product_keys.py b/.bin/Scripts/functions/product_keys.py index 1d96ec0b..950e509b 100644 --- a/.bin/Scripts/functions/product_keys.py +++ b/.bin/Scripts/functions/product_keys.py @@ -2,12 +2,14 @@ from functions.common import * + # Regex REGEX_REGISTRY_DIRS = re.compile( r'^(config$|RegBack$|System32$|Transfer|Win)', re.IGNORECASE) REGEX_SOFTWARE_HIVE = re.compile(r'^Software$', re.IGNORECASE) + def extract_keys(): """Extract keys from provided hives and return a dict.""" keys = {} @@ -43,6 +45,7 @@ def extract_keys(): # Done return keys + def list_clientdir_keys(): """List product keys found in hives inside the ClientDir.""" keys = extract_keys() @@ -57,6 +60,7 @@ def list_clientdir_keys(): return key_list + def find_software_hives(): """Search for transferred SW hives and return a list.""" hives = [] @@ -71,6 +75,7 @@ def find_software_hives(): return hives + def get_product_keys(): """List product keys from saved report.""" keys = [] @@ -86,6 +91,7 @@ def get_product_keys(): else: return ['No product keys found'] + def run_produkey(): """Run ProduKey and save report in the ClientDir.""" extract_item('ProduKey', silent=True) @@ -107,6 +113,7 @@ def run_produkey(): log_file] run_program(cmd, check=False) + if __name__ == '__main__': print("This file is not meant to be called directly.") diff --git a/.bin/Scripts/functions/repairs.py b/.bin/Scripts/functions/repairs.py index a964220c..f1e10a4a 100644 --- a/.bin/Scripts/functions/repairs.py +++ b/.bin/Scripts/functions/repairs.py @@ -2,6 +2,7 @@ from functions.common import * + def run_chkdsk(repair=False): """Run CHKDSK scan or schedule offline repairs.""" if repair: @@ -9,6 +10,7 @@ def run_chkdsk(repair=False): else: run_chkdsk_scan() + def run_chkdsk_scan(): """Run CHKDSK in a "split window" and report errors.""" if global_vars['OS']['Version'] in ('8', '8.1', '10'): @@ -32,6 +34,7 @@ def run_chkdsk_scan(): for line in out.stdout.decode().splitlines(): f.write(line.strip() + '\n') + def run_chkdsk_offline(): """Set filesystem 'dirty bit' to force a chkdsk during next boot.""" cmd = [ @@ -42,6 +45,7 @@ def run_chkdsk_offline(): if int(out.returncode) > 0: raise GenericError + def run_dism(repair=False): """Run DISM to either scan or repair component store health.""" if global_vars['OS']['Version'] in ('8', '8.1', '10'): @@ -75,6 +79,7 @@ def run_dism(repair=False): else: raise UnsupportedOSError + def run_kvrt(): """Run KVRT.""" extract_item('KVRT', silent=True) @@ -86,6 +91,7 @@ def run_kvrt(): '-processlevel', '3'] popen_program(cmd, pipe=False) + def run_sfc_scan(): """Run SFC in a "split window" and report errors.""" cmd = [ @@ -109,6 +115,7 @@ def run_sfc_scan(): else: raise GenericError + def run_tdsskiller(): """Run TDSSKiller.""" extract_item('TDSSKiller', silent=True) @@ -122,6 +129,7 @@ def run_tdsskiller(): '-dcexact', '-tdlfs'] run_program(cmd, pipe=False) + if __name__ == '__main__': print("This file is not meant to be called directly.") diff --git a/.bin/Scripts/functions/safemode.py b/.bin/Scripts/functions/safemode.py index 837b14e8..041cd506 100644 --- a/.bin/Scripts/functions/safemode.py +++ b/.bin/Scripts/functions/safemode.py @@ -2,19 +2,23 @@ from functions.common import * + # STATIC VARIABLES REG_MSISERVER = r'HKLM\SYSTEM\CurrentControlSet\Control\SafeBoot\Network\MSIServer' + def disable_safemode_msi(): """Disable MSI access under safemode.""" cmd = ['reg', 'delete', REG_MSISERVER, '/f'] run_program(cmd) + def disable_safemode(): """Edit BCD to remove safeboot value.""" cmd = ['bcdedit', '/deletevalue', '{default}', 'safeboot'] run_program(cmd) + def enable_safemode_msi(): """Enable MSI access under safemode.""" cmd = ['reg', 'add', REG_MSISERVER, '/f'] @@ -23,15 +27,18 @@ def enable_safemode_msi(): '/t', 'REG_SZ', '/d', 'Service', '/f'] run_program(cmd) + def enable_safemode(): """Edit BCD to set safeboot as default.""" cmd = ['bcdedit', '/set', '{default}', 'safeboot', 'network'] run_program(cmd) + def reboot(delay=3): cmd = ['shutdown', '-r', '-t', '{}'.format(delay)] run_program(cmd, check=False) + if __name__ == '__main__': print("This file is not meant to be called directly.") diff --git a/.bin/Scripts/functions/sensors.py b/.bin/Scripts/functions/sensors.py index 2fde69c4..a50f8941 100644 --- a/.bin/Scripts/functions/sensors.py +++ b/.bin/Scripts/functions/sensors.py @@ -5,6 +5,7 @@ import re from functions.tmux import * + # STATIC VARIABLES TEMP_LIMITS = { 'GREEN': 60, @@ -13,9 +14,11 @@ TEMP_LIMITS = { 'RED': 90, } + # REGEX REGEX_COLORS = re.compile(r'\033\[\d+;?1?m') + def clear_temps(sensor_data): """Clear saved temps but keep structure, returns dict.""" for _section, _adapters in sensor_data.items(): @@ -23,6 +26,7 @@ def clear_temps(sensor_data): for _source, _data in _sources.items(): _data['Temps'] = [] + def fix_sensor_str(s): """Cleanup string and return str.""" s = re.sub(r'^(\w+)-(\w+)-(\w+)', r'\1 (\2 \3)', s, re.IGNORECASE) @@ -36,6 +40,7 @@ def fix_sensor_str(s): s = s.replace(' ', ' ') return s + def generate_sensor_report( sensor_data, *temp_labels, colors=True, core_only=False): @@ -73,6 +78,7 @@ def generate_sensor_report( # Done return report + def get_colored_temp_str(temp): """Get colored string based on temp, returns str.""" try: @@ -97,6 +103,7 @@ def get_colored_temp_str(temp): temp = temp, **COLORS) + def get_raw_sensor_data(): """Read sensor data and return dict.""" data = {} @@ -110,6 +117,7 @@ def get_raw_sensor_data(): return data + def get_sensor_data(): """Parse raw sensor data and return new dict.""" json_data = get_raw_sensor_data() @@ -141,6 +149,7 @@ def get_sensor_data(): # Done return sensor_data + def get_temp_str(temp, colors=True): """Get temp string, returns str.""" if colors: @@ -154,6 +163,7 @@ def get_temp_str(temp, colors=True): '-' if temp < 0 else '', temp) + def monitor_sensors(monitor_pane, monitor_file): """Continually update sensor data and report to screen.""" sensor_data = get_sensor_data() @@ -166,6 +176,7 @@ def monitor_sensors(monitor_pane, monitor_file): if monitor_pane and not tmux_poll_pane(monitor_pane): break + def save_average_temp(sensor_data, temp_label, seconds=10): """Save average temps under temp_label, returns dict.""" clear_temps(sensor_data) @@ -181,6 +192,7 @@ def save_average_temp(sensor_data, temp_label, seconds=10): for _source, _data in _sources.items(): _data[temp_label] = sum(_data['Temps']) / len(_data['Temps']) + def update_sensor_data(sensor_data): """Read sensors and update existing sensor_data, returns dict.""" json_data = get_raw_sensor_data() @@ -193,12 +205,14 @@ def update_sensor_data(sensor_data): _data['Max'] = max(_temp, _data['Max']) _data['Temps'].append(_temp) + def join_columns(column1, column2, width=55): return '{:<{}}{}'.format( column1, 55+len(column1)-len(REGEX_COLORS.sub('', column1)), column2) + if __name__ == '__main__': print("This file is not meant to be called directly.") diff --git a/.bin/Scripts/functions/setup.py b/.bin/Scripts/functions/setup.py index 17cc37fa..749058e3 100644 --- a/.bin/Scripts/functions/setup.py +++ b/.bin/Scripts/functions/setup.py @@ -3,6 +3,7 @@ from functions.common import * from functions.update import * + # STATIC VARIABLES HKU = winreg.HKEY_USERS HKCR = winreg.HKEY_CLASSES_ROOT @@ -128,6 +129,7 @@ VCR_REDISTS = [ '/passive', '/norestart']}, ] + def config_classicstart(): """Configure ClassicStart.""" # User level, not system level @@ -180,14 +182,17 @@ def config_classicstart(): sleep(1) popen_program(cs_exe) + def config_explorer_system(): """Configure Windows Explorer for all users.""" write_registry_settings(SETTINGS_EXPLORER_SYSTEM, all_users=True) + def config_explorer_user(): """Configure Windows Explorer for current user.""" write_registry_settings(SETTINGS_EXPLORER_USER, all_users=False) + def disable_windows_telemetry(): """Disable Windows 10 telemetry settings with O&O ShutUp10.""" extract_item('ShutUp10', silent=True) @@ -197,6 +202,7 @@ def disable_windows_telemetry(): '/quiet'] run_program(cmd) + def update_clock(): """Set Timezone and sync clock.""" run_program(['tzutil' ,'/s', WINDOWS_TIME_ZONE], check=False) @@ -209,6 +215,7 @@ def update_clock(): run_program(['net', 'start', 'w32ime'], check=False) run_program(['w32tm', '/resync', '/nowait'], check=False) + def write_registry_settings(settings, all_users=False): """Write registry values from custom dict of dicts.""" hive = HKCU @@ -228,6 +235,7 @@ def write_registry_settings(settings, all_users=False): for name, value in v.get('SZ Items', {}).items(): winreg.SetValueEx(key, name, 0, winreg.REG_SZ, value) + # Installations def install_adobe_reader(): """Install Adobe Reader.""" @@ -240,10 +248,12 @@ def install_adobe_reader(): 'EULA_ACCEPT=YES'] run_program(cmd) + def install_chrome_extensions(): """Install Google Chrome extensions for all users.""" write_registry_settings(SETTINGS_GOOGLE_CHROME, all_users=True) + def install_classicstart_skin(): """Extract ClassicStart skin to installation folder.""" if global_vars['OS']['Version'] not in ('8', '8.1', '10'): @@ -257,6 +267,7 @@ def install_classicstart_skin(): os.makedirs(dest_path, exist_ok=True) shutil.copy(source, dest) + def install_firefox_extensions(): """Install Firefox extensions for all users.""" dist_path = r'{PROGRAMFILES}\Mozilla Firefox\distribution\extensions'.format( @@ -277,6 +288,7 @@ def install_firefox_extensions(): source_path] run_program(cmd) + def install_ninite_bundle(mse=False): """Run Ninite file(s) based on OS version.""" if global_vars['OS']['Version'] in ('8', '8.1', '10'): @@ -292,6 +304,7 @@ def install_ninite_bundle(mse=False): popen_program(r'{BaseDir}\Installers\Extras\Bundles\Legacy.exe'.format( **global_vars)) + def install_vcredists(): """Install all supported Visual C++ runtimes.""" extract_item('_vcredists', silent=True) @@ -307,16 +320,20 @@ def install_vcredists(): os.chdir(prev_dir) + # Misc def open_device_manager(): popen_program(['mmc', 'devmgmt.msc']) + def open_windows_activation(): popen_program(['slui']) + def open_windows_updates(): popen_program(['control', '/name', 'Microsoft.WindowsUpdate']) + if __name__ == '__main__': print("This file is not meant to be called directly.") diff --git a/.bin/Scripts/functions/sw_diags.py b/.bin/Scripts/functions/sw_diags.py index 317f2b4f..8faa25b7 100644 --- a/.bin/Scripts/functions/sw_diags.py +++ b/.bin/Scripts/functions/sw_diags.py @@ -4,6 +4,7 @@ import ctypes from functions.common import * + # STATIC VARIABLES AUTORUNS_SETTINGS = { r'Software\Sysinternals\AutoRuns': { @@ -26,6 +27,7 @@ AUTORUNS_SETTINGS = { }, } + def check_connection(): """Check if the system is online and optionally abort the script.""" while True: @@ -38,6 +40,7 @@ def check_connection(): else: abort() + def check_secure_boot_status(show_alert=False): """Checks UEFI Secure Boot status via PowerShell.""" boot_mode = get_boot_mode() @@ -77,6 +80,7 @@ def check_secure_boot_status(show_alert=False): show_alert_box('Secure Boot ERROR') raise GenericError + def get_boot_mode(): """Check if Windows is booted in UEFI or Legacy mode, returns str.""" kernel = ctypes.windll.kernel32 @@ -98,6 +102,7 @@ def get_boot_mode(): return type_str + def run_autoruns(): """Run AutoRuns in the background with VirusTotal checks enabled.""" extract_item('Autoruns', filter='autoruns*', silent=True) @@ -109,6 +114,7 @@ def run_autoruns(): winreg.SetValueEx(key, name, 0, winreg.REG_DWORD, value) popen_program(global_vars['Tools']['AutoRuns'], minimized=True) + def run_hwinfo_sensors(): """Run HWiNFO sensors.""" path = r'{BinDir}\HWiNFO'.format(**global_vars) @@ -122,12 +128,14 @@ def run_hwinfo_sensors(): f.write('SummaryOnly=0\n') popen_program(global_vars['Tools']['HWiNFO']) + def run_nircmd(*cmd): """Run custom NirCmd.""" extract_item('NirCmd', silent=True) cmd = [global_vars['Tools']['NirCmd'], *cmd] run_program(cmd, check=False) + def run_xmplay(): """Run XMPlay to test audio.""" extract_item('XMPlay', silent=True) @@ -141,6 +149,7 @@ def run_xmplay(): # Open XMPlay popen_program(cmd) + def run_hitmanpro(): """Run HitmanPro in the background.""" extract_item('HitmanPro', silent=True) @@ -150,6 +159,7 @@ def run_hitmanpro(): r'/log={LogDir}\Tools\HitmanPro.txt'.format(**global_vars)] popen_program(cmd) + def run_process_killer(): """Kill most running processes skipping those in the whitelist.txt.""" # borrowed from TronScript (reddit.com/r/TronScript) @@ -160,6 +170,7 @@ def run_process_killer(): run_program(['ProcessKiller.exe', '/silent'], check=False) os.chdir(prev_dir) + def run_rkill(): """Run RKill and cleanup afterwards.""" extract_item('RKill', silent=True) @@ -180,11 +191,13 @@ def run_rkill(): dest = non_clobber_rename(dest) shutil.move(item.path, dest) + def show_alert_box(message, title='Wizard Kit Warning'): """Show Windows alert box with message.""" message_box = ctypes.windll.user32.MessageBoxW message_box(None, message, title, 0x00001030) + if __name__ == '__main__': print("This file is not meant to be called directly.") diff --git a/.bin/Scripts/functions/tmux.py b/.bin/Scripts/functions/tmux.py index 84046d0b..a11560bc 100644 --- a/.bin/Scripts/functions/tmux.py +++ b/.bin/Scripts/functions/tmux.py @@ -2,12 +2,14 @@ from functions.common import * + def create_file(filepath): """Create file if it doesn't exist.""" if not os.path.exists(filepath): with open(filepath, 'w') as f: f.write('') + def tmux_get_pane_size(pane_id=None): """Get target, or current, pane size, returns tuple.""" x = -1 @@ -29,6 +31,7 @@ def tmux_get_pane_size(pane_id=None): return (x, y) + def tmux_kill_all_panes(pane_id=None): """Kill all tmux panes except the active pane or pane_id if specified.""" cmd = ['tmux', 'kill-pane', '-a'] @@ -36,12 +39,14 @@ def tmux_kill_all_panes(pane_id=None): cmd.extend(['-t', pane_id]) run_program(cmd, check=False) + def tmux_kill_pane(*panes): """Kill tmux pane by id.""" cmd = ['tmux', 'kill-pane', '-t'] for pane_id in panes: run_program(cmd+[pane_id], check=False) + def tmux_poll_pane(pane_id): """Check if pane exists, returns bool.""" cmd = ['tmux', 'list-panes', '-F', '#D'] @@ -49,6 +54,7 @@ def tmux_poll_pane(pane_id): panes = result.stdout.decode().splitlines() return pane_id in panes + def tmux_resize_pane(pane_id=None, x=None, y=None, **kwargs): """Resize pane to specific hieght or width.""" if not x and not y: @@ -65,6 +71,7 @@ def tmux_resize_pane(pane_id=None, x=None, y=None, **kwargs): run_program(cmd, check=False) + def tmux_split_window( lines=None, percent=None, behind=False, vertical=False, @@ -115,6 +122,7 @@ def tmux_split_window( result = run_program(cmd) return result.stdout.decode().strip() + def tmux_update_pane( pane_id, command=None, working_dir=None, text=None, watch=None, watch_cmd='cat'): @@ -142,6 +150,7 @@ def tmux_update_pane( run_program(cmd) + if __name__ == '__main__': print("This file is not meant to be called directly.") diff --git a/.bin/Scripts/functions/update.py b/.bin/Scripts/functions/update.py index 21d2acee..439bb6bf 100644 --- a/.bin/Scripts/functions/update.py +++ b/.bin/Scripts/functions/update.py @@ -8,6 +8,7 @@ from settings.launchers import * from settings.music import * from settings.sources import * + def compress_and_remove_item(item): """Compress and delete an item unless an error is encountered.""" try: @@ -17,6 +18,7 @@ def compress_and_remove_item(item): else: remove_item(item.path) + def compress_item(item): """Compress an item in a 7-Zip archive using the ARCHIVE_PASSWORD.""" # Prep @@ -42,6 +44,7 @@ def compress_item(item): # Done os.chdir(prev_dir) + def download_generic(out_dir, out_name, source_url): """Downloads a file using requests.""" ## Code based on this Q&A: https://stackoverflow.com/q/16694907 @@ -59,10 +62,12 @@ def download_generic(out_dir, out_name, source_url): except: raise GenericError('Failed to download file.') + def download_to_temp(out_name, source_url): """Download a file to the TmpDir.""" download_generic(global_vars['TmpDir'], out_name, source_url) + def extract_generic(source, dest, mode='x', sz_args=[]): """Extract a file to a destination.""" cmd = [ @@ -73,12 +78,14 @@ def extract_generic(source, dest, mode='x', sz_args=[]): cmd.extend(sz_args) run_program(cmd) + def extract_temp_to_bin(source, item, mode='x', sz_args=[]): """Extract a file to the .bin folder.""" source = r'{}\{}'.format(global_vars['TmpDir'], source) dest = r'{}\{}'.format(global_vars['BinDir'], item) extract_generic(source, dest, mode, sz_args) + def extract_temp_to_cbin(source, item, mode='x', sz_args=[]): """Extract a file to the .cbin folder.""" source = r'{}\{}'.format(global_vars['TmpDir'], source) @@ -88,6 +95,7 @@ def extract_temp_to_cbin(source, item, mode='x', sz_args=[]): shutil.copytree(include_path, dest) extract_generic(source, dest, mode, sz_args) + def generate_launcher(section, name, options): """Generate a launcher script.""" # Prep @@ -125,6 +133,7 @@ def generate_launcher(section, name, options): # f.writelines(out_text) f.write('\n'.join(out_text)) + def remove_item(item_path): """Delete a file or folder.""" if os.path.exists(item_path): @@ -133,6 +142,7 @@ def remove_item(item_path): else: os.remove(item_path) + def remove_from_kit(item): """Delete a file or folder from the .bin/.cbin folders.""" item_locations = [] @@ -144,11 +154,13 @@ def remove_from_kit(item): for item_path in item_locations: remove_item(item_path) + def remove_from_temp(item): """Delete a file or folder from the TmpDir folder.""" item_path = r'{}\{}'.format(global_vars['TmpDir'], item) remove_item(item_path) + def resolve_dynamic_url(source_url, regex): """Scan source_url for a url using the regex provided; returns str.""" # Load the download page @@ -170,6 +182,7 @@ def resolve_dynamic_url(source_url, regex): # Return return url + def scan_for_net_installers(server, family_name, min_year): """Scan network shares for installers.""" if not server['Mounted']: @@ -200,7 +213,8 @@ def scan_for_net_installers(server, family_name, min_year): } umount_network_share(server) -## Data Recovery ## + +# Data Recovery def update_testdisk(): # Stop running processes for exe in ['fidentify_win.exe', 'photorec_win.exe', @@ -226,7 +240,8 @@ def update_testdisk(): # Cleanup remove_from_temp('testdisk_wip.zip') -## Data Transfers ## + +# Data Transfers def update_fastcopy(): ## NOTE: Lives in .bin uncompressed # Stop running processes @@ -266,6 +281,7 @@ def update_fastcopy(): os.remove(r'{}\setup.exe'.format(_path, _installer)) remove_from_temp('FastCopy.zip') + def update_wimlib(): # Stop running processes kill_process('wimlib-imagex.exe') @@ -289,6 +305,7 @@ def update_wimlib(): remove_from_temp('wimlib32.zip') remove_from_temp('wimlib64.zip') + def update_xyplorer(): # Stop running processes kill_process('XYplorerFree.exe') @@ -305,7 +322,8 @@ def update_xyplorer(): # Cleanup remove_from_temp('xyplorer_free.zip') -## Diagnostics ## + +# Diagnostics def update_aida64(): # Stop running processes kill_process('notepadplusplus.exe') @@ -322,6 +340,7 @@ def update_aida64(): # Cleanup remove_from_temp('aida64.zip') + def update_autoruns(): # Stop running processes kill_process('Autoruns.exe') @@ -339,6 +358,7 @@ def update_autoruns(): # Cleanup remove_from_temp('Autoruns.zip') + def update_bleachbit(): # Stop running processes kill_process('bleachbit.exe') @@ -370,6 +390,7 @@ def update_bleachbit(): remove_from_temp('bleachbit.zip') remove_from_temp('Winapp2.zip') + def update_bluescreenview(): # Stop running processes for exe in ['BlueScreenView.exe', 'BlueScreenView64.exe']: @@ -394,6 +415,7 @@ def update_bluescreenview(): remove_from_temp('bluescreenview32.zip') remove_from_temp('bluescreenview64.zip') + def update_erunt(): # Stop running processes kill_process('ERUNT.EXE') @@ -410,6 +432,7 @@ def update_erunt(): # Cleanup remove_from_temp('erunt.zip') + def update_hitmanpro(): # Stop running processes for exe in ['HitmanPro.exe', 'HitmanPro64.exe']: @@ -423,6 +446,7 @@ def update_hitmanpro(): download_generic(dest, 'HitmanPro.exe', SOURCE_URLS['HitmanPro32']) download_generic(dest, 'HitmanPro64.exe', SOURCE_URLS['HitmanPro64']) + def update_hwinfo(): ## NOTE: Lives in .bin uncompressed # Stop running processes @@ -438,6 +462,7 @@ def update_hwinfo(): # Cleanup remove_from_temp('HWiNFO.zip') + def update_nircmd(): # Stop running processes for exe in ['nircmdc.exe', 'nircmdc64.exe']: @@ -461,6 +486,7 @@ def update_nircmd(): remove_from_temp('nircmd32.zip') remove_from_temp('nircmd64.zip') + def update_produkey(): # Stop running processes for exe in ['ProduKey.exe', 'ProduKey64.exe']: @@ -484,7 +510,8 @@ def update_produkey(): remove_from_temp('produkey32.zip') remove_from_temp('produkey64.zip') -## Drivers ## + +# Drivers def update_intel_rst(): # Remove existing folders remove_from_kit('Intel RST') @@ -500,6 +527,7 @@ def update_intel_rst(): for name, url in RST_SOURCES.items(): download_generic(dest, name, url) + def update_intel_ssd_toolbox(): # Remove existing folders remove_from_kit('Intel SSD Toolbox.exe') @@ -510,6 +538,7 @@ def update_intel_ssd_toolbox(): 'Intel SSD Toolbox.exe', SOURCE_URLS['Intel SSD Toolbox']) + def update_samsung_magician(): # Remove existing folders remove_from_kit('Samsung Magician.exe') @@ -528,6 +557,7 @@ def update_samsung_magician(): # Cleanup remove_from_temp('Samsung Magician.zip') + def update_sdi_origin(): # Download aria2 download_to_temp('aria2.zip', SOURCE_URLS['aria2']) @@ -585,7 +615,8 @@ def update_sdi_origin(): remove_from_temp('sdio.torrent') remove_from_temp('sdio_themes.zip') -## Installers ## + +# Installers def update_adobe_reader_dc(): # Prep dest = r'{}\Installers\Extras\Office'.format( @@ -601,6 +632,7 @@ def update_adobe_reader_dc(): download_generic( dest, 'Adobe Reader DC.exe', SOURCE_URLS['Adobe Reader DC']) + def update_macs_fan_control(): # Prep dest = r'{}\Installers'.format( @@ -616,6 +648,7 @@ def update_macs_fan_control(): download_generic( dest, 'Macs Fan Control.exe', SOURCE_URLS['Macs Fan Control']) + def update_office(): # Remove existing folders remove_from_kit('_Office') @@ -644,6 +677,7 @@ def update_office(): # Cleanup remove_from_temp('odt{}.exe'.format(year)) + def update_classic_start_skin(): # Remove existing folders remove_from_kit('ClassicStartSkin') @@ -654,6 +688,7 @@ def update_classic_start_skin(): 'Metro-Win10-Black.skin7', SOURCE_URLS['ClassicStartSkin']) + def update_vcredists(): # Remove existing folders remove_from_kit('_vcredists') @@ -674,6 +709,7 @@ def update_vcredists(): 'vcredist.exe', VCREDIST_SOURCES[year][bit]) + def update_one_ninite(section, dest, name, url, indent=8, width=40): # Prep url = 'https://ninite.com/{}/ninite.exe'.format(url) @@ -690,6 +726,7 @@ def update_one_ninite(section, dest, name, url, indent=8, width=40): remove_item(installer_dest) shutil.copy(r'{}\{}'.format(dest, name), installer_dest) + def update_all_ninite(indent=8, width=40, other_results={}): print_info('{}Ninite'.format(' '*int(indent/2))) for section in sorted(NINITE_SOURCES.keys()): @@ -700,7 +737,8 @@ def update_all_ninite(indent=8, width=40, other_results={}): other_results=other_results, indent=indent, width=width, section=section, dest=dest, name=name, url=url) -## Misc ## + +# Misc def update_caffeine(): # Stop running processes kill_process('caffeine.exe') @@ -717,6 +755,7 @@ def update_caffeine(): # Cleanup remove_from_temp('caffeine.zip') + def update_du(): # Stop running processes kill_process('du.exe') @@ -734,6 +773,7 @@ def update_du(): # Cleanup remove_from_temp('du.zip') + def update_everything(): # Stop running processes for exe in ['Everything.exe', 'Everything64.exe']: @@ -758,6 +798,7 @@ def update_everything(): remove_from_temp('everything32.zip') remove_from_temp('everything64.zip') + def update_firefox_ublock_origin(): # Remove existing folders remove_from_kit('FirefoxExtensions') @@ -768,6 +809,7 @@ def update_firefox_ublock_origin(): 'ublock_origin.xpi', SOURCE_URLS['Firefox uBO']) + def update_notepadplusplus(): # Stop running processes kill_process('notepadplusplus.exe') @@ -788,6 +830,7 @@ def update_notepadplusplus(): # Cleanup remove_from_temp('npp.7z') + def update_putty(): # Stop running processes kill_process('PUTTY.EXE') @@ -804,6 +847,7 @@ def update_putty(): # Cleanup remove_from_temp('putty.zip') + def update_wiztree(): # Stop running processes for process in ['WizTree.exe', 'WizTree64.exe']: @@ -822,6 +866,7 @@ def update_wiztree(): # Cleanup remove_from_temp('wiztree.zip') + def update_xmplay(): # Stop running processes kill_process('xmplay.exe') @@ -877,7 +922,8 @@ def update_xmplay(): remove_from_temp('xmp-rar.zip') remove_from_temp('WAModern.zip') -## Repairs ## + +# Repairs def update_adwcleaner(): # Stop running processes kill_process('AdwCleaner.exe') @@ -891,6 +937,7 @@ def update_adwcleaner(): 'AdwCleaner.exe', SOURCE_URLS['AdwCleaner']) + def update_kvrt(): # Stop running processes kill_process('KVRT.exe') @@ -904,6 +951,7 @@ def update_kvrt(): 'KVRT.exe', SOURCE_URLS['KVRT']) + def update_rkill(): # Stop running processes kill_process('RKill.exe') @@ -918,6 +966,7 @@ def update_rkill(): download_generic( r'{}\RKill'.format(global_vars['CBinDir']), 'RKill.exe', url) + def update_tdsskiller(): # Stop running processes kill_process('TDSSKiller.exe') @@ -931,7 +980,8 @@ def update_tdsskiller(): 'TDSSKiller.exe', SOURCE_URLS['TDSSKiller']) -## Uninstallers ## + +# Uninstallers def update_iobit_uninstaller(): # Stop running processes kill_process('IObitUninstallerPortable.exe') @@ -954,6 +1004,7 @@ def update_iobit_uninstaller(): # Cleanup remove_from_kit('IObitUninstallerPortable.exe') + if __name__ == '__main__': print("This file is not meant to be called directly.") diff --git a/.bin/Scripts/functions/windows_setup.py b/.bin/Scripts/functions/windows_setup.py index d23dce4c..82120843 100644 --- a/.bin/Scripts/functions/windows_setup.py +++ b/.bin/Scripts/functions/windows_setup.py @@ -3,6 +3,7 @@ from functions.data import * from functions.disk import * + # STATIC VARIABLES WINDOWS_VERSIONS = [ {'Name': 'Windows 7 Home Basic', @@ -35,6 +36,7 @@ WINDOWS_VERSIONS = [ 'Image Name': 'Windows 10 Pro'}, ] + def find_windows_image(windows_version): """Search for a Windows source image file, returns dict. @@ -85,6 +87,7 @@ def find_windows_image(windows_version): windows_version['Name'])) raise GenericAbort + def format_disk(disk, use_gpt): """Format disk for use as a Windows OS disk.""" if use_gpt: @@ -92,6 +95,7 @@ def format_disk(disk, use_gpt): else: format_mbr(disk) + def format_gpt(disk): """Format disk for use as a Windows OS disk using the GPT layout.""" script = [ @@ -126,6 +130,7 @@ def format_gpt(disk): # Run run_diskpart(script) + def format_mbr(disk): """Format disk for use as a Windows OS disk using the MBR layout.""" script = [ @@ -155,6 +160,7 @@ def format_mbr(disk): # Run run_diskpart(script) + def mount_windows_share(): """Mount the Windows images share unless already mounted.""" if not WINDOWS_SERVER['Mounted']: @@ -163,6 +169,7 @@ def mount_windows_share(): # error by trying to mount the same server with multiple credentials. mount_network_share(WINDOWS_SERVER, read_write=True) + def select_windows_version(): """Select Windows version from a menu, returns dict.""" actions = [ @@ -180,6 +187,7 @@ def select_windows_version(): elif selection == 'M': raise GenericAbort + def setup_windows(windows_image, windows_version): """Apply a Windows image to W:""" cmd = [ @@ -192,6 +200,7 @@ def setup_windows(windows_image, windows_version): cmd.extend(windows_image['Glob']) run_program(cmd) + def setup_windows_re(windows_version, windows_letter='W', tools_letter='T'): """Setup the WinRE partition.""" win = r'{}:\Windows'.format(windows_letter) @@ -210,6 +219,7 @@ def setup_windows_re(windows_version, windows_letter='W', tools_letter='T'): '/target', win] run_program(cmd) + def update_boot_partition(system_letter='S', windows_letter='W', mode='ALL'): """Setup the Windows boot partition.""" cmd = [ @@ -220,6 +230,7 @@ def update_boot_partition(system_letter='S', windows_letter='W', mode='ALL'): '/f', mode] run_program(cmd) + def wim_contains_image(filename, imagename): """Check if an ESD/WIM contains the specified image, returns bool.""" cmd = [ @@ -234,6 +245,7 @@ def wim_contains_image(filename, imagename): return True + if __name__ == '__main__': print("This file is not meant to be called directly.") diff --git a/.bin/Scripts/functions/winpe_menus.py b/.bin/Scripts/functions/winpe_menus.py index f42a6144..22df7449 100644 --- a/.bin/Scripts/functions/winpe_menus.py +++ b/.bin/Scripts/functions/winpe_menus.py @@ -4,6 +4,7 @@ from functions.backup import * from functions.disk import * from functions.windows_setup import * + # STATIC VARIABLES FAST_COPY_PE_ARGS = [ '/cmd=noexist_only', @@ -50,6 +51,7 @@ PE_TOOLS = { }, } + def check_pe_tools(): """Fix tool paths for WinPE layout.""" for k in PE_TOOLS.keys(): @@ -61,6 +63,7 @@ def check_pe_tools(): global_vars['Tools']['wimlib-imagex'], re.IGNORECASE) + def menu_backup(): """Take backup images of partition(s) in the WIM format.""" errors = False @@ -211,6 +214,7 @@ def menu_backup(): sleep(30) pause('\nPress Enter to return to main menu... ') + def menu_root(): """Main WinPE menu.""" check_pe_tools() @@ -249,6 +253,7 @@ def menu_root(): else: sys.exit() + def menu_setup(): """Format a disk, apply a Windows image, and create boot files.""" errors = False @@ -409,6 +414,7 @@ def menu_setup(): sleep(30) pause('\nPress Enter to return to main menu... ') + def menu_tools(): """Tool launcher menu.""" tools = [{'Name': k} for k in sorted(PE_TOOLS.keys())] @@ -438,6 +444,7 @@ def menu_tools(): elif (selection == 'M'): break + def select_minidump_path(): """Select BSOD minidump path from a menu.""" dumps = [] @@ -467,6 +474,7 @@ def select_minidump_path(): main_entries = dumps) return dumps[int(selection) - 1]['Name'] + if __name__ == '__main__': print("This file is not meant to be called directly.") diff --git a/.bin/Scripts/hw-diags-network b/.bin/Scripts/hw-diags-network index 7e0b0bed..3caa7adb 100755 --- a/.bin/Scripts/hw-diags-network +++ b/.bin/Scripts/hw-diags-network @@ -10,11 +10,13 @@ os.chdir(os.path.dirname(os.path.realpath(__file__))) sys.path.append(os.getcwd()) from functions.network import * + def check_connection(): if not is_connected(): # Raise to cause NS in try_and_print() raise Exception + if __name__ == '__main__': try: # Prep diff --git a/.bin/Scripts/msword-search b/.bin/Scripts/msword-search index 380c6ed5..19bbe688 100755 --- a/.bin/Scripts/msword-search +++ b/.bin/Scripts/msword-search @@ -22,6 +22,7 @@ init_global_vars() REGEX_DOC_FILES = re.compile(r'\.docx?$', re.IGNORECASE) + def scan_for_docs(path): for entry in os.scandir(path): if entry.is_dir(follow_symlinks=False): @@ -29,6 +30,7 @@ def scan_for_docs(path): elif entry.is_file and REGEX_DOC_FILES.search(entry.name): yield entry + def scan_file(file_path, search): match = False try: @@ -45,6 +47,7 @@ def scan_file(file_path, search): return entry.path if match else None + if __name__ == '__main__': try: # Prep