diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..ca218ad5 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +Scripts/__pycache__ diff --git a/LICENSE.txt b/LICENSE.txt index 3d52e4c5..8e17b045 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -1,4 +1,4 @@ -Copyright (c) 2016 Alan Mason +Copyright (c) 2017 Alan Mason Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: diff --git a/Scripts/functions.py b/Scripts/functions.py index 3f69b408..e647747e 100644 --- a/Scripts/functions.py +++ b/Scripts/functions.py @@ -1,10 +1,17 @@ # WK WinPE Functions +# Init import os import re import shutil import subprocess +import sys import time +import winreg +os.chdir(os.path.dirname(os.path.realpath(__file__))) +bin = os.path.abspath('..\\') +sys.path.append(os.getcwd()) +from functions import * import partition_uids # Init @@ -32,6 +39,44 @@ WINDOWS_SERVER = { 'User': 'backup', # Using these credentials in case both the windows source and backup shares are mounted. 'Pass': 'Abracadabra', # This is because Windows only allows one set of credentials to be used per server at a time. } +WINDOWS_VERSIONS = [ + {'Name': 'Windows 7 Home Basic', + 'Image File': 'Win7', + 'Image Name': 'Windows 7 HOMEBASIC', + 'Family': '7'}, + {'Name': 'Windows 7 Home Premium', + 'Image File': 'Win7', + 'Image Name': 'Windows 7 HOMEPREMIUM', + 'Family': '7'}, + {'Name': 'Windows 7 Professional', + 'Image File': 'Win7', + 'Image Name': 'Windows 7 PROFESSIONAL', + 'Family': '7'}, + {'Name': 'Windows 7 Ultimate', + 'Image File': 'Win7', + 'Image Name': 'Windows 7 ULTIMATE', + 'Family': '7'}, + + {'Name': 'Windows 8.1', + 'Image File': 'Win8', + 'Image Name': 'Windows 8.1', + 'Family': '8', + 'CRLF': True}, + {'Name': 'Windows 8.1 Pro', + 'Image File': 'Win8', + 'Image Name': 'Windows 8.1 Pro', + 'Family': '8'}, + + {'Name': 'Windows 10 Home', + 'Image File': 'Win10', + 'Image Name': 'Windows 10 Home', + 'Family': '10', + 'CRLF': True}, + {'Name': 'Windows 10 Pro', + 'Image File': 'Win10', + 'Image Name': 'Windows 10 Pro', + 'Family': '10'}, +] diskpart_script = '{tmp}\\diskpart.script'.format(tmp=os.environ['TMP']) ## Colors @@ -42,6 +87,20 @@ COLORS = { 'YELLOW': '\033[33m', 'BLUE': '\033[34m'} +class AbortException(Exception): + pass + +class BackupException(Exception): + pass + +class SetupException(Exception): + pass + +def abort_to_main_menu(message='Returning to main menu...'): + print_warning(message) + pause('Press Enter to return to main menu... ') + raise AbortException + def ask(prompt='Kotaero'): answer = None prompt = prompt + ' [Y/N]: ' @@ -53,6 +112,41 @@ def ask(prompt='Kotaero'): answer = False return answer +def assign_volume_letters(): + try: + # Run script + with open(diskpart_script, 'w') as script: + for vol in get_volume_numbers(): + script.write('select volume {number}\n'.format(number=vol)) + script.write('assign\n') + run_program('diskpart /s {script}'.format(script=diskpart_script)) + except subprocess.CalledProcessError: + pass + +def backup_partition(bin=None, par=None): + # Bail early + if bin is None: + raise Exception('bin path not specified.') + if par is None: + raise Exception('Partition not specified.') + + print(' Partition {Number} Backup...\t\t'.format(**par), end='', flush=True) + if par['Number'] in disk['Bad Partitions']: + print_warning('Skipped.') + else: + cmd = '{bin}\\wimlib\\wimlib-imagex capture {Letter}:\\ "{Image Path}\\{Image File}" "{Image Name}" "{Image Name}" --compress=fast'.format(bin=bin, **par) + if par['Image Exists']: + print_warning('Skipped.') + else: + try: + os.makedirs('{Image Path}'.format(**par), exist_ok=True) + run_program(cmd) + print_success('Complete.') + except subprocess.CalledProcessError as err: + print_error('Failed.') + par['Error'] = err.stderr.decode().splitlines() + raise BackupException + def convert_to_bytes(size): size = str(size) tmp = re.search(r'(\d+)\s+([KMGT]B)', size.upper()) @@ -72,6 +166,402 @@ def convert_to_bytes(size): return size +def is_valid_image(bin=None, filename=None, imagename=None): + # Bail early + if bin is None: + raise Exception('bin not specified.') + if filename is None: + raise Exception('Filename not specified.') + if imagename is None: + raise Exception('Image Name not specified.') + + cmd = '{bin}\\wimlib\\wimlib-imagex info "{filename}" "{imagename}"'.format(bin=bin, filename=filename, imagename=imagename) + try: + run_program(cmd) + except subprocess.CalledProcessError: + print_error('Invalid image: {filename}'.format(filename=filename)) + return False + + return True + +def find_windows_image(bin, windows_version=None): + """Search for a Windows source image file on local drives and network drives (in that order)""" + image = {} + + # Bail early + if windows_version is None: + raise Exception('Windows version not specified.') + imagefile = windows_version['Image File'] + + # Search local source + process_return = run_program('mountvol') + for tmp in re.findall(r'.*([A-Za-z]):\\', process_return.stdout.decode()): + for ext in ['esd', 'wim', 'swm']: + filename = '{drive}:\\images\\{imagefile}'.format(drive=tmp[0], imagefile=imagefile) + filename_ext = '{filename}.{ext}'.format(filename=filename, ext=ext) + if os.path.isfile(filename_ext): + if is_valid_image(bin, filename_ext, windows_version['Image Name']): + image['Ext'] = ext + image['File'] = filename + image['Glob'] = '--ref="{File}*.swm"'.format(**image) if ext == 'swm' else '' + image['Source'] = tmp[0] + break + + # Check for network source (if necessary) + if not any(image): + if not WINDOWS_SERVER['Mounted']: + mount_windows_share() + for ext in ['esd', 'wim', 'swm']: + filename = '\\\\{IP}\\{Share}\\images\\{imagefile}'.format(imagefile=imagefile, **WINDOWS_SERVER) + filename_ext = '{filename}.{ext}'.format(filename=filename, ext=ext) + if os.path.isfile(filename_ext): + if is_valid_image(bin, filename_ext, windows_version['Image Name']): + image['Ext'] = ext + image['File'] = filename + image['Glob'] = '--ref="{File}*.swm"'.format(**image) if ext == 'swm' else '' + image['Source'] = None + break + + # Display image to be used (if any) and return + if any(image): + print_info('Using image: {File}.{Ext}'.format(**image)) + return image + else: + print_error('Failed to find Windows source image for {winver}'.format(winver=windows_version['Name'])) + abort_to_main_menu('Aborting Windows setup') + +def format_gpt(disk=None, windows_family=None): + """Format disk for use as a Windows OS drive using the GPT (UEFI) layout.""" + + # Bail early + if disk is None: + raise Exception('No disk provided.') + if windows_family is None: + raise Exception('No Windows family provided.') + + # Format drive + print_info('Drive will use a GPT (UEFI) layout.') + with open(diskpart_script, 'w') as script: + # Partition table + script.write('select disk {number}\n'.format(number=disk['Number'])) + script.write('clean\n') + script.write('convert gpt\n') + + # System partition + script.write('create partition efi size=260\n') # NOTE: Allows for Advanced Format 4K drives + script.write('format quick fs=fat32 label="System"\n') + script.write('assign letter="S"\n') + + # Microsoft Reserved (MSR) partition + script.write('create partition msr size=128\n') + + # Windows partition + script.write('create partition primary\n') + script.write('format quick fs=ntfs label="Windows"\n') + script.write('assign letter="W"\n') + + # Recovery Tools partition (Windows 8+) + if re.search(r'^(8|10)', windows_family): + script.write('shrink minimum=500\n') + script.write('create partition primary\n') + script.write('format quick fs=ntfs label="Recovery Tools"\n') + script.write('assign letter="T"\n') + script.write('set id="de94bba4-06d1-4d40-a16a-bfd50179d6ac"\n') + script.write('gpt attributes=0x8000000000000001\n') + + # Run script + print(' Formatting drive...') + run_program('diskpart /s {script}'.format(script=diskpart_script)) + time.sleep(2) + +def format_mbr(disk=None, windows_family=None): + """Format disk for use as a Windows OS drive using the MBR (legacy) layout.""" + + # Bail early + if disk is None: + raise Exception('No disk provided.') + if windows_family is None: + raise Exception('No Windows family provided.') + + # Format drive + print_info('Drive will use a MBR (legacy) layout.') + with open(diskpart_script, 'w') as script: + # Partition table + script.write('select disk {number}\n'.format(number=disk['Number'])) + script.write('clean\n') + + # System partition + script.write('create partition primary size=100\n') + script.write('format fs=ntfs quick label="System Reserved"\n') + script.write('active\n') + script.write('assign letter="S"\n') + + # Windows partition + script.write('create partition primary\n') + script.write('format fs=ntfs quick label="Windows"\n') + script.write('assign letter="W"\n') + + # Recovery Tools partition (Windows 8+) + if re.search(r'^(8|10)', windows_family): + script.write('shrink minimum=500\n') + script.write('create partition primary\n') + script.write('format quick fs=ntfs label="Recovery"\n') + script.write('assign letter="T"\n') + script.write('set id=27\n') + + # Run script + print(' Formatting drive...') + run_program('diskpart /s {script}'.format(script=diskpart_script)) + time.sleep(2) + +def get_attached_disk_info(): + """Get details about the attached disks""" + disks = [] + print_info('Getting drive info...') + + # Assign all the letters + assign_volume_letters() + + # Get disks + disks = get_disks() + + # Get disk details + for disk in disks: + # Get partition style + disk['Table'] = get_table_type(disk) + + # Get disk name/model and physical details + disk.update(get_disk_details(disk)) + + # Get partition info for disk + disk['Partitions'] = get_partitions(disk) + + for par in disk['Partitions']: + # Get partition details + par.update(get_partition_details(disk, par)) + + # Done + return disks + +def get_boot_mode(): + boot_mode = 'Legacy' + try: + reg_key = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, 'System\\CurrentControlSet\\Control') + reg_value = winreg.QueryValueEx(reg_key, 'PEFirmwareType')[0] + if reg_value == 2: + boot_mode = 'UEFI' + except: + boot_mode = 'Unknown' + + return boot_mode + +def get_disk_details(disk=None): + details = {} + + # Bail early + if disk is None: + raise Exception('Disk not specified.') + + try: + # Run script + with open(diskpart_script, 'w') as script: + script.write('select disk {Number}\n'.format(**disk)) + script.write('detail disk\n') + process_return = run_program('diskpart /s {script}'.format(script=diskpart_script)) + process_return = process_return.stdout.decode().strip() + except subprocess.CalledProcessError: + pass + else: + # Remove empty lines + tmp = [s.strip() for s in process_return.splitlines() if s.strip() != ''] + + # Set disk name + details['Name'] = tmp[4] + + # Remove lines without a ':' and split each remaining line at the ':' to form a key/value pair + tmp = [s.split(':') for s in tmp if ':' in s] + + # Add key/value pairs to the details variable and return dict + details.update({key.strip(): value.strip() for (key, value) in tmp}) + + return details + +def get_disks(): + disks = [] + + try: + # Run script + with open(diskpart_script, 'w') as script: + script.write('list disk\n') + process_return = run_program('diskpart /s {script}'.format(script=diskpart_script)) + process_return = process_return.stdout.decode().strip() + except subprocess.CalledProcessError: + pass + else: + # Append disk numbers + for tmp in re.findall(r'Disk (\d+)\s+\w+\s+(\d+\s+\w+)', process_return): + _num = tmp[0] + _size = human_readable_size(tmp[1]) + disks.append({'Number': _num, 'Size': _size}) + + return disks + +def get_partition_details(disk=None, par=None): + details = {} + + # Bail early + if disk is None: + raise Exception('Disk not specified.') + if par is None: + raise Exception('Partition not specified.') + + # Diskpart details + try: + # Run script + with open(diskpart_script, 'w') as script: + script.write('select disk {Number}\n'.format(**disk)) + script.write('select partition {Number}\n'.format(**par)) + script.write('detail partition\n') + process_return = run_program('diskpart /s {script}'.format(script=diskpart_script)) + process_return = process_return.stdout.decode().strip() + except subprocess.CalledProcessError: + pass + else: + # Get volume letter or RAW status + tmp = re.search(r'Volume\s+\d+\s+(\w|RAW)\s+', process_return) + if tmp: + if tmp.group(1) == 'RAW': + details['FileSystem'] = RAW + else: + details['Letter'] = tmp.group(1) + + # Remove empty lines from process_return + tmp = [s.strip() for s in process_return.splitlines() if s.strip() != ''] + + # Remove lines without a ':' and split each remaining line at the ':' to form a key/value pair + tmp = [s.split(':') for s in tmp if ':' in s] + + # Add key/value pairs to the details variable and return dict + details.update({key.strip(): value.strip() for (key, value) in tmp}) + + # Get MBR type / GPT GUID for extra details on "Unknown" partitions + guid = partition_uids.lookup_guid(details['Type']) + if guid is not None: + details.update({ + 'Description': guid.get('Description', ''), + 'OS': guid.get('OS', '')}) + + if 'Letter' in details: + # Disk usage + tmp = shutil.disk_usage('{Letter}:\\'.format(**details)) + details['Used Space'] = human_readable_size(tmp.used) + + # fsutil details + try: + process_return = run_program('fsutil fsinfo volumeinfo {Letter}:'.format(**details)) + process_return = process_return.stdout.decode().strip() + except subprocess.CalledProcessError: + pass + else: + # Remove empty lines from process_return + tmp = [s.strip() for s in process_return.splitlines() if s.strip() != ''] + + # Add "Feature" lines + details['File System Features'] = [s.strip() for s in tmp if ':' not in s] + + # Remove lines without a ':' and split each remaining line at the ':' to form a key/value pair + tmp = [s.split(':') for s in tmp if ':' in s] + + # Add key/value pairs to the details variable and return dict + details.update({key.strip(): value.strip() for (key, value) in tmp}) + + # Set Volume Name + details['Name'] = details.get('Volume Name', '') + + # Set FileSystem Type + if details.get('FileSystem', '') != 'RAW': + details['FileSystem'] = details.get('File System Name', 'Unknown') + + return details + +def get_partitions(disk=None): + partitions = [] + + # Bail early + if disk is None: + raise Exception('Disk not specified.') + + try: + # Run script + with open(diskpart_script, 'w') as script: + script.write('select disk {Number}\n'.format(**disk)) + script.write('list partition\n') + process_return = run_program('diskpart /s {script}'.format(script=diskpart_script)) + process_return = process_return.stdout.decode().strip() + except subprocess.CalledProcessError: + pass + else: + # Append partition numbers + for tmp in re.findall(r'Partition\s+(\d+)\s+\w+\s+(\d+\s+\w+)\s+', process_return): + _num = tmp[0] + _size = human_readable_size(tmp[1]) + partitions.append({'Number': _num, 'Size': _size}) + + return partitions + +def get_table_type(disk=None): + _type = 'Unknown' + + # Bail early + if disk is None: + raise Exception('Disk not specified.') + + try: + with open(diskpart_script, 'w') as script: + script.write('select disk {Number}\n'.format(**disk)) + script.write('uniqueid disk\n') + process_return = run_program('diskpart /s {script}'.format(script=diskpart_script)) + process_return = process_return.stdout.decode().strip() + except subprocess.CalledProcessError: + pass + else: + if re.findall(r'Disk ID: {[A-Z0-9]+-[A-Z0-9]+-[A-Z0-9]+-[A-Z0-9]+-[A-Z0-9]+}', process_return): + _type = 'GPT' + elif re.findall(r'Disk ID: 00000000', process_return): + _type = 'RAW' + elif re.findall(r'Disk ID: [A-Z0-9]+', process_return): + _type = 'MBR' + + return _type + +def get_ticket_id(): + ticket_id = None + while ticket_id is None: + tmp = input('Enter ticket number: ') + if re.match(r'^([0-9]+([\-_]*\w+|))$', tmp): + ticket_id = tmp + + return ticket_id + +def get_volume_numbers(): + vol_nums = [] + + try: + # Run script + with open(diskpart_script, 'w') as script: + script.write('list volume\n') + process_return = run_program('diskpart /s {script}'.format(script=diskpart_script)) + process_return = process_return.stdout.decode().strip() + except subprocess.CalledProcessError: + pass + else: + # Append volume numbers + for tmp in re.findall(r'Volume (\d+)\s+([A-Za-z]?)\s+', process_return): + if tmp[1] == '': + vol_nums.append(tmp[0]) + + return vol_nums + def human_readable_size(size, decimals=0): # Prep string formatting width = 3+decimals @@ -109,417 +599,48 @@ def human_readable_size(size, decimals=0): # Return return tmp -def pause(prompt='Press Enter to continue... '): - input(prompt) - -def print_error(message='Generic error', **kwargs): - print('{RED}{message}{CLEAR}'.format(message=message, **COLORS, **kwargs)) - -def print_info(message='Generic info', **kwargs): - print('{BLUE}{message}{CLEAR}'.format(message=message, **COLORS, **kwargs)) - -def print_warning(message='Generic warning', **kwargs): - print('{YELLOW}{message}{CLEAR}'.format(message=message, **COLORS, **kwargs)) - -def print_success(message='Generic success', **kwargs): - print('{GREEN}{message}{CLEAR}'.format(message=message, **COLORS, **kwargs)) - -def run_program(cmd=None, args=[], check=True): - if cmd is None: - raise Exception('No program passed.') - - if len(args) > 0: - args = [cmd] + args - process_return = subprocess.run(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE, check=check) - else: - process_return = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, check=check) - - return process_return - -def assign_volume_letters(): - with open(diskpart_script, 'w') as script: - script.write('list volume\n') - process_return = run_program('diskpart /s {script}'.format(script=diskpart_script)) - with open(diskpart_script, 'w') as script: - for tmp in re.findall(r'Volume (\d+)\s+([A-Za-z]?)\s+', process_return.stdout.decode()): - if tmp[1] == '': - script.write('select volume {number}\n'.format(number=tmp[0])) - script.write('assign\n') - try: - run_program('diskpart /s {script}'.format(script=diskpart_script)) - except: - pass - -def remove_volume_letters(keep=None): - with open(diskpart_script, 'w') as script: - script.write('list volume\n') - process_return = run_program('diskpart /s {script}'.format(script=diskpart_script)) - with open(diskpart_script, 'w') as script: - for tmp in re.findall(r'Volume (\d+)\s+([A-Za-z]?)\s+', process_return.stdout.decode()): - if tmp[1] != '' and tmp[1] != keep: - script.write('select volume {number}\n'.format(number=tmp[0])) - script.write('remove\n') - try: - run_program('diskpart /s {script}'.format(script=diskpart_script)) - except: - pass - -def select_minidump_path(): - dumps = [] - - # Assign volume letters first - assign_volume_letters() - - # Search for minidumps - tmp = run_program('mountvol') - tmp = [d for d in re.findall(r'.*([A-Za-z]):\\', tmp.stdout.decode())] - # Remove RAMDisk letter - if 'X' in tmp: - tmp.remove('X') - for drive in tmp: - if os.path.exists('{drive}:\\Windows\\MiniDump'.format(drive=drive)): - dumps.append({'Name': '{drive}:\\Windows\\MiniDump'.format(drive=drive)}) - - # Check results before showing menu - if len(dumps) == 0: - print_error(' No BSoD / MiniDump paths found') - time.sleep(2) - return None - - # Menu - selection = menu_select('Which BSoD / MiniDump path are we scanning?', dumps, []) - return dumps[int(selection) - 1]['Name'] - -def find_windows_image(filename=None): - """Search for a Windows source image file on local drives and network drives (in that order)""" - image = {} +def menu_select(title='~ Untitled Menu ~', main_entries=[], action_entries=[], prompt='Please make a selection', secret_exit=False): + """Display options in a menu for user selection""" # Bail early - if filename is None: - raise Exception('Filename not specified.') - - # Search local source - process_return = run_program('mountvol') - for tmp in re.findall(r'.*([A-Za-z]):\\', process_return.stdout.decode()): - for ext in ['esd', 'wim', 'swm']: - if os.path.isfile('{drive}:\\images\\{filename}.{ext}'.format(drive=tmp[0], ext=ext, filename=filename)): - image['Ext'] = ext - image['File'] = '{drive}:\\images\\{filename}'.format(drive=tmp[0], filename=filename) - image['Glob'] = '--ref="{File}*.swm"'.format(**image) if ext == 'swm' else '' - image['Source'] = tmp[0] - break - - # Check for network source (if necessary) - if not any(image): - if not WINDOWS_SERVER['Mounted']: - mount_windows_share() - for ext in ['esd', 'wim', 'swm']: - if os.path.isfile('\\\\{IP}\\{Share}\\images\\{filename}.{ext}'.format(ext=ext, filename=filename, **WINDOWS_SERVER)): - image['Ext'] = ext - image['File'] = '\\\\{IP}\\{Share}\\images\\{filename}'.format(filename=filename, **WINDOWS_SERVER) - image['Glob'] = '--ref="{File}*.swm"'.format(**image) if ext == 'swm' else '' - image['Source'] = None - break - - # Display image to be used (if any) and return - if any(image): - print_info('Using image: {File}.{Ext}'.format(**image)) - return image - else: - return None - -def format_gpt(disk=None, windows_family=None): - """Format disk for use as a Windows OS drive using the GPT (UEFI) layout.""" - - # Bail early - if disk is None: - raise Exception('No disk provided.') - if windows_family is None: - raise Exception('No Windows family provided.') - - # Format drive - print_info('Drive will use a GPT (UEFI) layout.') - with open(diskpart_script, 'w') as script: - # Partition table - script.write('select disk {number}\n'.format(number=disk['Number'])) - script.write('clean\n') - script.write('convert gpt\n') - - # Windows RE tools partitions (Windows 8+) - if re.search(r'^(8|10)', windows_family): - script.write('create partition primary size=300\n') - script.write('format quick fs=ntfs label="Windows RE tools"\n') - script.write('assign letter="T"\n') - script.write('set id="de94bba4-06d1-4d40-a16a-bfd50179d6ac"\n') - script.write('gpt attributes=0x8000000000000001\n') - - # System partition - script.write('create partition efi size=260\n') # NOTE: Allows for Advanced Format 4K drives - script.write('format quick fs=fat32 label="System"\n') - script.write('assign letter="S"\n') - - # Microsoft Reserved (MSR) partition - script.write('create partition msr size=128\n') - - # Windows partition - script.write('create partition primary\n') - script.write('format quick fs=ntfs label="Windows"\n') - script.write('assign letter="W"\n') - - # Run script - print(' Formatting drive...') - run_program('diskpart /s {script}'.format(script=diskpart_script)) - time.sleep(2) - -def format_mbr(disk=None): - """Format disk for use as a Windows OS drive using the MBR (legacy) layout.""" - - # Bail early - if disk is None: - raise Exception('No disk provided.') - - # Format drive - print_info('Drive will use a MBR (legacy) layout.') - with open(diskpart_script, 'w') as script: - # Partition table - script.write('select disk {number}\n'.format(number=disk['Number'])) - script.write('clean\n') - - # System partition - script.write('create partition primary size=100\n') - script.write('format fs=ntfs quick label="System Reserved"\n') - script.write('active\n') - script.write('assign letter=s\n') - - # Windows partition - script.write('create partition primary\n') - script.write('format fs=ntfs quick label="Windows"\n') - script.write('assign letter=w\n') - - # Run script - print(' Formatting drive...') - run_program('diskpart /s {script}'.format(script=diskpart_script)) - time.sleep(2) - -def get_attached_disk_info(): - """Get details about the attached disks""" - disks = [] - print_info('Getting drive info...') - - # Assign all the letters - assign_volume_letters() - - # Get disk numbers - with open(diskpart_script, 'w') as script: - script.write('list disk\n') - process_return = run_program('diskpart /s {script}'.format(script=diskpart_script)) - for tmp in re.findall(r'Disk (\d+)\s+\w+\s+(\d+\s+\w+)', process_return.stdout.decode()): - disks.append({'Number': tmp[0], 'Size': human_readable_size(tmp[1])}) - - # Get disk details - for disk in disks: - # Get partition style - with open(diskpart_script, 'w') as script: - script.write('select disk {Number}\n'.format(**disk)) - script.write('uniqueid disk\n') - process_return = run_program('diskpart /s {script}'.format(script=diskpart_script)) - if re.findall(r'Disk ID: {[A-Z0-9]+-[A-Z0-9]+-[A-Z0-9]+-[A-Z0-9]+-[A-Z0-9]+}', process_return.stdout.decode()): - disk['Table'] = 'GPT' - elif re.findall(r'Disk ID: 00000000', process_return.stdout.decode()): - disk['Table'] = 'RAW' - elif re.findall(r'Disk ID: [A-Z0-9]+', process_return.stdout.decode()): - disk['Table'] = 'MBR' - else: - disk['Table'] = 'Unknown' - - # Get disk name/model and physical details - with open(diskpart_script, 'w') as script: - script.write('select disk {Number}\n'.format(**disk)) - script.write('detail disk\n') - process_return = run_program('diskpart /s {script}'.format(script=diskpart_script)) - tmp = process_return.stdout.decode().strip().splitlines() - # Remove empty lines and those without a ':' and split each remaining line at the ':' to form a key/value pair - tmp = [s.strip() for s in tmp if s.strip() != ''] - # Set disk name - disk['Name'] = tmp[4] - tmp = [s.split(':') for s in tmp if ':' in s] - # Add new key/value pairs to the disks variable - disk.update({key.strip(): value.strip() for (key, value) in tmp}) - - # Get partition info for disk - with open(diskpart_script, 'w') as script: - script.write('select disk {Number}\n'.format(**disk)) - script.write('list partition\n') - process_return = run_program('diskpart /s {script}'.format(script=diskpart_script)) - disk['Partitions'] = [] - for tmp in re.findall(r'Partition\s+(\d+)\s+\w+\s+(\d+\s+\w+)\s+', process_return.stdout.decode().strip()): - disk['Partitions'].append({'Number': tmp[0], 'Size': human_readable_size(tmp[1])}) - for par in disk['Partitions']: - # Get partition details - with open(diskpart_script, 'w') as script: - script.write('select disk {Number}\n'.format(**disk)) - script.write('select partition {Number}\n'.format(**par)) - script.write('detail partition\n') - process_return = run_program('diskpart /s {script}'.format(script=diskpart_script)) - for tmp in re.findall(r'Volume\s+\d+\s+(\w|RAW)\s+', process_return.stdout.decode().strip()): - if tmp == 'RAW': - par['FileSystem'] = 'RAW' - else: - par['Letter'] = tmp - try: - process_return2 = run_program('fsutil fsinfo volumeinfo {Letter}:'.format(**par)) - for line in process_return2.stdout.decode().splitlines(): - line = line.strip() - # Get partition name - match = re.search(r'Volume Name\s+:\s+(.*)$', line) - if match: - par['Name'] = match.group(1).strip() - # Get filesystem type - match = re.search(r'File System Name\s+:\s+(.*)$', line) - if match: - par['FileSystem'] = match.group(1).strip() - usage = shutil.disk_usage('{Letter}:\\'.format(Letter=tmp)) - par['Used Space'] = human_readable_size(usage.used) - except subprocess.CalledProcessError: - par['FileSystem'] = 'Unknown' - # Get MBR type / GPT GUID for extra details on "Unknown" partitions - for tmp in re.findall(r'Type\s+:\s+(\S+)', process_return.stdout.decode().strip()): - par['Type'] = tmp - uid = partition_uids.lookup_guid(tmp) - if uid is not None: - par.update({ - 'Description': uid.get('Description', ''), - 'OS': uid.get('OS', '')}) - # Ensure the Name has been set - if 'Name' not in par: - par['Name'] = '' - if 'FileSystem' not in par: - par['FileSystem'] = 'Unknown' - - # Done - return disks - -def select_disk(prompt='Which disk?'): - """Select a disk from the attached disks""" - disks = get_attached_disk_info() + if (len(main_entries) + len(action_entries) == 0): + raise Exception("MenuError: No items given") # Build menu - disk_options = [] - for disk in disks: - display_name = '{Size}\t[{Table}] ({Type}) {Name}'.format(**disk) - if len(disk['Partitions']) > 0: - pwidth=len(str(len(disk['Partitions']))) - for par in disk['Partitions']: - # Show unsupported partition(s) in RED - par_skip = False - if 'Letter' not in par or re.search(r'(RAW|Unknown)', par['FileSystem']): - par_skip = True - if par_skip: - display_name += COLORS['YELLOW'] + menu_splash = '{title}\n\n'.format(title=title) + valid_answers = [] + if (secret_exit): + valid_answers.append('Q') - # Main text - display_name += '\n\t\t\tPartition {Number:>{pwidth}}: {Size} ({FileSystem})'.format(pwidth=pwidth, **par) - if par['Name'] != '': - display_name += '\t"{Name}"'.format(**par) + # Add main entries + if (len(main_entries) > 0): + for i in range(len(main_entries)): + entry = main_entries[i] + # Add Spacer + if ('CRLF' in entry): + menu_splash += '\n' + valid_answers.append(str(i+1)) + menu_splash += '{number:>{mwidth}}: {name}\n'.format(number=i+1, mwidth=len(str(len(main_entries))), name=entry.get('Display Name', entry['Name'])) + menu_splash += '\n' - # Clear color (if set above) - if par_skip: - display_name += COLORS['CLEAR'] - else: - display_name += '{YELLOW}\n\t\t\tNo partitions found.{CLEAR}'.format(**COLORS) - disk_options.append({'Name': display_name, 'Disk': disk}) - actions = [ - {'Name': 'Main Menu', 'Letter': 'M'}, - ] + # Add action entries + if (len(action_entries) > 0): + for entry in action_entries: + # Add Spacer + if ('CRLF' in entry): + menu_splash += '\n' + valid_answers.append(entry['Letter']) + menu_splash += '{letter:>{mwidth}}: {name}\n'.format(letter=entry['Letter'].upper(), mwidth=len(str(len(action_entries))), name=entry['Name']) + menu_splash += '\n' - # Menu loop - selection = menu_select(prompt, disk_options, actions) + answer = '' - if (selection.isnumeric()): - return disk_options[int(selection)-1]['Disk'] - elif (selection == 'M'): - return None + while (answer.upper() not in valid_answers): + os.system('cls') + print(menu_splash) + answer = input('{prompt}: '.format(prompt=prompt)) -def select_windows_version(): - versions = [ - {'Name': 'Windows 7 Home Basic', - 'ImageFile': 'Win7', - 'ImageName': 'Windows 7 HOMEBASIC', - 'Family': '7'}, - {'Name': 'Windows 7 Home Premium', - 'ImageFile': 'Win7', - 'ImageName': 'Windows 7 HOMEPREMIUM', - 'Family': '7'}, - {'Name': 'Windows 7 Professional', - 'ImageFile': 'Win7', - 'ImageName': 'Windows 7 PROFESSIONAL', - 'Family': '7'}, - {'Name': 'Windows 7 Ultimate', - 'ImageFile': 'Win7', - 'ImageName': 'Windows 7 ULTIMATE', - 'Family': '7'}, - - {'Name': 'Windows 8.1', - 'ImageFile': 'Win8', - 'ImageName': 'Windows 8.1', - 'Family': '8', - 'CRLF': True}, - {'Name': 'Windows 8.1 Pro', - 'ImageFile': 'Win8', - 'ImageName': 'Windows 8.1 Pro', - 'Family': '8'}, - - {'Name': 'Windows 10 Home', - 'ImageFile': 'Win10', - 'ImageName': 'Windows 10 Home', - 'Family': '10', - 'CRLF': True}, - {'Name': 'Windows 10 Pro', - 'ImageFile': 'Win10', - 'ImageName': 'Windows 10 Pro', - 'Family': '10'}, - ] - actions = [ - {'Name': 'Main Menu', 'Letter': 'M'}, - ] - - # Menu loop - selection = menu_select('Which version of Windows are we installing?', versions, actions) - - if selection.isnumeric(): - return versions[int(selection)-1] - elif selection == 'M': - return None - -def select_destination(): - # Build menu - dests = [] - for server in BACKUP_SERVERS: - if server['Mounted']: - dests.append(server) - actions = [ - {'Name': 'Main Menu', 'Letter': 'M'}, - ] - - # Size check - for dest in dests: - if 'IP' in dest: - dest['Usage'] = shutil.disk_usage('\\\\{IP}\\{Share}'.format(**dest)) - else: - dest['Usage'] = shutil.disk_usage('{Letter}:\\'.format(**dest)) - dest['Free Space'] = human_readable_size(dest['Usage'].free) - dest['Display Name'] = '{Name} ({Free Space} available)'.format(**dest) - - # Show menu or bail - if len(dests) > 0: - selection = menu_select('Where are we backing up to?', dests, actions) - if selection == 'M': - return None - else: - return dests[int(selection)-1] - else: - print_warning('No backup destinations found.') - return None + return answer.upper() def mount_backup_shares(): """Mount the backup shares for use as destinations for backup image creation""" @@ -566,48 +687,336 @@ def mount_windows_share(): print_warning('Failed to mount \\\\{Name}\\{Share}'.format(**WINDOWS_SERVER)) time.sleep(1) -def menu_select(title='~ Untitled Menu ~', main_entries=[], action_entries=[], prompt='Please make a selection', secret_exit=False): - """Display options in a menu for user selection""" +def pause(prompt='Press Enter to continue... '): + input(prompt) +def prep_disk_for_backup(dest=None, disk=None, ticket_id=None): + disk['Backup Warnings'] = '\n' + disk['Clobber Risk'] = [] + width = len(str(len(disk['Partitions']))) + # Bail early - if (len(main_entries) + len(action_entries) == 0): - raise Exception("MenuError: No items given") + if dest is None: + raise Exception('Destination not provided.') + if disk is None: + raise Exception('Disk not provided.') + if ticket_id is None: + raise Exception('Ticket ID not provided.') + + # Get partition totals + disk['Bad Partitions'] = [par['Number'] for par in disk['Partitions'] if 'Letter' not in par or re.search(r'(RAW|Unknown)', par['FileSystem'])] + disk['Valid Partitions'] = len(disk['Partitions']) - len(disk['Bad Partitions']) + + # Bail if no valid partitions are found (those that can be imaged) + if disk['Valid Partitions'] <= 0: + abort_to_main_menu(' No partitions can be imaged for the selected drive') + + # Prep partitions + for par in disk['Partitions']: + if par['Number'] in disk['Bad Partitions']: + par['Display String'] = '{YELLOW} * Partition {Number:>{width}}:\t{Size} {FileSystem}\t\t{q}{Name}{q}\t{Description} ({OS}){CLEAR}'.format( + width=width, + q='"' if par['Name'] != '' else '', + **par, + **COLORS) + else: + # Update info for WIM capturing + par['Image Name'] = str(par['Name']) + if par['Image Name'] == '': + par['Image Name'] = 'Unknown' + if 'IP' in dest: + par['Image Path'] = '\\\\{IP}\\{Share}\\{ticket}'.format(ticket=ticket_id, **dest) + else: + par['Image Path'] = '{Letter}:\\{ticket}'.format(ticket=ticket_id, **dest) + par['Image File'] = '{Number}_{Image Name}'.format(**par) + par['Image File'] = '{fixed_name}.wim'.format(fixed_name=re.sub(r'\W', '_', par['Image File'])) + + # Check for existing backups + par['Image Exists'] = False + if os.path.exists('{Image Path}\\{Image File}'.format(**par)): + par['Image Exists'] = True + disk['Clobber Risk'].append(par['Number']) + par['Display String'] = '{BLUE} + '.format(**COLORS) + else: + par['Display String'] = '{CLEAR} '.format(**COLORS) + + # Append rest of Display String for valid/clobber partitions + par['Display String'] += 'Partition {Number:>{width}}:\t{Size} {FileSystem} (Used: {Used Space})\t{q}{Name}{q}{CLEAR}'.format( + width=width, + q='"' if par['Name'] != '' else '', + **par, + **COLORS) + + # Set description for bad partitions + if len(disk['Bad Partitions']) > 1: + disk['Backup Warnings'] = '\n{YELLOW} * Unable to backup these partitions{CLEAR}'.format(**COLORS) + elif len(disk['Bad Partitions']) == 1: + print_warning(' * Unable to backup this partition') + disk['Backup Warnings'] = '\n{YELLOW} * Unable to backup this partition{CLEAR}'.format(**COLORS) + + # Set description for partitions that would be clobbered + if disk['Clobber Risk'] > 1: + disk['Backup Warnings'] = '\n{BLUE} + These partitions already have backup images on {Display Name}{CLEAR}'.format(**dest, **COLORS) + elif disk['Clobber Risk'] == 1: + disk['Backup Warnings'] = '\n{BLUE} + This partition already has a backup image on {Display Name}{CLEAR}'.format(**dest, **COLORS) + + # Set warning for skipped partitions + if disk['Clobber Risk'] + len(disk['Bad Partitions']) > 1: + disk['Backup Warnings'] = '\n{YELLOW}If you continue the partitions marked above will NOT be backed up.{CLEAR}'.format(**COLORS) + if disk['Clobber Risk'] + len(disk['Bad Partitions']) == 1: + disk['Backup Warnings'] = '\n{YELLOW}If you continue the partition marked above will NOT be backed up.{CLEAR}'.format(**COLORS) + +def prep_disk_for_formatting(disk=None): + disk['Format Warnings'] = '\n' + width = len(str(len(disk['Partitions']))) + + # Bail early + if disk is None: + raise Exception('Disk not provided.') + + # Confirm drive format + print_warning('All data will be deleted from the following drive:') + print_warning('\t{Size}\t({Table}) {Name}'.format(**disk)) + if (not ask('Is this correct?')): + abort_to_main_menu('Aborting Windows setup') + + # MBR/Legacy or GPT/UEFI? + disk['Use GPT'] = True + if (get_boot_mode() == 'UEFI'): + if (not ask("Setup drive using GPT (UEFI) layout?")): + disk['Use GPT'] = False + else: + if (ask("Setup drive using MBR (legacy) layout?")): + disk['Use GPT'] = False + + # Disk details + disk['Format Warnings'] += ' FORMATTING:\tDrive: {Size}\t[{Table}] ({Type}) {Name}\n'.format(**disk) + if (disk['Use GPT']): + disk['Format Warnings'] += ' Using: \tGPT (UEFI) layout\n' + else: + disk['Format Warnings'] += ' Using: \tMBR (legacy) layout\n' + + # Partition details + if len(disk['Partitions']) == 0: + # Bad color hack that will probably cause (aesthetic) issues in the future + disk['Format Warnings'] += '{YELLOW}\t\tNo partitions found{CLEAR}'.format(**COLORS) + else: + disk['Format Warnings'] += ' ERASING the following partitions:\n' + for par in disk['Partitions']: + if 'Letter' not in par or par['FileSystem'].upper() == 'RAW': + par['Display String'] = '\t\tPartition {Number:>{width}}:\t{Size} {q}{Name}{q} ({FileSystem})\t\t{Description} ({OS})'.format( + width=width, + q='"' if par['Name'] != '' else '', + **par) + else: + par['Display String'] = '\t\tPartition {Number:>{width}}:\t{Size} {q}{Name}{q} ({FileSystem})\t\t(Used space: {Used Space})'.format( + width=width, + q='"' if par['Name'] != '' else '', + **par) + +def print_error(message='Generic error', **kwargs): + print('{RED}{message}{CLEAR}'.format(message=message, **COLORS, **kwargs)) + +def print_info(message='Generic info', **kwargs): + print('{BLUE}{message}{CLEAR}'.format(message=message, **COLORS, **kwargs)) + +def print_success(message='Generic success', **kwargs): + print('{GREEN}{message}{CLEAR}'.format(message=message, **COLORS, **kwargs)) + +def print_warning(message='Generic warning', **kwargs): + print('{YELLOW}{message}{CLEAR}'.format(message=message, **COLORS, **kwargs)) + +def remove_volume_letters(keep=None): + try: + # Run script + with open(diskpart_script, 'w') as script: + for vol in get_volume_numbers(): + script.write('select volume {number}\n'.format(number=vol)) + script.write('remove\n') + run_program('diskpart /s {script}'.format(script=diskpart_script)) + except subprocess.CalledProcessError: + pass + +def run_program(cmd=None, args=[], check=True): + if cmd is None: + raise Exception('No program passed.') + + if len(args) > 0: + args = [cmd] + args + process_return = subprocess.run(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE, check=check) + else: + process_return = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, check=check) + + return process_return + +def select_destination(): + # Build menu + dests = [] + for server in BACKUP_SERVERS: + if server['Mounted']: + dests.append(server) + actions = [ + {'Name': 'Main Menu', 'Letter': 'M'}, + ] + + # Size check + for dest in dests: + if 'IP' in dest: + dest['Usage'] = shutil.disk_usage('\\\\{IP}\\{Share}'.format(**dest)) + else: + dest['Usage'] = shutil.disk_usage('{Letter}:\\'.format(**dest)) + dest['Free Space'] = human_readable_size(dest['Usage'].free) + dest['Display Name'] = '{Name} ({Free Space} available)'.format(**dest) + + # Show menu or bail + if len(dests) > 0: + selection = menu_select('Where are we backing up to?', dests, actions) + if selection == 'M': + return None + else: + return dests[int(selection)-1] + else: + print_warning('No backup destinations found.') + return None + +def select_disk(prompt='Which disk?'): + """Select a disk from the attached disks""" + disks = get_attached_disk_info() # Build menu - menu_splash = '{title}\n\n'.format(title=title) - valid_answers = [] - if (secret_exit): - valid_answers.append('Q') + disk_options = [] + for disk in disks: + display_name = '{Size}\t[{Table}] ({Type}) {Name}'.format(**disk) + if len(disk['Partitions']) > 0: + pwidth=len(str(len(disk['Partitions']))) + for par in disk['Partitions']: + # Show unsupported partition(s) in RED + par_skip = False + if 'Letter' not in par or re.search(r'(RAW|Unknown)', par['FileSystem']): + par_skip = True + if par_skip: + display_name += COLORS['YELLOW'] - # Add main entries - if (len(main_entries) > 0): - for i in range(len(main_entries)): - entry = main_entries[i] - # Add Spacer - if ('CRLF' in entry): - menu_splash += '\n' - valid_answers.append(str(i+1)) - menu_splash += '{number:>{mwidth}}: {name}\n'.format(number=i+1, mwidth=len(str(len(main_entries))), name=entry.get('Display Name', entry['Name'])) - menu_splash += '\n' + # Main text + display_name += '\n\t\t\tPartition {Number:>{pwidth}}: {Size} ({FileSystem})'.format(pwidth=pwidth, **par) + if par['Name'] != '': + display_name += '\t"{Name}"'.format(**par) - # Add action entries - if (len(action_entries) > 0): - for entry in action_entries: - # Add Spacer - if ('CRLF' in entry): - menu_splash += '\n' - valid_answers.append(entry['Letter']) - menu_splash += '{letter:>{mwidth}}: {name}\n'.format(letter=entry['Letter'].upper(), mwidth=len(str(len(action_entries))), name=entry['Name']) - menu_splash += '\n' + # Clear color (if set above) + if par_skip: + display_name += COLORS['CLEAR'] + else: + display_name += '{YELLOW}\n\t\t\tNo partitions found.{CLEAR}'.format(**COLORS) + disk_options.append({'Name': display_name, 'Disk': disk}) + actions = [ + {'Name': 'Main Menu', 'Letter': 'M'}, + ] - answer = '' + # Menu loop + selection = menu_select(prompt, disk_options, actions) - while (answer.upper() not in valid_answers): - os.system('cls') - print(menu_splash) - answer = input('{prompt}: '.format(prompt=prompt)) + if (selection.isnumeric()): + return disk_options[int(selection)-1]['Disk'] + elif (selection == 'M'): + abort_to_main_menu() - return answer.upper() +def select_minidump_path(): + dumps = [] + + # Assign volume letters first + assign_volume_letters() + + # Search for minidumps + tmp = run_program('mountvol') + tmp = [d for d in re.findall(r'.*([A-Za-z]):\\', tmp.stdout.decode())] + # Remove RAMDisk letter + if 'X' in tmp: + tmp.remove('X') + for drive in tmp: + if os.path.exists('{drive}:\\Windows\\MiniDump'.format(drive=drive)): + dumps.append({'Name': '{drive}:\\Windows\\MiniDump'.format(drive=drive)}) + + # Check results before showing menu + if len(dumps) == 0: + print_error(' No BSoD / MiniDump paths found') + time.sleep(2) + return None + + # Menu + selection = menu_select('Which BSoD / MiniDump path are we scanning?', dumps, []) + return dumps[int(selection) - 1]['Name'] + +def select_windows_version(): + actions = [{'Name': 'Main Menu', 'Letter': 'M'},] + + # Menu loop + selection = menu_select('Which version of Windows are we installing?', WINDOWS_VERSIONS, actions) + + if selection.isnumeric(): + return WINDOWS_VERSIONS[int(selection)-1] + elif selection == 'M': + abort_to_main_menu() + +def setup_boot_files(windows_version=None, system_letter='S', windows_letter='W', tools_letter='T'): + # Bail early + if windows_version is None: + raise Exception('Windows version not specified.') + + # Setup system partition + print(' Creating boot files...') + try: + run_program('bcdboot {win}:\\Windows /s {sys}: /f ALL'.format(win=windows_letter, sys=system_letter)) + except subprocess.CalledProcessError: + print_error('Failed to create boot files.') + raise SetupException + if re.search(r'^(8|10)', windows_version['Family']): + try: + _dest = '{tools}:\\Recovery\\WindowsRE'.format(tools=tools_letter) + os.makedirs(_dest, exist_ok=True) + shutil.copy('{win}:\\Windows\\System32\\Recovery\\WinRE.wim', '{dest}\\WinRE.wim'.format(dest=_dest, win=windows_letter)) + run_program('{win}:\\Windows\\System32\\reagentc /setreimage /path {dest} /target {win}:\\Windows'.format(dest=_dest, win=windows_letter)) + except subprocess.CalledProcessError: + print_warning('Failed to setup WindowsRE files.') + raise SetupException + +def setup_windows(bin=None, windows_image=None, windows_version=None): + # Bail early + if bin is None: + raise Exception('bin path not specified.') + if windows_image is None: + raise Exception('Windows image not specified.') + if windows_version is None: + raise Exception('Windows version not specified.') + + # Apply image + print(' Applying image...') + cmd = '{bin}\\wimlib\\wimlib-imagex apply "{File}.{Ext}" "{Image Name}" W:\\ {Glob}'.format(bin=bin, **windows_image, **windows_version) + try: + run_program(cmd) + except subprocess.CalledProcessError: + print_error('Failed to apply Windows image.') + raise SetupException + +def verify_wim_backup(bin=None, par=None): + # Bail early + if bin is None: + raise Exception('bin path not specified.') + if par is None: + raise Exception('Partition not specified.') + + # Verify hiding all output for quicker verification + print(' Partition {Number} Image...\t\t'.format(**par), end='', flush=True) + cmd = '{bin}\\wimlib\\wimlib-imagex verify "{Image Path}\\{Image File}" --nocheck'.format(bin=bin, **par) + if not os.path.exists('{Image Path}\\{Image File}'.format(**par)): + print_error('Missing.') + else: + try: + run_program(cmd) + print_success('OK.') + except subprocess.CalledProcessError as err: + print_error('Damaged.') + par['Error'] = par.get('Error', []) + err.stderr.decode().splitlines() + raise BackupException if __name__ == '__main__': print("This file is not meant to be called directly.") diff --git a/Scripts/menu.py b/Scripts/menu.py index e781c14c..fb352f83 100644 --- a/Scripts/menu.py +++ b/Scripts/menu.py @@ -1,297 +1,141 @@ # WK WinPE Menu +# Init import os import re import subprocess +import sys import time import traceback -import winreg - -from functions import * - -# Init os.chdir(os.path.dirname(os.path.realpath(__file__))) bin = os.path.abspath('..\\') -## Check bootup type -BOOT_TYPE = 'Legacy' -try: - reg_key = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, 'System\\CurrentControlSet\\Control') - reg_value = winreg.QueryValueEx(reg_key, 'PEFirmwareType')[0] - if reg_value == 2: - BOOT_TYPE = 'UEFI' -except: - BOOT_TYPE = 'Unknown' - -class AbortException(Exception): - pass - -def abort_to_main_menu(message='Returning to main menu...'): - print_warning(message) - pause('Press Enter to return to main menu... ') - raise AbortException +sys.path.append(os.getcwd()) +from functions import * def menu_backup_imaging(): """Take backup images of partition(s) in the WIM format and save them to a backup share""" + errors = False # Mount backup shares os.system('cls') mount_backup_shares() - # Set ticket number - ticket = None - while ticket is None: - tmp = input('Enter ticket number: ') - if re.match(r'^([0-9]+([-_]?\w+|))$', tmp): - ticket = tmp - - # Select disk to backup - disk = select_disk('For which drive are we creating backups?') - if disk is None: - abort_to_main_menu() - - # Get list of partitions that can't be imaged - bad_parts = [p['Number'] for p in disk['Partitions'] if 'Letter' not in p or re.search(r'(RAW|Unknown)', p['FileSystem'])] - - # Bail if no partitions are found (that can be imaged) - num_parts = len(disk['Partitions']) - if num_parts == 0 or num_parts == len(bad_parts): - abort_to_main_menu(' No partitions can be imaged for the selected drive') + # Set ticket ID + ticket_id = get_ticket_id() # Select destination dest = select_destination() if dest is None: abort_to_main_menu('Aborting Backup Creation') - # List (and update) partition details for selected drive + # Select disk to backup + disk = select_disk('For which drive are we creating backups?') + if disk is None: + abort_to_main_menu() + prep_disk_for_backup(dest, disk, ticket_id) + + # Display details for backup task os.system('cls') print('Create Backup - Details:\n') print(' Drive: {Size}\t[{Table}] ({Type}) {Name}\n'.format(**disk)) - clobber_risk = 0 - width=len(str(len(disk['Partitions']))) for par in disk['Partitions']: - # Detail each partition - if par['Number'] in bad_parts: - print_warning(' * Partition {Number:>{width}}:\t{Size} {FileSystem}\t\t{q}{Name}{q}\t{Description} ({OS})'.format( - width=width, - q='"' if par['Name'] != '' else '', - **par)) - else: - # Update info for WIM capture - par['ImageName'] = str(par['Name']) - if par['ImageName'] == '': - par['ImageName'] = 'Unknown' - if 'IP' in dest: - par['ImagePath'] = '\\\\{IP}\\{Share}\\{ticket}'.format(ticket=ticket, **dest) - else: - par['ImagePath'] = '{Letter}:\\{ticket}'.format(ticket=ticket, **dest) - par['ImageFile'] = '{Number}_{ImageName}'.format(**par) - par['ImageFile'] = '{fixed_name}.wim'.format(fixed_name=re.sub(r'\W', '_', par['ImageFile'])) - - # Check for existing backups - par['ImageExists'] = False - if os.path.exists('{ImagePath}\\{ImageFile}'.format(**par)): - par['ImageExists'] = True - clobber_risk += 1 - print_info(' + Partition {Number:>{width}}:\t{Size} {FileSystem} (Used: {Used Space})\t{q}{Name}{q}'.format( - width=width, - q='"' if par['Name'] != '' else '', - **par)) - else: - print(' Partition {Number:>{width}}:\t{Size} {FileSystem} (Used: {Used Space})\t{q}{Name}{q}'.format( - width=width, - q='"' if par['Name'] != '' else '', - **par)) - print('') # Spacer - - # Add warning about partition(s) that will be skipped - if len(bad_parts) > 1: - print_warning(' * Unable to backup these partitions') - elif len(bad_parts) == 1: - print_warning(' * Unable to backup this partition') - if clobber_risk > 1: - print_info(' + These partitions already have backup images on {Display Name}:'.format(**dest)) - elif clobber_risk == 1: - print_info(' + This partition already has a backup image on {Display Name}:'.format(**dest)) - if clobber_risk + len(bad_parts) > 1: - print_warning('\nIf you continue the partitions marked above will NOT be backed up.\n') - if clobber_risk + len(bad_parts) == 1: - print_warning('\nIf you continue the partition marked above will NOT be backed up.\n') - - # (re)display the destination - print(' Destination:\t{name}\n'.format(name=dest.get('Display Name', dest['Name']))) + print(par['Display String']) + print(disk['Backup Warnings']) + print('\n Destination:\t{name}\n'.format(name=dest.get('Display Name', dest['Name']))) # Ask to proceed if (not ask('Proceed with backup?')): abort_to_main_menu('Aborting Backup Creation') - + # Backup partition(s) print('\n\nStarting task.\n') - errors = False for par in disk['Partitions']: - print(' Partition {Number} Backup...\t\t'.format(**par), end='', flush=True) - if par['Number'] in bad_parts: - print_warning('Skipped.') - else: - cmd = '{bin}\\wimlib\\wimlib-imagex capture {Letter}:\\ "{ImagePath}\\{ImageFile}" "{ImageName}" "{ImageName}" --compress=fast'.format(bin=bin, **par) - if par['ImageExists']: - print_warning('Skipped.') - else: - try: - os.makedirs('{ImagePath}'.format(**par), exist_ok=True) - run_program(cmd) - print_success('Complete.') - except subprocess.CalledProcessError as err: - print_error('Failed.') - errors = True - par['Error'] = err.stderr.decode().splitlines() - + try: + backup_partition(bin, par) + except BackupException: + errors = True + # Verify backup(s) - if len(par) - len(bad_parts) > 1: + if len(disk['Valid Partitions']) > 1: print('\n\n Verifying backups\n') else: print('\n\n Verifying backup\n') for par in disk['Partitions']: - if par['Number'] not in bad_parts: - print(' Partition {Number} Image...\t\t'.format(**par), end='', flush=True) - cmd = '{bin}\\wimlib\\wimlib-imagex verify "{ImagePath}\\{ImageFile}" --nocheck'.format(bin=bin, **par) - if not os.path.exists('{ImagePath}\\{ImageFile}'.format(**par)): - print_error('Missing.') - else: - try: - run_program(cmd) - print_success('OK.') - except subprocess.CalledProcessError as err: - print_error('Damaged.') - errors = True - par['Error'] = par.get('Error', []) + err.stderr.decode().splitlines() + if par['Number'] in disk['Bad Partitions']: + continue # Skip verification + try: + verify_wim_backup(bin, par) + except BackupException: + errors = True # Print summary if errors: print_warning('\nErrors were encountered and are detailed below.') for par in [p for p in disk['Partitions'] if 'Error' in p]: print(' Partition {Number} Error:'.format(**par)) - for line in par['Error']: - line = line.strip() - if line != '': - print_error('\t{line}'.format(line=line)) - time.sleep(300) + for line in [line.strip() for line in par['Error'] if line.strip() != '']: + print_error('\t{line}'.format(line=line)) + time.sleep(30) else: print_success('\nNo errors were encountered during imaging.') - time.sleep(10) + time.sleep(5) pause('\nPress Enter to return to main menu... ') def menu_windows_setup(): """Format a drive, partition for MBR or GPT, apply a Windows image, and rebuild the boot files""" + errors = False # Select the version of Windows to apply os.system('cls') - selected_windows_version = select_windows_version() - if selected_windows_version is None: - abort_to_main_menu('Aborting Windows setup') - + windows_version = select_windows_version() + # Find Windows image - image = find_windows_image(selected_windows_version['ImageFile']) - if not any(image): - print_error('Failed to find Windows source image for {winver}'.format(winver=selected_windows_version['Name'])) - abort_to_main_menu('Aborting Windows setup') + windows_image = find_windows_image(bin, windows_version) # Select drive to use as the OS drive - dest_drive = select_disk('To which drive are we installing Windows?') - if dest_drive is None: - abort_to_main_menu('Aborting Windows setup') - - # Confirm drive format - print_warning('All data will be deleted from the following drive:') - print_warning('\t{Size}\t({Table}) {Name}'.format(**dest_drive)) - if (not ask('Is this correct?')): - abort_to_main_menu('Aborting Windows setup') - - # MBR/Legacy or GPT/UEFI? - use_gpt = True - if (BOOT_TYPE == 'UEFI'): - if (not ask("Setup drive using GPT (UEFI) layout?")): - use_gpt = False - else: - if (ask("Setup drive using MBR (legacy) layout?")): - use_gpt = False + dest_disk = select_disk('To which drive are we installing Windows?') + prep_disk_for_formatting(dest_disk) # Safety check print_warning('SAFETY CHECK\n') - print_error(' FORMATTING:\tDrive: {Size}\t[{Table}] ({Type}) {Name}'.format(**dest_drive)) - if len(dest_drive['Partitions']) > 0: - width=len(str(len(dest_drive['Partitions']))) - for par in dest_drive['Partitions']: - if 'Letter' not in par or re.search(r'(RAW)', par['FileSystem']): - print_error('\t\tPartition {Number:>{width}}:\t{Size} {q}{Name}{q} ({FileSystem})\t\t{Description} ({OS})'.format( - width=width, - q='"' if par['Name'] != '' else '', - **par)) - else: - print_error('\t\tPartition {Number:>{width}}:\t{Size} {q}{Name}{q} ({FileSystem})\t\t(Used space: {Used Space})'.format( - width=width, - q='"' if par['Name'] != '' else '', - **par)) - else: - print_warning('\t\tNo partitions found') - if (use_gpt): - print(' Using: \tGPT (UEFI) layout') - else: - print(' Using: \tMBR (legacy) layout') - print_info(' Installing:\t{winver}'.format(winver=selected_windows_version['Name'])) + print_error(dest_disk['Format Warnings']) + for par in dest_disk['Partitions']: + print_error(par['Display String']) + print_info('\n Installing:\t{winver}'.format(winver=windows_version['Name'])) if (not ask('\nIs this correct?')): abort_to_main_menu('Aborting Windows setup') # Release currently used volume letters (ensures that the drives will get S, T, & W as needed below) - remove_volume_letters(keep=image['Source']) + remove_volume_letters(keep=windows_image['Source']) # Format and partition drive - if (use_gpt): - format_gpt(dest_drive, selected_windows_version['Family']) + if (dest_disk['Use GPT']): + format_gpt(dest_disk, windows_version['Family']) else: - format_mbr(dest_drive) + format_mbr(dest_disk, windows_version['Family']) - # Apply Windows image - errors = False - print(' Applying image...') - cmd = '{bin}\\wimlib\\wimlib-imagex apply "{File}.{Ext}" "{ImageName}" W:\\ {Glob}'.format(bin=bin, **image, **selected_windows_version) + # Setup Windows try: - run_program(cmd) - except subprocess.CalledProcessError: + setup_windows(bin, windows_image, windows_version) + setup_boot_files(windows_version) + except SetupException: errors = True - print_error('Failed to apply Windows image.') - - # Create boot files - if not errors: - print(' Creating boot files...'.format(**selected_windows_version)) - try: - run_program('bcdboot W:\\Windows /s S: /f ALL') - except subprocess.CalledProcessError: - errors = True - print_error('Failed to create boot files.') - if re.search(r'^(8|10)', selected_windows_version['Family']): - try: - run_program('W:\\Windows\\System32\\reagentc /setreimage /path T:\\Recovery\\WindowsRE /target W:\\Windows') - except subprocess.CalledProcessError: - # errors = True # Changed to warning. - print_warning('Failed to setup WindowsRE files.') # Print summary if errors: print_warning('\nErrors were encountered during setup.') - time.sleep(300) + time.sleep(30) else: - print_success('\nNo errors were encountered during setup.') - time.sleep(10) + print_success('\nDone.') + time.sleep(5) pause('\nPress Enter to return to main menu... ') def menu_tools(): tools = [ {'Name': 'Blue Screen View', 'Folder': 'BlueScreenView', 'File': 'BlueScreenView.exe'}, {'Name': 'CPU-Z', 'Folder': 'CPU-Z', 'File': 'cpuz.exe'}, - {'Name': 'Explorer++', 'Folder': 'Explorer++', 'File': 'Explorer++.exe'}, {'Name': 'Fast Copy', 'Folder': 'FastCopy', 'File': 'FastCopy.exe', 'Args': ['/log', '/logfile=X:\WK\Info\FastCopy.log', '/cmd=noexist_only', '/utf8', '/skip_empty_dir', '/linkdest', '/open_window', '/balloon=FALSE', r'/exclude=$RECYCLE.BIN;$Recycle.Bin;.AppleDB;.AppleDesktop;.AppleDouble;.com.apple.timemachine.supported;.dbfseventsd;.DocumentRevisions-V100*;.DS_Store;.fseventsd;.PKInstallSandboxManager;.Spotlight*;.SymAV*;.symSchedScanLockxz;.TemporaryItems;.Trash*;.vol;.VolumeIcon.icns;desktop.ini;Desktop?DB;Desktop?DF;hiberfil.sys;lost+found;Network?Trash?Folder;pagefile.sys;Recycled;RECYCLER;System?Volume?Information;Temporary?Items;Thumbs.db']}, {'Name': 'HWiNFO', 'Folder': 'HWiNFO', 'File': 'HWiNFO.exe'}, - {'Name': 'HW Monitor', 'Folder': 'HWMonitor', 'File': 'HWMonitor.exe'}, {'Name': 'NT Password Editor', 'Folder': 'NT Password Editor', 'File': 'ntpwedit.exe'}, {'Name': 'Notepad2', 'Folder': 'Notepad2', 'File': 'Notepad2-Mod.exe'}, {'Name': 'PhotoRec', 'Folder': 'TestDisk', 'File': 'photorec_win.exe', 'Args': ['-new_console:n']}, @@ -351,10 +195,9 @@ def menu_main(): print_error('Major exception in: {menu}'.format(menu=menus[int(selection)-1]['Name'])) print_warning(' Please let The Wizard know and he\'ll look into it (Please include the details below).') print(traceback.print_exc()) - print_info(' You can reboot and try again but if this crashes again an alternative approach is required.') - time.sleep(300) - pause('Press Enter to shutdown...') - run_program(['wpeutil', 'shutdown']) + time.sleep(5) + print_info(' You can retry but if this crashes again an alternative approach may be required.') + pause('\nPress enter to return to the main menu') elif (selection == 'C'): run_program(['cmd', '-new_console:n'], check=False) elif (selection == 'R'): @@ -362,7 +205,7 @@ def menu_main(): elif (selection == 'S'): run_program(['wpeutil', 'shutdown']) else: - quit() + sys.exit(0) if __name__ == '__main__': menu_main() \ No newline at end of file diff --git a/System32/Winpeshl.ini b/System32/Winpeshl.ini index cd3d04ab..dc424ce7 100644 --- a/System32/Winpeshl.ini +++ b/System32/Winpeshl.ini @@ -2,4 +2,5 @@ [LaunchApps] wpeinit wpeutil updatebootinfo -"%SystemDrive%\WK\conemu-maximus5\ConEmu.exe", /cmd cmd /k python %SystemDrive%\WK\Scripts\menu.py" +cd /d "%SystemDrive%\WK" +"%SystemDrive%\WK\ConEmu\ConEmu.exe", /cmd cmd /k python "%SystemDrive%\WK\Scripts\menu.py" diff --git a/System32/menu.cmd b/System32/menu.cmd new file mode 100644 index 00000000..771dc372 --- /dev/null +++ b/System32/menu.cmd @@ -0,0 +1,2 @@ +@echo off +python "%SystemDrive%\WK\Scripts\menu.py" \ No newline at end of file diff --git a/WK/amd64/conemu-maximus5/ConEmu.xml b/WK/amd64/ConEmu/ConEmu.xml similarity index 52% rename from WK/amd64/conemu-maximus5/ConEmu.xml rename to WK/amd64/ConEmu/ConEmu.xml index 9752d747..b8abe846 100644 --- a/WK/amd64/conemu-maximus5/ConEmu.xml +++ b/WK/amd64/ConEmu/ConEmu.xml @@ -1,38 +1,45 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -45,108 +52,131 @@ - + - + - - + + + - + - + + + + + + + + + + + + + + + + - - - - - - - + - + + + + + + - - - + + + + - + - + - + + + - + + - - + + - + - - - - - - - + + + + + + + + + - - + + + + @@ -155,14 +185,22 @@ - + + + + + + + + - + + @@ -170,7 +208,10 @@ + + + @@ -186,17 +227,19 @@ - + - + + + @@ -205,39 +248,48 @@ - + + - + - - - - + + + + - + - + + + + + + + + + - + - - - - - + + + + + @@ -248,22 +300,30 @@ + - + + + + + + + - + - + + @@ -271,24 +331,24 @@ - + - + - + - - + + @@ -308,7 +368,7 @@ - + @@ -317,7 +377,7 @@ - + @@ -329,7 +389,9 @@ - + + + @@ -339,348 +401,60 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - + - + - - - - + + + + - + - - - + + + - - + + - - - - + + + + - - - + + + + - - - - - + + + + + @@ -693,31 +467,36 @@ - + + - - - - - + + + + + - - - - - - - - - + + + + + + + + + + - + + + + @@ -727,22 +506,23 @@ - - + + + - - - - - - - - - - + + + + + + + + + + @@ -805,40 +585,98 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/WK/amd64/Explorer++/config.xml b/WK/amd64/Explorer++/config.xml deleted file mode 100644 index add6848f..00000000 --- a/WK/amd64/Explorer++/config.xml +++ /dev/null @@ -1,113 +0,0 @@ - - - - - yes - no - yes - yes - no - yes - no - no - - - - - 90 - yes - no - no - no - no - no - no - 0 - yes - 9 - no - 0 - yes - no - ::{20D04FE0-3AEA-1069-A2D8-08002B30309D} - no - 500 - yes - yes - 1 - yes - no - no - no - yes - yes - yes - yes - no - yes - no - yes - yes - yes - no - yes - yes - no - yes - yes - yes - 1 - yes - 1 - yes - no - no - - no - 208 - 4 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/WK/amd64/HWMonitor/hwmonitorw.ini b/WK/amd64/HWMonitor/hwmonitorw.ini deleted file mode 100644 index 85f41603..00000000 --- a/WK/amd64/HWMonitor/hwmonitorw.ini +++ /dev/null @@ -1,7 +0,0 @@ -[HWMonitor] -VERSION=1.2.9.0 -USE_ACPI=1 -USE_SMBUS=1 -USE_SMART=1 -USE_DISPLAY=1 -UPDATES=0 diff --git a/WK/amd64/HWiNFO/HWiNFO64.INI b/WK/amd64/HWiNFO/HWiNFO64.INI index 700c5ff6..23133936 100644 --- a/WK/amd64/HWiNFO/HWiNFO64.INI +++ b/WK/amd64/HWiNFO/HWiNFO64.INI @@ -1,4 +1,3 @@ - [LogfileSettings] COMP=1 COMP_SP=1 @@ -172,7 +171,7 @@ PCIdirect=1 OpenSystemSummary=0 RememberPreferences=1 LargeFonts=0 -OpenSensors=1 +OpenSensors=0 MinimalizeMainWnd=0 MinimalizeSensors=0 PersistentDriver=0 @@ -180,7 +179,7 @@ UseHPET=1 AutoUpdate=0 GPUI2CNVAPI=1 GPUI2CADL=0 -SensorsOnly=1 +SensorsOnly=0 AcpiEval=1 CpuClkFromBusClk=1 BusClkPolling=1 diff --git a/WK/amd64/Q-Dir/Q-Dir.ini b/WK/amd64/Q-Dir/Q-Dir.ini index a9bdcb74..f6532f37 100644 --- a/WK/amd64/Q-Dir/Q-Dir.ini +++ b/WK/amd64/Q-Dir/Q-Dir.ini @@ -4,11 +4,11 @@ QDir_Id=0 useColorStart=1 Als=12 designe_mode=2 -WinRC=-1;-29;1441;873 -showCmd=1 +WinRC=66;87;1026;761 +showCmd=3 StartCrash=0 default_tab= -Max=3 +Max=1 show_ext_in_type=1 title_info=1 adresbar_style=1 @@ -56,4 +56,14 @@ Disable=0 [Quick-Links] WK=%systemdrive%/WK [Options] -Start=0 +Start=7 +[X-Size] +mode=1 +dig=0 +fld_size=1 +ths_sep=1 +type=0 +precent=1 +ff_cnt=1 +block_no_focus=1 +nosort_fld_size=1 diff --git a/WK/x86/conemu-maximus5/ConEmu.xml b/WK/x86/ConEmu/ConEmu.xml similarity index 52% rename from WK/x86/conemu-maximus5/ConEmu.xml rename to WK/x86/ConEmu/ConEmu.xml index a54f9ab5..b8abe846 100644 --- a/WK/x86/conemu-maximus5/ConEmu.xml +++ b/WK/x86/ConEmu/ConEmu.xml @@ -1,38 +1,45 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -45,108 +52,131 @@ - + - + - - + + + - + - + + + + + + + + + + + + + + + + - - - - - - - + - + + + + + + - - - + + + + - + - + - + + + - + + - - + + - + - - - - - - - + + + + + + + + + - + - + + + @@ -155,14 +185,22 @@ - + + + + + + + + - + + @@ -170,7 +208,10 @@ + + + @@ -186,17 +227,19 @@ - + - + + + @@ -205,39 +248,48 @@ - + + - + - - - - + + + + - + - + + + + + + + + + - + - - - - - + + + + + @@ -248,22 +300,30 @@ + - + + + + + + + - + - + + @@ -271,24 +331,24 @@ - + - + - + - - + + @@ -308,7 +368,7 @@ - + @@ -317,7 +377,7 @@ - + @@ -329,7 +389,9 @@ - + + + @@ -339,348 +401,60 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - + - + - - - - + + + + - + - - - + + + - - + + - - - - + + + + - - - + + + + - - - - - + + + + + @@ -693,31 +467,36 @@ - + + - - - - - + + + + + - - - - - - - - - + + + + + + + + + + - + + + + @@ -727,22 +506,23 @@ - - + + + - - - - - - - - - - + + + + + + + + + + @@ -805,40 +585,98 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/WK/x86/Explorer++/config.xml b/WK/x86/Explorer++/config.xml deleted file mode 100644 index add6848f..00000000 --- a/WK/x86/Explorer++/config.xml +++ /dev/null @@ -1,113 +0,0 @@ - - - - - yes - no - yes - yes - no - yes - no - no - - - - - 90 - yes - no - no - no - no - no - no - 0 - yes - 9 - no - 0 - yes - no - ::{20D04FE0-3AEA-1069-A2D8-08002B30309D} - no - 500 - yes - yes - 1 - yes - no - no - no - yes - yes - yes - yes - no - yes - no - yes - yes - yes - no - yes - yes - no - yes - yes - yes - 1 - yes - 1 - yes - no - no - - no - 208 - 4 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/WK/x86/HWMonitor/hwmonitorw.ini b/WK/x86/HWMonitor/hwmonitorw.ini deleted file mode 100644 index 85f41603..00000000 --- a/WK/x86/HWMonitor/hwmonitorw.ini +++ /dev/null @@ -1,7 +0,0 @@ -[HWMonitor] -VERSION=1.2.9.0 -USE_ACPI=1 -USE_SMBUS=1 -USE_SMART=1 -USE_DISPLAY=1 -UPDATES=0 diff --git a/WK/x86/HWiNFO/HWiNFO32.INI b/WK/x86/HWiNFO/HWiNFO32.INI index ace15fef..74cf2a3e 100644 --- a/WK/x86/HWiNFO/HWiNFO32.INI +++ b/WK/x86/HWiNFO/HWiNFO32.INI @@ -633,7 +633,7 @@ PCIdirect=1 OpenSystemSummary=0 RememberPreferences=1 LargeFonts=0 -OpenSensors=1 +OpenSensors=0 MinimalizeMainWnd=0 MinimalizeSensors=0 PersistentDriver=0 @@ -641,7 +641,7 @@ UseHPET=1 AutoUpdate=0 GPUI2CNVAPI=1 GPUI2CADL=0 -SensorsOnly=1 +SensorsOnly=0 AcpiEval=1 CpuClkFromBusClk=1 BusClkPolling=1 diff --git a/WK/x86/Q-Dir/Q-Dir.ini b/WK/x86/Q-Dir/Q-Dir.ini index a9bdcb74..18f44d38 100644 --- a/WK/x86/Q-Dir/Q-Dir.ini +++ b/WK/x86/Q-Dir/Q-Dir.ini @@ -4,11 +4,11 @@ QDir_Id=0 useColorStart=1 Als=12 designe_mode=2 -WinRC=-1;-29;1441;873 -showCmd=1 +WinRC=8;15;968;689 +showCmd=3 StartCrash=0 default_tab= -Max=3 +Max=1 show_ext_in_type=1 title_info=1 adresbar_style=1 @@ -56,4 +56,14 @@ Disable=0 [Quick-Links] WK=%systemdrive%/WK [Options] -Start=0 +Start=7 +[X-Size] +mode=1 +dig=0 +fld_size=1 +ths_sep=1 +type=0 +precent=1 +ff_cnt=1 +block_no_focus=1 +nosort_fld_size=1 diff --git a/make.cmd b/make.cmd index 1447ecd8..c12fb6d0 100644 --- a/make.cmd +++ b/make.cmd @@ -2,7 +2,7 @@ :Init setlocal EnableDelayedExpansion -title WinPE 10 creation tool +title WK-WinPE creation tool color 1b pushd %~dp0 @@ -125,25 +125,26 @@ for %%a in (amd64 x86) do ( robocopy /s /r:3 /w:0 "!wd!\Scripts" "!mount!\WK\Scripts" rem Add System32 Stuff + copy /y "!wd!\System32\menu.cmd" "!mount!\Windows\System32\menu.cmd" copy /y "!wd!\System32\Winpeshl.ini" "!mount!\Windows\System32\Winpeshl.ini" - rem Background + rem Background takeown /f "!mount!\Windows\System32\winpe.jpg" /a icacls "!mount!\Windows\System32\winpe.jpg" /grant administrators:F copy /y "!wd!\System32\winpe.jpg" "!mount!\Windows\System32\winpe.jpg" - copy /y "!wd!\System32\winpe.jpg" "!mount!\WK\conemu-maximus5\winpe.jpg" + copy /y "!wd!\System32\winpe.jpg" "!mount!\WK\ConEmu\ConEmu.jpg" rem Registry Edits reg load HKLM\WinPE-SW "!mount!\Windows\System32\config\SOFTWARE" reg load HKLM\WinPE-SYS "!mount!\Windows\System32\config\SYSTEM" - rem Add 7-Zip and Python to path + rem Add 7-Zip and Python to path reg add "HKLM\WinPE-SYS\ControlSet001\Control\Session Manager\Environment" /v Path /t REG_EXPAND_SZ /d "%%SystemRoot%%\system32;%%SystemRoot%%;%%SystemRoot%%\System32\Wbem;%%SYSTEMROOT%%\System32\WindowsPowerShell\v1.0\;%%SystemDrive%%\WK\7-Zip;%%SystemDrive%%\WK\python;%%SystemDrive%%\WK\wimlib" /f - rem Replace Notepad + rem Replace Notepad reg add "HKLM\WinPE-SW\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\notepad.exe" /v Debugger /t REG_SZ /d "X:\WK\Notepad2\Notepad2-Mod.exe /z" /f - rem Unload registry hives + rem Unload registry hives reg unload HKLM\WinPE-SW reg unload HKLM\WinPE-SYS @@ -151,8 +152,8 @@ for %%a in (amd64 x86) do ( dism /unmount-image /mountdir:"!mount!" /commit rem Create ISO - del "WinPE-!iso_date!-!arch!.iso" - call makewinpemedia.cmd /iso "!pe_files!" "WinPE-!iso_date!-!arch!-testing.iso" + del "wk-winpe-!iso_date!-!arch!.iso" + call makewinpemedia.cmd /iso "!pe_files!" "wk-winpe-!iso_date!-!arch!.iso" ) goto Done