Updated files to meet PEP8 guidelines

* Fixes issue #42
  * More work is likely needed
This commit is contained in:
2Shirt 2018-12-27 21:46:04 -07:00
commit 7b8b1ab111
Signed by: 2Shirt
GPG key ID: 152FAC923B0E132C
33 changed files with 7011 additions and 6612 deletions

View file

@ -12,19 +12,20 @@ from functions.network import *
init_global_vars() init_global_vars()
if __name__ == '__main__': if __name__ == '__main__':
try: try:
# Prep # Prep
clear_screen() clear_screen()
# Connect # Connect
connect_to_network() connect_to_network()
# Done
print_standard('\nDone.')
#pause("Press Enter to exit...")
exit_script()
except SystemExit:
pass
except:
major_exception()
# Done
print_standard('\nDone.')
#pause("Press Enter to exit...")
exit_script()
except SystemExit:
pass
except:
major_exception()
# vim: sts=2 sw=2 ts=2

View file

@ -6,58 +6,58 @@ import os
import sys import sys
# Init # Init
sys.path.append(os.path.dirname(os.path.realpath(__file__))) os.chdir(os.path.dirname(os.path.realpath(__file__)))
sys.path.append(os.getcwd())
from functions.ddrescue import * from functions.ddrescue import *
from functions.hw_diags import * from functions.hw_diags import *
init_global_vars() init_global_vars()
if __name__ == '__main__': if __name__ == '__main__':
try:
# Prep
clear_screen()
args = list(sys.argv)
run_mode = ''
source_path = None
dest_path = None
# Parse args
try: try:
# Prep script_name = os.path.basename(args.pop(0))
clear_screen() run_mode = str(args.pop(0)).lower()
args = list(sys.argv) source_path = args.pop(0)
run_mode = '' dest_path = args.pop(0)
source_path = None except IndexError:
dest_path = None # We'll set the missing paths later
pass
# Parse args # Show usage
try: if re.search(r'-+(h|help)', str(sys.argv), re.IGNORECASE):
script_name = os.path.basename(args.pop(0)) show_usage(script_name)
run_mode = str(args.pop(0)).lower() exit_script()
source_path = args.pop(0)
dest_path = args.pop(0)
except IndexError:
# We'll set the missing paths later
pass
# Show usage # Start cloning/imaging
if re.search(r'-+(h|help)', str(sys.argv), re.IGNORECASE): if run_mode in ('clone', 'image'):
show_usage(script_name) menu_ddrescue(source_path, dest_path, run_mode)
exit_script() else:
if not re.search(r'^-*(h|help\?)', run_mode, re.IGNORECASE):
print_error('Invalid mode.')
# Start cloning/imaging # Done
if run_mode in ('clone', 'image'): print_standard('\nDone.')
menu_ddrescue(source_path, dest_path, run_mode) pause("Press Enter to exit...")
else: exit_script()
if not re.search(r'^-*(h|help\?)', run_mode, re.IGNORECASE): except GenericAbort:
print_error('Invalid mode.') abort()
except GenericError as ge:
# Done msg = 'Generic Error'
print_standard('\nDone.') if str(ge):
pause("Press Enter to exit...") msg = str(ge)
exit_script() print_error(msg)
except GenericAbort: abort()
abort() except SystemExit:
except GenericError as ge: pass
msg = 'Generic Error' except:
if str(ge): major_exception()
msg = str(ge)
print_error(msg)
abort()
except SystemExit:
pass
except:
major_exception()
# vim: sts=4 sw=4 ts=4 # vim: sts=2 sw=2 ts=2

View file

@ -6,61 +6,68 @@ from borrowed import acpi
from functions.common import * from functions.common import *
from os import environ from os import environ
# Variables
# STATIC VARIABLES
SLMGR = r'{}\System32\slmgr.vbs'.format(environ.get('SYSTEMROOT')) SLMGR = r'{}\System32\slmgr.vbs'.format(environ.get('SYSTEMROOT'))
def activate_with_bios(): def activate_with_bios():
"""Attempt to activate Windows with a key stored in the BIOS.""" """Attempt to activate Windows with a key stored in the BIOS."""
# Code borrowed from https://github.com/aeruder/get_win8key # Code borrowed from https://github.com/aeruder/get_win8key
##################################################### #####################################################
#script to query windows 8.x OEM key from PC firmware #script to query windows 8.x OEM key from PC firmware
#ACPI -> table MSDM -> raw content -> byte offset 56 to end #ACPI -> table MSDM -> raw content -> byte offset 56 to end
#ck, 03-Jan-2014 (christian@korneck.de) #ck, 03-Jan-2014 (christian@korneck.de)
##################################################### #####################################################
bios_key = None bios_key = None
table = b"MSDM" table = b"MSDM"
if acpi.FindAcpiTable(table) is True: if acpi.FindAcpiTable(table) is True:
rawtable = acpi.GetAcpiTable(table) rawtable = acpi.GetAcpiTable(table)
#http://msdn.microsoft.com/library/windows/hardware/hh673514 #http://msdn.microsoft.com/library/windows/hardware/hh673514
#byte offset 36 from beginning \ #byte offset 36 from beginning \
# = Microsoft 'software licensing data structure' \ # = Microsoft 'software licensing data structure' \
# / 36 + 20 bytes offset from beginning = Win Key # / 36 + 20 bytes offset from beginning = Win Key
bios_key = rawtable[56:len(rawtable)].decode("utf-8") bios_key = rawtable[56:len(rawtable)].decode("utf-8")
if bios_key is None: if bios_key is None:
raise BIOSKeyNotFoundError raise BIOSKeyNotFoundError
# Install Key # Install Key
cmd = ['cscript', '//nologo', SLMGR, '/ipk', bios_key] cmd = ['cscript', '//nologo', SLMGR, '/ipk', bios_key]
subprocess.run(cmd, check=False) subprocess.run(cmd, check=False)
sleep(5) sleep(5)
# Attempt activation # Attempt activation
cmd = ['cscript', '//nologo', SLMGR, '/ato'] cmd = ['cscript', '//nologo', SLMGR, '/ato']
subprocess.run(cmd, check=False) subprocess.run(cmd, check=False)
sleep(5) sleep(5)
# Check status
if not windows_is_activated():
raise Exception('Activation Failed')
# Check status
if not windows_is_activated():
raise Exception('Activation Failed')
def get_activation_string(): def get_activation_string():
"""Get activation status, returns str.""" """Get activation status, returns str."""
act_str = subprocess.run( act_str = subprocess.run(
['cscript', '//nologo', SLMGR, '/xpr'], check=False, ['cscript', '//nologo', SLMGR, '/xpr'], check=False,
stdout=subprocess.PIPE, stderr=subprocess.PIPE) stdout=subprocess.PIPE, stderr=subprocess.PIPE)
act_str = act_str.stdout.decode() act_str = act_str.stdout.decode()
act_str = act_str.splitlines() act_str = act_str.splitlines()
act_str = act_str[1].strip() act_str = act_str[1].strip()
return act_str return act_str
def windows_is_activated(): def windows_is_activated():
"""Check if Windows is activated via slmgr.vbs and return bool.""" """Check if Windows is activated via slmgr.vbs and return bool."""
activation_string = subprocess.run( activation_string = subprocess.run(
['cscript', '//nologo', SLMGR, '/xpr'], check=False, ['cscript', '//nologo', SLMGR, '/xpr'], check=False,
stdout=subprocess.PIPE, stderr=subprocess.PIPE) stdout=subprocess.PIPE, stderr=subprocess.PIPE)
activation_string = activation_string.stdout.decode() activation_string = activation_string.stdout.decode()
return bool(activation_string and 'permanent' in activation_string)
return bool(activation_string and 'permanent' in activation_string)
if __name__ == '__main__': if __name__ == '__main__':
print("This file is not meant to be called directly.") print("This file is not meant to be called directly.")
# vim: sts=2 sw=2 ts=2

View file

@ -4,202 +4,216 @@ import ctypes
from functions.disk import * from functions.disk import *
# Regex # Regex
REGEX_BAD_PATH_NAMES = re.compile( REGEX_BAD_PATH_NAMES = re.compile(
r'([<>:"/\|\?\*]' r'([<>:"/\|\?\*]'
r'|^(CON|PRN|AUX|NUL|COM\d*|LPT\d*)$)' r'|^(CON|PRN|AUX|NUL|COM\d*|LPT\d*)$)'
r'|^\s+' r'|^\s+'
r'|[\s\.]+$', r'|[\s\.]+$',
re.IGNORECASE) re.IGNORECASE)
def backup_partition(disk, par): def backup_partition(disk, par):
"""Create a backup image of a partition.""" """Create a backup image of a partition."""
if par.get('Image Exists', False) or par['Number'] in disk['Bad Partitions']: if (par.get('Image Exists', False)
raise GenericAbort or par['Number'] in disk['Bad Partitions']):
raise GenericAbort
cmd = [
global_vars['Tools']['wimlib-imagex'],
'capture',
'{}:\\'.format(par['Letter']),
par['Image Path'],
par['Image Name'], # Image name
par['Image Name'], # Image description
'--compress=none',
]
dest_dir = re.sub(r'(.*)\\.*$', r'\1', par['Image Path'], re.IGNORECASE)
os.makedirs(dest_dir, exist_ok=True)
run_program(cmd)
cmd = [
global_vars['Tools']['wimlib-imagex'],
'capture',
'{}:\\'.format(par['Letter']),
par['Image Path'],
par['Image Name'], # Image name
par['Image Name'], # Image description
'--compress=none',
]
dest_dir = re.sub(r'(.*)\\.*$', r'\1', par['Image Path'], re.IGNORECASE)
os.makedirs(dest_dir, exist_ok=True)
run_program(cmd)
def fix_path(path): def fix_path(path):
"""Replace invalid filename characters with underscores.""" """Replace invalid filename characters with underscores."""
local_drive = path[1:2] == ':' local_drive = path[1:2] == ':'
new_path = REGEX_BAD_PATH_NAMES.sub('_', path) new_path = REGEX_BAD_PATH_NAMES.sub('_', path)
if local_drive: if local_drive:
new_path = '{}:{}'.format(new_path[0:1], new_path[2:]) new_path = '{}:{}'.format(new_path[0:1], new_path[2:])
return new_path return new_path
def get_volume_display_name(mountpoint): def get_volume_display_name(mountpoint):
"""Get display name from volume mountpoint and label, returns str.""" """Get display name from volume mountpoint and label, returns str."""
name = mountpoint name = mountpoint
try: try:
kernel32 = ctypes.windll.kernel32 kernel32 = ctypes.windll.kernel32
vol_name_buffer = ctypes.create_unicode_buffer(1024) vol_name_buffer = ctypes.create_unicode_buffer(1024)
fs_name_buffer = ctypes.create_unicode_buffer(1024) fs_name_buffer = ctypes.create_unicode_buffer(1024)
serial_number = None serial_number = None
max_component_length = None max_component_length = None
file_system_flags = None file_system_flags = None
vol_info = kernel32.GetVolumeInformationW( vol_info = kernel32.GetVolumeInformationW(
ctypes.c_wchar_p(mountpoint), ctypes.c_wchar_p(mountpoint),
vol_name_buffer, vol_name_buffer,
ctypes.sizeof(vol_name_buffer), ctypes.sizeof(vol_name_buffer),
serial_number, serial_number,
max_component_length, max_component_length,
file_system_flags, file_system_flags,
fs_name_buffer, fs_name_buffer,
ctypes.sizeof(fs_name_buffer) ctypes.sizeof(fs_name_buffer)
) )
name = '{} "{}"'.format(name, vol_name_buffer.value) name = '{} "{}"'.format(name, vol_name_buffer.value)
except: except:
pass pass
return name
return name
def prep_disk_for_backup(destination, disk, backup_prefix): def prep_disk_for_backup(destination, disk, backup_prefix):
"""Gather details about the disk and its partitions. """Gather details about the disk and its partitions.
This includes partitions that can't be backed up, This includes partitions that can't be backed up,
whether backups already exist on the BACKUP_SERVER, whether backups already exist on the BACKUP_SERVER,
partition names/sizes/used space, etc.""" partition names/sizes/used space, etc."""
disk['Clobber Risk'] = [] disk['Clobber Risk'] = []
width = len(str(len(disk['Partitions']))) width = len(str(len(disk['Partitions'])))
# Get partition totals # Get partition totals
disk['Bad Partitions'] = [par['Number'] for par in disk['Partitions'] disk['Bad Partitions'] = [par['Number'] for par in disk['Partitions']
if is_bad_partition(par)] if is_bad_partition(par)]
num_valid_partitions = len(disk['Partitions']) - len(disk['Bad Partitions']) num_valid_partitions = len(disk['Partitions']) - len(disk['Bad Partitions'])
disk['Valid Partitions'] = num_valid_partitions disk['Valid Partitions'] = num_valid_partitions
if disk['Valid Partitions'] <= 0: if disk['Valid Partitions'] <= 0:
print_error('ERROR: No partitions can be backed up for this disk') print_error('ERROR: No partitions can be backed up for this disk')
raise GenericAbort raise GenericAbort
# Prep partitions # Prep partitions
for par in disk['Partitions']: for par in disk['Partitions']:
display = '{size} {fs}'.format( display = '{size} {fs}'.format(
num = par['Number'], num = par['Number'],
width = width, width = width,
size = par['Size'], size = par['Size'],
fs = par['FileSystem']) fs = par['FileSystem'])
if par['Number'] in disk['Bad Partitions']: if par['Number'] in disk['Bad Partitions']:
# Set display string using partition description & OS type # Set display string using partition description & OS type
display = '* {display}\t\t{q}{name}{q}\t{desc} ({os})'.format( display = '* {display}\t\t{q}{name}{q}\t{desc} ({os})'.format(
display = display, display = display,
q = '"' if par['Name'] != '' else '', q = '"' if par['Name'] != '' else '',
name = par['Name'], name = par['Name'],
desc = par['Description'], desc = par['Description'],
os = par['OS']) os = par['OS'])
else: else:
# Update info for WIM capturing # Update info for WIM capturing
par['Image Name'] = par['Name'] if par['Name'] else 'Unknown' par['Image Name'] = par['Name'] if par['Name'] else 'Unknown'
if 'IP' in destination: if 'IP' in destination:
par['Image Path'] = r'\\{}\{}\{}'.format( par['Image Path'] = r'\\{}\{}\{}'.format(
destination['IP'], destination['Share'], backup_prefix) destination['IP'], destination['Share'], backup_prefix)
else: else:
par['Image Path'] = r'{}:\{}'.format( par['Image Path'] = r'{}:\{}'.format(
destination['Letter'], backup_prefix) destination['Letter'], backup_prefix)
par['Image Path'] += r'\{}_{}.wim'.format( par['Image Path'] += r'\{}_{}.wim'.format(
par['Number'], par['Image Name']) par['Number'], par['Image Name'])
par['Image Path'] = fix_path(par['Image Path']) par['Image Path'] = fix_path(par['Image Path'])
# Check for existing backups # Check for existing backups
par['Image Exists'] = os.path.exists(par['Image Path']) par['Image Exists'] = os.path.exists(par['Image Path'])
if par['Image Exists']: if par['Image Exists']:
disk['Clobber Risk'].append(par['Number']) disk['Clobber Risk'].append(par['Number'])
display = '+ {}'.format(display) display = '+ {}'.format(display)
else: else:
display = ' {}'.format(display) display = ' {}'.format(display)
# Append rest of Display String for valid/clobber partitions # Append rest of Display String for valid/clobber partitions
display += ' (Used: {used})\t{q}{name}{q}'.format( display += ' (Used: {used})\t{q}{name}{q}'.format(
used = par['Used Space'], used = par['Used Space'],
q = '"' if par['Name'] != '' else '', q = '"' if par['Name'] != '' else '',
name = par['Name']) name = par['Name'])
# For all partitions # For all partitions
par['Display String'] = display par['Display String'] = display
# Set description for bad partitions
warnings = '\n'
if disk['Bad Partitions']:
warnings += '{} * Unsupported filesystem{}\n'.format(
COLORS['YELLOW'], COLORS['CLEAR'])
if disk['Clobber Risk']:
warnings += '{} + Backup exists on {}{}\n'.format(
COLORS['BLUE'], destination['Name'], COLORS['CLEAR'])
if disk['Bad Partitions'] or disk['Clobber Risk']:
warnings += '\n{}Marked partition(s) will NOT be backed up.{}\n'.format(
COLORS['YELLOW'], COLORS['CLEAR'])
disk['Backup Warnings'] = warnings
# Set description for bad partitions
warnings = '\n'
if disk['Bad Partitions']:
warnings += '{} * Unsupported filesystem{}\n'.format(
COLORS['YELLOW'], COLORS['CLEAR'])
if disk['Clobber Risk']:
warnings += '{} + Backup exists on {}{}\n'.format(
COLORS['BLUE'], destination['Name'], COLORS['CLEAR'])
if disk['Bad Partitions'] or disk['Clobber Risk']:
warnings += '\n{}Marked partition(s) will NOT be backed up.{}\n'.format(
COLORS['YELLOW'], COLORS['CLEAR'])
disk['Backup Warnings'] = warnings
def select_backup_destination(auto_select=True): def select_backup_destination(auto_select=True):
"""Select a backup destination from a menu, returns server dict.""" """Select a backup destination from a menu, returns server dict."""
destinations = [s for s in BACKUP_SERVERS if s['Mounted']] destinations = [s for s in BACKUP_SERVERS if s['Mounted']]
actions = [ actions = [
{'Name': 'Main Menu', 'Letter': 'M'}, {'Name': 'Main Menu', 'Letter': 'M'},
] ]
# Add local disks # Add local disks
for d in psutil.disk_partitions(): for d in psutil.disk_partitions():
if re.search(r'^{}'.format(global_vars['Env']['SYSTEMDRIVE']), d.mountpoint, re.IGNORECASE): if re.search(
# Skip current OS drive r'^{}'.format(global_vars['Env']['SYSTEMDRIVE']),
pass d.mountpoint,
elif 'fixed' in d.opts: re.IGNORECASE):
# Skip DVD, etc # Skip current OS drive
destinations.append({ pass
'Name': 'Local Disk - {}'.format( elif 'fixed' in d.opts:
get_volume_display_name(d.mountpoint)), # Skip DVD, etc
'Letter': re.sub(r'^(\w):\\.*$', r'\1', d.mountpoint), destinations.append({
}) 'Name': 'Local Disk - {}'.format(
get_volume_display_name(d.mountpoint)),
'Letter': re.sub(r'^(\w):\\.*$', r'\1', d.mountpoint),
})
# Size check # Size check
for dest in destinations: for dest in destinations:
if 'IP' in dest: if 'IP' in dest:
dest['Usage'] = shutil.disk_usage(r'\\{IP}\{Share}'.format(**dest)) dest['Usage'] = shutil.disk_usage(r'\\{IP}\{Share}'.format(**dest))
else:
dest['Usage'] = shutil.disk_usage('{}:\\'.format(dest['Letter']))
dest['Free Space'] = human_readable_size(dest['Usage'].free)
dest['Display Name'] = '{Name} ({Free Space} available)'.format(**dest)
# Bail
if not destinations:
print_warning('No backup destinations found.')
raise GenericAbort
# Skip menu?
if len(destinations) == 1 and auto_select:
return destinations[0]
selection = menu_select(
title = 'Where are we backing up to?',
main_entries = destinations,
action_entries = actions)
if selection == 'M':
raise GenericAbort
else: else:
return destinations[int(selection)-1] dest['Usage'] = shutil.disk_usage('{}:\\'.format(dest['Letter']))
dest['Free Space'] = human_readable_size(dest['Usage'].free)
dest['Display Name'] = '{Name} ({Free Space} available)'.format(**dest)
# Bail
if not destinations:
print_warning('No backup destinations found.')
raise GenericAbort
# Skip menu?
if len(destinations) == 1 and auto_select:
return destinations[0]
selection = menu_select(
title = 'Where are we backing up to?',
main_entries = destinations,
action_entries = actions)
if selection == 'M':
raise GenericAbort
else:
return destinations[int(selection)-1]
def verify_wim_backup(partition): def verify_wim_backup(partition):
"""Verify WIM integrity.""" """Verify WIM integrity."""
if not os.path.exists(partition['Image Path']): if not os.path.exists(partition['Image Path']):
raise PathNotFoundError raise PathNotFoundError
cmd = [ cmd = [
global_vars['Tools']['wimlib-imagex'], global_vars['Tools']['wimlib-imagex'],
'verify', 'verify',
partition['Image Path'], partition['Image Path'],
'--nocheck', '--nocheck',
] ]
run_program(cmd) run_program(cmd)
if __name__ == '__main__': if __name__ == '__main__':
print("This file is not meant to be called directly.") print("This file is not meant to be called directly.")
# vim: sts=2 sw=2 ts=2

View file

@ -1,48 +1,32 @@
# Wizard Kit: Functions - Browsers # Wizard Kit: Functions - Browsers
from functions.common import * from functions.common import *
from operator import itemgetter from operator import itemgetter
# Define other_results for later try_and_print # Define other_results for later try_and_print
browser_data = {} browser_data = {}
other_results = { other_results = {
'Error': { 'Error': {
'MultipleInstallationsError': 'Multiple installations detected', 'MultipleInstallationsError': 'Multiple installations detected',
}, },
'Warning': { 'Warning': {
'NotInstalledError': 'Not installed', 'NotInstalledError': 'Not installed',
'NoProfilesError': 'No profiles found', 'NoProfilesError': 'No profiles found',
}
} }
}
# 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 # STATIC VARIABLES
DEFAULT_HOMEPAGE = 'https://www.google.com/' DEFAULT_HOMEPAGE = 'https://www.google.com/'
IE_GALLERY = 'https://www.microsoft.com/en-us/iegallery' IE_GALLERY = 'https://www.microsoft.com/en-us/iegallery'
MOZILLA_PREFS = { MOZILLA_PREFS = {
'browser.search.defaultenginename': '"Google"', 'browser.search.defaultenginename': '"Google"',
'browser.search.defaultenginename.US': '"Google"', 'browser.search.defaultenginename.US': '"Google"',
'browser.search.geoSpecificDefaults': 'false', 'browser.search.geoSpecificDefaults': 'false',
'browser.startup.homepage': '"{}"'.format(DEFAULT_HOMEPAGE), 'browser.startup.homepage': '"{}"'.format(DEFAULT_HOMEPAGE),
'extensions.ui.lastCategory': '"addons://list/extension"', 'extensions.ui.lastCategory': '"addons://list/extension"',
} }
UBO_CHROME = 'https://chrome.google.com/webstore/detail/ublock-origin/cjpalhdlnbpafiamejdnhcphjbkeiagm?hl=en' UBO_CHROME = 'https://chrome.google.com/webstore/detail/ublock-origin/cjpalhdlnbpafiamejdnhcphjbkeiagm?hl=en'
UBO_CHROME_REG = r'Software\Wow6432Node\Google\Chrome\Extensions\cjpalhdlnbpafiamejdnhcphjbkeiagm' UBO_CHROME_REG = r'Software\Wow6432Node\Google\Chrome\Extensions\cjpalhdlnbpafiamejdnhcphjbkeiagm'
UBO_EXTRA_CHROME = 'https://chrome.google.com/webstore/detail/ublock-origin-extra/pgdnlhfefecpicbbihgmbmffkjpaplco?hl=en' UBO_EXTRA_CHROME = 'https://chrome.google.com/webstore/detail/ublock-origin-extra/pgdnlhfefecpicbbihgmbmffkjpaplco?hl=en'
@ -53,456 +37,505 @@ UBO_MOZILLA_REG = r'Software\Mozilla\Firefox\Extensions'
UBO_MOZILLA_REG_NAME = 'uBlock0@raymondhill.net' UBO_MOZILLA_REG_NAME = 'uBlock0@raymondhill.net'
UBO_OPERA = 'https://addons.opera.com/en/extensions/details/ublock/?display=en' UBO_OPERA = 'https://addons.opera.com/en/extensions/details/ublock/?display=en'
SUPPORTED_BROWSERS = { SUPPORTED_BROWSERS = {
'Internet Explorer': { 'Internet Explorer': {
'base': 'ie', 'base': 'ie',
'exe_name': 'iexplore.exe', 'exe_name': 'iexplore.exe',
'rel_install_path': 'Internet Explorer', 'rel_install_path': 'Internet Explorer',
'user_data_path': r'{USERPROFILE}\Favorites', 'user_data_path': r'{USERPROFILE}\Favorites',
}, },
'Google Chrome': { 'Google Chrome': {
'base': 'chromium', 'base': 'chromium',
'exe_name': 'chrome.exe', 'exe_name': 'chrome.exe',
'rel_install_path': r'Google\Chrome\Application', 'rel_install_path': r'Google\Chrome\Application',
'user_data_path': r'{LOCALAPPDATA}\Google\Chrome\User Data', 'user_data_path': r'{LOCALAPPDATA}\Google\Chrome\User Data',
}, },
'Google Chrome Canary': { 'Google Chrome Canary': {
'base': 'chromium', 'base': 'chromium',
'exe_name': 'chrome.exe', 'exe_name': 'chrome.exe',
'rel_install_path': r'Google\Chrome SxS\Application', 'rel_install_path': r'Google\Chrome SxS\Application',
'user_data_path': r'{LOCALAPPDATA}\Google\Chrome SxS\User Data', 'user_data_path': r'{LOCALAPPDATA}\Google\Chrome SxS\User Data',
}, },
'Mozilla Firefox': { 'Mozilla Firefox': {
'base': 'mozilla', 'base': 'mozilla',
'exe_name': 'firefox.exe', 'exe_name': 'firefox.exe',
'rel_install_path': 'Mozilla Firefox', 'rel_install_path': 'Mozilla Firefox',
'user_data_path': r'{APPDATA}\Mozilla\Firefox\Profiles', 'user_data_path': r'{APPDATA}\Mozilla\Firefox\Profiles',
}, },
'Mozilla Firefox Dev': { 'Mozilla Firefox Dev': {
'base': 'mozilla', 'base': 'mozilla',
'exe_name': 'firefox.exe', 'exe_name': 'firefox.exe',
'rel_install_path': 'Firefox Developer Edition', 'rel_install_path': 'Firefox Developer Edition',
'user_data_path': r'{APPDATA}\Mozilla\Firefox\Profiles', 'user_data_path': r'{APPDATA}\Mozilla\Firefox\Profiles',
}, },
'Opera': { 'Opera': {
'base': 'chromium', 'base': 'chromium',
'exe_name': 'launcher.exe', 'exe_name': 'launcher.exe',
'rel_install_path': 'Opera', 'rel_install_path': 'Opera',
'user_data_path': r'{APPDATA}\Opera Software\Opera Stable', 'user_data_path': r'{APPDATA}\Opera Software\Opera Stable',
}, },
'Opera Beta': { 'Opera Beta': {
'base': 'chromium', 'base': 'chromium',
'exe_name': 'launcher.exe', 'exe_name': 'launcher.exe',
'rel_install_path': 'Opera beta', 'rel_install_path': 'Opera beta',
'user_data_path': r'{APPDATA}\Opera Software\Opera Next', 'user_data_path': r'{APPDATA}\Opera Software\Opera Next',
}, },
'Opera Dev': { 'Opera Dev': {
'base': 'chromium', 'base': 'chromium',
'exe_name': 'launcher.exe', 'exe_name': 'launcher.exe',
'rel_install_path': 'Opera developer', 'rel_install_path': 'Opera developer',
'user_data_path': r'{APPDATA}\Opera Software\Opera Developer', 'user_data_path': r'{APPDATA}\Opera Software\Opera Developer',
}, },
} }
# 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(): def archive_all_users():
"""Create backups for all browsers for all users.""" """Create backups for all browsers for all users."""
users_root = r'{}\Users'.format(global_vars['Env']['SYSTEMDRIVE']) users_root = r'{}\Users'.format(global_vars['Env']['SYSTEMDRIVE'])
user_envs = [] user_envs = []
# Build list of valid users # Build list of valid users
for user_name in os.listdir(users_root): for user_name in os.listdir(users_root):
valid_user = True valid_user = True
if user_name in ('Default', 'Default User'): if user_name in ('Default', 'Default User'):
# Skip default users # Skip default users
continue continue
user_path = os.path.join(users_root, user_name) user_path = os.path.join(users_root, user_name)
appdata_local = os.path.join(user_path, r'AppData\Local') appdata_local = os.path.join(user_path, r'AppData\Local')
appdata_roaming = os.path.join(user_path, r'AppData\Roaming') appdata_roaming = os.path.join(user_path, r'AppData\Roaming')
valid_user &= os.path.exists(appdata_local) valid_user &= os.path.exists(appdata_local)
valid_user &= os.path.exists(appdata_roaming) valid_user &= os.path.exists(appdata_roaming)
if valid_user: if valid_user:
user_envs.append({ user_envs.append({
'USERNAME': user_name, 'USERNAME': user_name,
'USERPROFILE': user_path, 'USERPROFILE': user_path,
'APPDATA': appdata_roaming, 'APPDATA': appdata_roaming,
'LOCALAPPDATA': appdata_local}) 'LOCALAPPDATA': appdata_local})
# Backup browsers for all valid users # Backup browsers for all valid users
print_info('Backing up browsers') print_info('Backing up browsers')
for fake_env in sorted(user_envs, key=itemgetter('USERPROFILE')): for fake_env in sorted(user_envs, key=itemgetter('USERPROFILE')):
print_standard(' {}'.format(fake_env['USERNAME'])) print_standard(' {}'.format(fake_env['USERNAME']))
for b_k, b_v in sorted(SUPPORTED_BROWSERS.items()): for b_k, b_v in sorted(SUPPORTED_BROWSERS.items()):
if b_k == 'Mozilla Firefox Dev': if b_k == 'Mozilla Firefox Dev':
continue continue
source_path = b_v['user_data_path'].format(**fake_env) source_path = b_v['user_data_path'].format(**fake_env)
if not os.path.exists(source_path): if not os.path.exists(source_path):
continue continue
source_items = source_path + '*' source_items = source_path + '*'
archive_path = r'{BackupDir}\Browsers ({USERNAME})\{Date}'.format( archive_path = r'{BackupDir}\Browsers ({USERNAME})\{Date}'.format(
**global_vars, **fake_env) **global_vars, **fake_env)
os.makedirs(archive_path, exist_ok=True) os.makedirs(archive_path, exist_ok=True)
archive_path += r'\{}.7z'.format(b_k) archive_path += r'\{}.7z'.format(b_k)
cmd = [ cmd = [
global_vars['Tools']['SevenZip'],
'a', '-aoa', '-bso0', '-bse0', '-mx=1',
archive_path, source_items]
try_and_print(message='{}...'.format(b_k),
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'])
dest = r'{BackupDir}\Browsers ({USERNAME})\{Date}'.format(
**global_vars, **global_vars['Env'])
archive = r'{}\{}.7z'.format(dest, name)
os.makedirs(dest, exist_ok=True)
cmd = [
global_vars['Tools']['SevenZip'], global_vars['Tools']['SevenZip'],
'a', '-aoa', '-bso0', '-bse0', '-mx=1', 'a', '-aoa', '-bso0', '-bse0', '-mx=1',
'-mhe=on', '-p{}'.format(ARCHIVE_PASSWORD), archive_path, source_items]
archive, source] try_and_print(message='{}...'.format(b_k),
run_program(cmd) 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'])
dest = r'{BackupDir}\Browsers ({USERNAME})\{Date}'.format(
**global_vars, **global_vars['Env'])
archive = r'{}\{}.7z'.format(dest, name)
os.makedirs(dest, exist_ok=True)
cmd = [
global_vars['Tools']['SevenZip'],
'a', '-aoa', '-bso0', '-bse0', '-mx=1',
'-mhe=on', '-p{}'.format(ARCHIVE_PASSWORD),
archive, source]
run_program(cmd)
def backup_browsers(): def backup_browsers():
"""Create backup of all detected browser profiles.""" """Create backup of all detected browser profiles."""
for name in [k for k, v in sorted(browser_data.items()) if v['profiles']]: for name in [k for k, v in sorted(browser_data.items()) if v['profiles']]:
try_and_print(message='{}...'.format(name), try_and_print(message='{}...'.format(name),
function=archive_browser, name=name) function=archive_browser, name=name)
def clean_chromium_profile(profile): def clean_chromium_profile(profile):
"""Renames profile, creates a new folder, and copies the user data to it.""" """Recreate profile with only the essential user data.
if profile is None:
raise Exception This is done by renaming the existing profile, creating a new folder
backup_path = '{path}_{Date}.bak'.format( with the original name, then copying the essential files from the
path=profile['path'], **global_vars) backup folder. This way the original state is preserved in case
backup_path = non_clobber_rename(backup_path) something goes wrong.
shutil.move(profile['path'], backup_path) """
os.makedirs(profile['path'], exist_ok=True) if profile is None:
raise Exception
backup_path = '{path}_{Date}.bak'.format(
path=profile['path'], **global_vars)
backup_path = non_clobber_rename(backup_path)
shutil.move(profile['path'], backup_path)
os.makedirs(profile['path'], exist_ok=True)
# Restore essential files from backup_path
for entry in os.scandir(backup_path):
if REGEX_CHROMIUM_ITEMS.search(entry.name):
shutil.copy(entry.path, r'{}\{}'.format(
profile['path'], entry.name))
# Restore essential files from backup_path
for entry in os.scandir(backup_path):
if REGEX_CHROMIUM_ITEMS.search(entry.name):
shutil.copy(entry.path, r'{}\{}'.format(
profile['path'], entry.name))
def clean_internet_explorer(**kwargs): def clean_internet_explorer(**kwargs):
"""Uses the built-in function to reset IE and sets the homepage. """Uses the built-in function to reset IE and sets the homepage.
NOTE: kwargs set but unused as a workaround.""" NOTE: kwargs set but unused as a workaround."""
kill_process('iexplore.exe') kill_process('iexplore.exe')
run_program(['rundll32.exe', 'inetcpl.cpl,ResetIEtoDefaults'], check=False) run_program(['rundll32.exe', 'inetcpl.cpl,ResetIEtoDefaults'], check=False)
key = r'Software\Microsoft\Internet Explorer\Main' key = r'Software\Microsoft\Internet Explorer\Main'
# Set homepage
with winreg.OpenKey(HKCU, key, access=winreg.KEY_WRITE) as _key:
winreg.SetValueEx(_key, 'Start Page', 0,
winreg.REG_SZ, DEFAULT_HOMEPAGE)
try:
winreg.DeleteValue(_key, 'Secondary Start Pages')
except FileNotFoundError:
pass
# Set homepage
with winreg.OpenKey(HKCU, key, access=winreg.KEY_WRITE) as _key:
winreg.SetValueEx(_key, 'Start Page', 0,
winreg.REG_SZ, DEFAULT_HOMEPAGE)
try:
winreg.DeleteValue(_key, 'Secondary Start Pages')
except FileNotFoundError:
pass
def clean_mozilla_profile(profile): def clean_mozilla_profile(profile):
"""Renames profile, creates a new folder, and copies the user data to it.""" """Recreate profile with only the essential user data.
if profile is None:
raise Exception
backup_path = '{path}_{Date}.bak'.format(
path=profile['path'], **global_vars)
backup_path = non_clobber_rename(backup_path)
shutil.move(profile['path'], backup_path)
homepages = []
os.makedirs(profile['path'], exist_ok=True)
# Restore essential files from backup_path This is done by renaming the existing profile, creating a new folder
for entry in os.scandir(backup_path): with the original name, then copying the essential files from the
if REGEX_MOZILLA.search(entry.name): backup folder. This way the original state is preserved in case
if entry.is_dir(): something goes wrong.
shutil.copytree(entry.path, r'{}\{}'.format( """
profile['path'], entry.name)) if profile is None:
else: raise Exception
shutil.copy(entry.path, r'{}\{}'.format( backup_path = '{path}_{Date}.bak'.format(
profile['path'], entry.name)) path=profile['path'], **global_vars)
backup_path = non_clobber_rename(backup_path)
shutil.move(profile['path'], backup_path)
homepages = []
os.makedirs(profile['path'], exist_ok=True)
# Restore essential files from backup_path
for entry in os.scandir(backup_path):
if REGEX_MOZILLA.search(entry.name):
if entry.is_dir():
shutil.copytree(entry.path, r'{}\{}'.format(
profile['path'], entry.name))
else:
shutil.copy(entry.path, r'{}\{}'.format(
profile['path'], entry.name))
# Set profile defaults
with open(r'{path}\prefs.js'.format(**profile), 'a', encoding='ascii') as f:
for k, v in MOZILLA_PREFS.items():
f.write('user_pref("{}", {});\n'.format(k, v))
# Set profile defaults
with open(r'{path}\prefs.js'.format(**profile), 'a', encoding='ascii') as f:
for k, v in MOZILLA_PREFS.items():
f.write('user_pref("{}", {});\n'.format(k, v))
def get_browser_details(name): def get_browser_details(name):
"""Get installation status and profile details for all supported browsers.""" """Get installation and profile details for all supported browsers."""
browser = SUPPORTED_BROWSERS[name].copy() browser = SUPPORTED_BROWSERS[name].copy()
# Update user_data_path # Update user_data_path
browser['user_data_path'] = browser['user_data_path'].format( browser['user_data_path'] = browser['user_data_path'].format(
**global_vars['Env']) **global_vars['Env'])
# Find executable (if multiple files are found, the last one is used) # Find executable (if multiple files are found, the last one is used)
exe_path = None exe_path = None
num_installs = 0 num_installs = 0
for install_path in ['LOCALAPPDATA', 'PROGRAMFILES(X86)', 'PROGRAMFILES']: for install_path in ['LOCALAPPDATA', 'PROGRAMFILES(X86)', 'PROGRAMFILES']:
test_path = r'{install_path}\{rel_install_path}\{exe_name}'.format( test_path = r'{install_path}\{rel_install_path}\{exe_name}'.format(
install_path = global_vars['Env'].get(install_path, ''), install_path = global_vars['Env'].get(install_path, ''),
**browser) **browser)
if os.path.exists(test_path): if os.path.exists(test_path):
num_installs += 1 num_installs += 1
exe_path = test_path exe_path = test_path
# Find profile(s) # Find profile(s)
profiles = [] profiles = []
if browser['base'] == 'ie': if browser['base'] == 'ie':
profiles.append({'name': 'Default', 'path': None}) profiles.append({'name': 'Default', 'path': None})
elif 'Google Chrome' in name: elif 'Google Chrome' in name:
profiles.extend( profiles.extend(
get_chromium_profiles( get_chromium_profiles(
search_path=browser['user_data_path'])) search_path=browser['user_data_path']))
elif browser['base'] == 'mozilla': elif browser['base'] == 'mozilla':
dev = 'Dev' in name dev = 'Dev' in name
profiles.extend( profiles.extend(
get_mozilla_profiles( get_mozilla_profiles(
search_path=browser['user_data_path'], dev=dev)) search_path=browser['user_data_path'], dev=dev))
if exe_path and not dev and len(profiles) == 0: if exe_path and not dev and len(profiles) == 0:
# e.g. If Firefox is installed but no profiles were found. # e.g. If Firefox is installed but no profiles were found.
## Rename profiles.ini and create a new default profile ## Rename profiles.ini and create a new default profile
profiles_ini_path = browser['user_data_path'].replace( profiles_ini_path = browser['user_data_path'].replace(
'Profiles', 'profiles.ini') 'Profiles', 'profiles.ini')
if os.path.exists(profiles_ini_path): if os.path.exists(profiles_ini_path):
backup_path = '{path}_{Date}.bak'.format( backup_path = '{path}_{Date}.bak'.format(
path=profiles_ini_path, **global_vars) path=profiles_ini_path, **global_vars)
backup_path = non_clobber_rename(backup_path) backup_path = non_clobber_rename(backup_path)
shutil.move(profiles_ini_path, backup_path) shutil.move(profiles_ini_path, backup_path)
run_program([exe_path, '-createprofile', 'default'], check=False) run_program([exe_path, '-createprofile', 'default'], check=False)
profiles.extend( profiles.extend(
get_mozilla_profiles( get_mozilla_profiles(
search_path=browser['user_data_path'], dev=dev)) search_path=browser['user_data_path'], dev=dev))
elif 'Opera' in name: elif 'Opera' in name:
if os.path.exists(browser['user_data_path']): if os.path.exists(browser['user_data_path']):
profiles.append( profiles.append(
{'name': 'Default', 'path': browser['user_data_path']}) {'name': 'Default', 'path': browser['user_data_path']})
# Get homepages # Get homepages
if browser['base'] == 'ie': if browser['base'] == 'ie':
# IE is set to only have one profile above # IE is set to only have one profile above
profiles[0]['homepages'] = get_ie_homepages() profiles[0]['homepages'] = get_ie_homepages()
elif browser['base'] == 'mozilla': elif browser['base'] == 'mozilla':
for profile in profiles: for profile in profiles:
prefs_path = r'{path}\prefs.js'.format(**profile) prefs_path = r'{path}\prefs.js'.format(**profile)
profile['homepages'] = get_mozilla_homepages(prefs_path=prefs_path) profile['homepages'] = get_mozilla_homepages(prefs_path=prefs_path)
# Add to browser_data # Add to browser_data
browser_data[name] = browser browser_data[name] = browser
browser_data[name].update({ browser_data[name].update({
'exe_path': exe_path, 'exe_path': exe_path,
'profiles': profiles, 'profiles': profiles,
}) })
# Raise installation warnings (if any)
if num_installs == 0:
raise NotInstalledError
elif num_installs > 1 and browser['base'] != 'ie':
raise MultipleInstallationsError
# Raise installation warnings (if any)
if num_installs == 0:
raise NotInstalledError
elif num_installs > 1 and browser['base'] != 'ie':
raise MultipleInstallationsError
def get_chromium_profiles(search_path): def get_chromium_profiles(search_path):
"""Find any chromium-style profiles and return as a list of dicts.""" """Find any chromium-style profiles and return as a list of dicts."""
profiles = [] profiles = []
try: try:
for entry in os.scandir(search_path): for entry in os.scandir(search_path):
if entry.is_dir() and REGEX_CHROMIUM_PROFILE.search(entry.name): if entry.is_dir() and REGEX_CHROMIUM_PROFILE.search(entry.name):
profiles.append(entry) profiles.append(entry)
REGEX_PROFILE_BACKUP = r'\.\w+bak.*' REGEX_PROFILE_BACKUP = r'\.\w+bak.*'
profiles = [p for p in profiles if not REGEX_BACKUP.search(p.name)] profiles = [p for p in profiles if not REGEX_BACKUP.search(p.name)]
# Convert os.DirEntries to dicts # Convert os.DirEntries to dicts
profiles = [{'name': p.name, 'path': p.path} for p in profiles] profiles = [{'name': p.name, 'path': p.path} for p in profiles]
except Exception: except Exception:
pass pass
return profiles
return profiles
def get_ie_homepages(): def get_ie_homepages():
"""Read homepages from the registry and return as a list.""" """Read homepages from the registry and return as a list."""
homepages = [] homepages = []
main_page = '' main_page = ''
extra_pages = [] extra_pages = []
key = r'Software\Microsoft\Internet Explorer\Main' key = r'Software\Microsoft\Internet Explorer\Main'
with winreg.OpenKey(HKCU, key) as _key: with winreg.OpenKey(HKCU, key) as _key:
try: try:
main_page = winreg.QueryValueEx(_key, 'Start Page')[0] main_page = winreg.QueryValueEx(_key, 'Start Page')[0]
except FileNotFoundError: except FileNotFoundError:
pass pass
try: try:
extra_pages = winreg.QueryValueEx(_key, 'Secondary Start Pages')[0] extra_pages = winreg.QueryValueEx(_key, 'Secondary Start Pages')[0]
except FileNotFoundError: except FileNotFoundError:
pass pass
if main_page != '': if main_page != '':
homepages.append(main_page) homepages.append(main_page)
if len(extra_pages) > 0: if len(extra_pages) > 0:
homepages.extend(extra_pages) homepages.extend(extra_pages)
# Remove all curly braces
homepages = [h.replace('{', '').replace('}', '') for h in homepages]
return homepages
# Remove all curly braces
homepages = [h.replace('{', '').replace('}', '') for h in homepages]
return homepages
def get_mozilla_homepages(prefs_path): def get_mozilla_homepages(prefs_path):
"""Read homepages from prefs.js and return as a list.""" """Read homepages from prefs.js and return as a list."""
homepages = [] homepages = []
try: try:
with open(prefs_path, 'r') as f: with open(prefs_path, 'r') as f:
search = re.search( search = re.search(
r'browser\.startup\.homepage", "([^"]*)"', r'browser\.startup\.homepage", "([^"]*)"',
f.read(), re.IGNORECASE) f.read(), re.IGNORECASE)
if search: if search:
homepages = search.group(1).split('|') homepages = search.group(1).split('|')
except Exception: except Exception:
pass pass
return homepages
return homepages
def get_mozilla_profiles(search_path, dev=False): def get_mozilla_profiles(search_path, dev=False):
"""Find any mozilla-style profiles and return as a list of dicts.""" """Find any mozilla-style profiles and return as a list of dicts."""
profiles = [] profiles = []
try: try:
for entry in os.scandir(search_path): for entry in os.scandir(search_path):
if entry.is_dir(): if entry.is_dir():
if 'dev-edition' in entry.name: if 'dev-edition' in entry.name:
# NOTE: Not always present which can lead # NOTE: Not always present which can lead
# to Dev profiles being marked as non-Dev # to Dev profiles being marked as non-Dev
## NOTE 2: It is possible that a non-Dev profile ## NOTE 2: It is possible that a non-Dev profile
## to be created with 'dev-edition' in the name. ## to be created with 'dev-edition' in the name.
## (It wouldn't make sense, but possible) ## (It wouldn't make sense, but possible)
if dev: if dev:
profiles.append(entry) profiles.append(entry)
elif not dev: elif not dev:
profiles.append(entry) profiles.append(entry)
profiles = [p for p in profiles if not REGEX_BACKUP.search(p.name)] profiles = [p for p in profiles if not REGEX_BACKUP.search(p.name)]
# Convert os.DirEntries to dicts # Convert os.DirEntries to dicts
profiles = [{'name': p.name, 'path': p.path} for p in profiles] profiles = [{'name': p.name, 'path': p.path} for p in profiles]
except Exception: except Exception:
pass pass
return profiles
return profiles
def install_adblock(indent=8, width=32, just_firefox=False): def install_adblock(indent=8, width=32, just_firefox=False):
"""Install adblock for all supported browsers.""" """Install adblock for all supported browsers."""
for browser in sorted(browser_data): for browser in sorted(browser_data):
if just_firefox and browser_data[browser]['base'] != 'mozilla': if just_firefox and browser_data[browser]['base'] != 'mozilla':
continue continue
exe_path = browser_data[browser].get('exe_path', None) exe_path = browser_data[browser].get('exe_path', None)
function=run_program function=run_program
if not exe_path: if not exe_path:
if browser_data[browser]['profiles']: if browser_data[browser]['profiles']:
print_standard( print_standard(
'{indent}{browser:<{width}}'.format( '{indent}{browser:<{width}}'.format(
indent=' '*indent, width=width, browser=browser+'...'), indent=' '*indent, width=width, browser=browser+'...'),
end='', flush=True) end='', flush=True)
print_warning('Profile(s) detected but browser not installed', print_warning('Profile(s) detected but browser not installed',
timestamp=False) timestamp=False)
else: else:
# Only warn if profile(s) are detected. # Only warn if profile(s) are detected.
pass pass
else:
# Set urls to open
urls = []
if browser_data[browser]['base'] == 'chromium':
if browser == 'Google Chrome':
# Check for system exensions
try:
winreg.QueryValue(HKLM, UBO_CHROME_REG)
except FileNotFoundError:
urls.append(UBO_CHROME)
try:
winreg.QueryValue(HKLM, UBO_EXTRA_CHROME_REG)
except FileNotFoundError:
urls.append(UBO_EXTRA_CHROME)
if len(urls) == 0:
urls = ['chrome://extensions']
elif 'Opera' in browser:
urls.append(UBO_OPERA)
else: else:
# Set urls to open urls.append(UBO_CHROME)
urls = [] urls.append(UBO_EXTRA_CHROME)
if browser_data[browser]['base'] == 'chromium':
if browser == 'Google Chrome':
# Check for system exensions
try:
winreg.QueryValue(HKLM, UBO_CHROME_REG)
except FileNotFoundError:
urls.append(UBO_CHROME)
try:
winreg.QueryValue(HKLM, UBO_EXTRA_CHROME_REG)
except FileNotFoundError:
urls.append(UBO_EXTRA_CHROME)
if len(urls) == 0: elif browser_data[browser]['base'] == 'mozilla':
urls = ['chrome://extensions'] # Check for system extensions
elif 'Opera' in browser: try:
urls.append(UBO_OPERA) with winreg.OpenKey(HKLM, UBO_MOZILLA_REG) as key:
else: winreg.QueryValueEx(key, UBO_MOZILLA_REG_NAME)
urls.append(UBO_CHROME) except FileNotFoundError:
urls.append(UBO_EXTRA_CHROME) urls = [UBO_MOZILLA]
else:
if os.path.exists(UBO_MOZZILA_PATH):
urls = ['about:addons']
else:
urls = [UBO_MOZILLA]
elif browser_data[browser]['base'] == 'mozilla': elif browser_data[browser]['base'] == 'ie':
# Check for system extensions urls.append(IE_GALLERY)
try: function=popen_program
with winreg.OpenKey(HKLM, UBO_MOZILLA_REG) as key:
winreg.QueryValueEx(key, UBO_MOZILLA_REG_NAME)
except FileNotFoundError:
urls = [UBO_MOZILLA]
else:
if os.path.exists(UBO_MOZZILA_PATH):
urls = ['about:addons']
else:
urls = [UBO_MOZILLA]
elif browser_data[browser]['base'] == 'ie': # By using check=False we're skipping any return codes so
urls.append(IE_GALLERY) # it should only fail if the program can't be run
function=popen_program # (or can't be found).
# In other words, this isn't tracking the addon/extension's
# installation status.
try_and_print(message='{}...'.format(browser),
indent=indent, width=width,
cs='Done', function=function,
cmd=[exe_path, *urls], check=False)
# By using check=False we're skipping any return codes so
# it should only fail if the program can't be run
# (or can't be found).
# In other words, this isn't tracking the addon/extension's
# installation status.
try_and_print(message='{}...'.format(browser),
indent=indent, width=width,
cs='Done', function=function,
cmd=[exe_path, *urls], check=False)
def list_homepages(indent=8, width=32): def list_homepages(indent=8, width=32):
"""List current homepages for reference.""" """List current homepages for reference."""
browser_list = [k for k, v in sorted(browser_data.items()) if v['exe_path']]
for browser in browser_list:
# Skip Chromium-based browsers
if browser_data[browser]['base'] == 'chromium':
print_info(
'{indent}{browser:<{width}}'.format(
indent=' '*indent, width=width, browser=browser+'...'),
end='', flush=True)
print_warning('Not implemented', timestamp=False)
continue
for browser in [k for k, v in sorted(browser_data.items()) if v['exe_path']]: # All other browsers
# Skip Chromium-based browsers print_info('{indent}{browser:<{width}}'.format(
if browser_data[browser]['base'] == 'chromium': indent=' '*indent, width=width, browser=browser+'...'))
print_info( for profile in browser_data[browser].get('profiles', []):
'{indent}{browser:<{width}}'.format( name = profile.get('name', '?')
indent=' '*indent, width=width, browser=browser+'...'), homepages = profile.get('homepages', [])
end='', flush=True) if len(homepages) == 0:
print_warning('Not implemented', timestamp=False) print_standard(
continue '{indent}{name:<{width}}'.format(
indent=' '*indent, width=width, name=name),
end='', flush=True)
print_warning('None found', timestamp=False)
else:
for page in homepages:
print_standard('{indent}{name:<{width}}{page}'.format(
indent=' '*indent, width=width, name=name, page=page))
# All other browsers
print_info('{indent}{browser:<{width}}'.format(
indent=' '*indent, width=width, browser=browser+'...'))
for profile in browser_data[browser].get('profiles', []):
name = profile.get('name', '?')
homepages = profile.get('homepages', [])
if len(homepages) == 0:
print_standard(
'{indent}{name:<{width}}'.format(
indent=' '*indent, width=width, name=name),
end='', flush=True)
print_warning('None found', timestamp=False)
else:
for page in homepages:
print_standard('{indent}{name:<{width}}{page}'.format(
indent=' '*indent, width=width, name=name, page=page))
def reset_browsers(indent=8, width=32): def reset_browsers(indent=8, width=32):
"""Reset all detected browsers to safe defaults.""" """Reset all detected browsers to safe defaults."""
for browser in [k for k, v in sorted(browser_data.items()) if v['profiles']]: browser_list = [k for k, v in sorted(browser_data.items()) if v['profiles']]
print_info('{indent}{name}'.format(indent=' '*indent, name=browser)) for browser in browser_list:
for profile in browser_data[browser]['profiles']: print_info('{indent}{name}'.format(indent=' '*indent, name=browser))
if browser_data[browser]['base'] == 'chromium': for profile in browser_data[browser]['profiles']:
function = clean_chromium_profile if browser_data[browser]['base'] == 'chromium':
elif browser_data[browser]['base'] == 'ie': function = clean_chromium_profile
function = clean_internet_explorer elif browser_data[browser]['base'] == 'ie':
elif browser_data[browser]['base'] == 'mozilla': function = clean_internet_explorer
function = clean_mozilla_profile elif browser_data[browser]['base'] == 'mozilla':
try_and_print( function = clean_mozilla_profile
message='{}...'.format(profile['name']), try_and_print(
indent=indent, width=width, function=function, message='{}...'.format(profile['name']),
other_results=other_results, profile=profile) indent=indent, width=width, function=function,
other_results=other_results, profile=profile)
def scan_for_browsers(just_firefox=False): def scan_for_browsers(just_firefox=False):
"""Scan system for any supported browsers.""" """Scan system for any supported browsers."""
for name, details in sorted(SUPPORTED_BROWSERS.items()): for name, details in sorted(SUPPORTED_BROWSERS.items()):
if just_firefox and details['base'] != 'mozilla': if just_firefox and details['base'] != 'mozilla':
continue continue
try_and_print(message='{}...'.format(name), try_and_print(message='{}...'.format(name),
function=get_browser_details, cs='Detected', function=get_browser_details, cs='Detected',
other_results=other_results, name=name) other_results=other_results, name=name)
if __name__ == '__main__': if __name__ == '__main__':
print("This file is not meant to be called directly.") print("This file is not meant to be called directly.")
# vim: sts=2 sw=2 ts=2

View file

@ -2,128 +2,135 @@
from functions.common import * from functions.common import *
def cleanup_adwcleaner(): def cleanup_adwcleaner():
"""Move AdwCleaner folders into the ClientDir.""" """Move AdwCleaner folders into the ClientDir."""
source_path = r'{SYSTEMDRIVE}\AdwCleaner'.format(**global_vars['Env']) source_path = r'{SYSTEMDRIVE}\AdwCleaner'.format(**global_vars['Env'])
source_quarantine = r'{}\Quarantine'.format(source_path) source_quarantine = r'{}\Quarantine'.format(source_path)
# Quarantine # Quarantine
if os.path.exists(source_quarantine): if os.path.exists(source_quarantine):
os.makedirs(global_vars['QuarantineDir'], exist_ok=True) os.makedirs(global_vars['QuarantineDir'], exist_ok=True)
dest_name = r'{QuarantineDir}\AdwCleaner_{Date-Time}'.format( dest_name = r'{QuarantineDir}\AdwCleaner_{Date-Time}'.format(
**global_vars) **global_vars)
dest_name = non_clobber_rename(dest_name) dest_name = non_clobber_rename(dest_name)
shutil.move(source_quarantine, dest_name) shutil.move(source_quarantine, dest_name)
# Delete source folder if empty # Delete source folder if empty
delete_empty_folders(source_path) delete_empty_folders(source_path)
# Main folder
if os.path.exists(source_path):
os.makedirs(global_vars['LogDir'], exist_ok=True)
dest_name = r'{LogDir}\Tools\AdwCleaner'.format(
**global_vars)
dest_name = non_clobber_rename(dest_name)
shutil.move(source_path, dest_name)
# Main folder
if os.path.exists(source_path):
os.makedirs(global_vars['LogDir'], exist_ok=True)
dest_name = r'{LogDir}\Tools\AdwCleaner'.format(
**global_vars)
dest_name = non_clobber_rename(dest_name)
shutil.move(source_path, dest_name)
def cleanup_cbs(dest_folder): def cleanup_cbs(dest_folder):
"""Safely cleanup a known CBS archive bug under Windows 7. """Safely cleanup a known CBS archive bug under Windows 7.
If a CbsPersist file is larger than 2 Gb then the auto archive feature If a CbsPersist file is larger than 2 Gb then the auto archive feature
continually fails and will fill up the system drive with temp files. continually fails and will fill up the system drive with temp files.
This function moves the temp files and CbsPersist file to a temp folder, This function moves the temp files and CbsPersist file to a temp folder,
compresses the CbsPersist files with 7-Zip, and then opens the temp folder compresses the CbsPersist files with 7-Zip, and then opens the temp folder
for the user to manually save the backup files and delete the temp files. for the user to manually save the backup files and delete the temp files.
""" """
backup_folder = r'{dest_folder}\CbsFix'.format(dest_folder=dest_folder) backup_folder = r'{dest_folder}\CbsFix'.format(dest_folder=dest_folder)
temp_folder = r'{backup_folder}\Temp'.format(backup_folder=backup_folder) temp_folder = r'{backup_folder}\Temp'.format(backup_folder=backup_folder)
os.makedirs(backup_folder, exist_ok=True) os.makedirs(backup_folder, exist_ok=True)
os.makedirs(temp_folder, exist_ok=True) os.makedirs(temp_folder, exist_ok=True)
# Move files into temp folder # Move files into temp folder
cbs_path = r'{SYSTEMROOT}\Logs\CBS'.format(**global_vars['Env']) cbs_path = r'{SYSTEMROOT}\Logs\CBS'.format(**global_vars['Env'])
for entry in os.scandir(cbs_path): for entry in os.scandir(cbs_path):
# CbsPersist files # CbsPersist files
if entry.name.lower().startswith('cbspersist'): if entry.name.lower().startswith('cbspersist'):
dest_name = r'{}\{}'.format(temp_folder, entry.name) dest_name = r'{}\{}'.format(temp_folder, entry.name)
dest_name = non_clobber_rename(dest_name) dest_name = non_clobber_rename(dest_name)
shutil.move(entry.path, dest_name) shutil.move(entry.path, dest_name)
temp_path = r'{SYSTEMROOT}\Temp'.format(**global_vars['Env']) temp_path = r'{SYSTEMROOT}\Temp'.format(**global_vars['Env'])
for entry in os.scandir(temp_path): for entry in os.scandir(temp_path):
# cab_ files # cab_ files
if entry.name.lower().startswith('cab_'): if entry.name.lower().startswith('cab_'):
dest_name = r'{}\{}'.format(temp_folder, entry.name) dest_name = r'{}\{}'.format(temp_folder, entry.name)
dest_name = non_clobber_rename(dest_name) dest_name = non_clobber_rename(dest_name)
shutil.move(entry.path, dest_name) shutil.move(entry.path, dest_name)
# Compress CbsPersist files with 7-Zip
cmd = [
global_vars['Tools']['SevenZip'],
'a', '-t7z', '-mx=3', '-bso0', '-bse0',
r'{}\CbsPersists.7z'.format(backup_folder),
r'{}\CbsPersist*'.format(temp_folder)]
run_program(cmd)
# Compress CbsPersist files with 7-Zip
cmd = [
global_vars['Tools']['SevenZip'],
'a', '-t7z', '-mx=3', '-bso0', '-bse0',
r'{}\CbsPersists.7z'.format(backup_folder),
r'{}\CbsPersist*'.format(temp_folder)]
run_program(cmd)
def cleanup_desktop(): def cleanup_desktop():
"""Move known backup files and reports into the ClientDir.""" """Move known backup files and reports into the ClientDir."""
dest_folder = r'{LogDir}\Tools'.format(**global_vars) dest_folder = r'{LogDir}\Tools'.format(**global_vars)
os.makedirs(dest_folder, exist_ok=True) os.makedirs(dest_folder, exist_ok=True)
desktop_path = r'{USERPROFILE}\Desktop'.format(**global_vars['Env']) desktop_path = r'{USERPROFILE}\Desktop'.format(**global_vars['Env'])
for entry in os.scandir(desktop_path): for entry in os.scandir(desktop_path):
# JRT, RKill, Shortcut cleaner # JRT, RKill, Shortcut cleaner
if re.search(r'^(JRT|RKill|sc-cleaner)', entry.name, re.IGNORECASE): if re.search(r'^(JRT|RKill|sc-cleaner)', entry.name, re.IGNORECASE):
dest_name = r'{}\{}'.format(dest_folder, entry.name) dest_name = r'{}\{}'.format(dest_folder, entry.name)
dest_name = non_clobber_rename(dest_name) dest_name = non_clobber_rename(dest_name)
shutil.move(entry.path, dest_name) shutil.move(entry.path, dest_name)
# Remove dir if empty
delete_empty_folders(dest_folder)
# Remove dir if empty
delete_empty_folders(dest_folder)
def delete_empty_folders(folder_path): def delete_empty_folders(folder_path):
"""Delete all empty folders in path (depth first).""" """Delete all empty folders in path (depth first)."""
if not os.path.exists(folder_path) or not os.path.isdir(folder_path): if not os.path.exists(folder_path) or not os.path.isdir(folder_path):
# Bail early (silently) # Bail early (silently)
return return
# Delete empty subfolders first # Delete empty subfolders first
for item in os.scandir(folder_path): for item in os.scandir(folder_path):
if item.is_dir(): if item.is_dir():
delete_empty_folders(item.path) delete_empty_folders(item.path)
# Remove top folder
try:
os.rmdir(folder_path)
except OSError:
pass
# Remove top folder
try:
os.rmdir(folder_path)
except OSError:
pass
def delete_registry_key(hive, key, recurse=False): def delete_registry_key(hive, key, recurse=False):
"""Delete a registry key and all it's subkeys.""" """Delete a registry key and all it's subkeys."""
access = winreg.KEY_ALL_ACCESS access = winreg.KEY_ALL_ACCESS
try: try:
if recurse: if recurse:
# Delete all subkeys first # Delete all subkeys first
with winreg.OpenKeyEx(hive, key, 0, access) as k: with winreg.OpenKeyEx(hive, key, 0, access) as k:
key_info = winreg.QueryInfoKey(k) key_info = winreg.QueryInfoKey(k)
for x in range(key_info[0]): for x in range(key_info[0]):
subkey = r'{}\{}'.format(key, winreg.EnumKey(k, 0)) subkey = r'{}\{}'.format(key, winreg.EnumKey(k, 0))
delete_registry_key(hive, subkey) delete_registry_key(hive, subkey)
# Delete key
winreg.DeleteKey(hive, key)
except FileNotFoundError:
# Ignore
pass
# Delete key
winreg.DeleteKey(hive, key)
except FileNotFoundError:
# Ignore
pass
def delete_registry_value(hive, key, value): def delete_registry_value(hive, key, value):
"""Delete a registry value.""" """Delete a registry value."""
access = winreg.KEY_ALL_ACCESS access = winreg.KEY_ALL_ACCESS
with winreg.OpenKeyEx(hive, key, 0, access) as k: with winreg.OpenKeyEx(hive, key, 0, access) as k:
winreg.DeleteValue(k, value) winreg.DeleteValue(k, value)
if __name__ == '__main__': if __name__ == '__main__':
print("This file is not meant to be called directly.") print("This file is not meant to be called directly.")
# vim: sts=4 sw=4 ts=4 # vim: sts=2 sw=2 ts=2

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,189 +0,0 @@
# Wizard Kit: Functions - Diagnostics
import ctypes
from functions.common import *
# STATIC VARIABLES
AUTORUNS_SETTINGS = {
r'Software\Sysinternals\AutoRuns': {
'checkvirustotal': 1,
'EulaAccepted': 1,
'shownomicrosoft': 1,
'shownowindows': 1,
'showonlyvirustotal': 1,
'submitvirustotal': 0,
'verifysignatures': 1,
},
r'Software\Sysinternals\AutoRuns\SigCheck': {
'EulaAccepted': 1,
},
r'Software\Sysinternals\AutoRuns\Streams': {
'EulaAccepted': 1,
},
r'Software\Sysinternals\AutoRuns\VirusTotal': {
'VirusTotalTermsAccepted': 1,
},
}
def check_connection():
"""Check if the system is online and optionally abort the script."""
while True:
result = try_and_print(message='Ping test...', function=ping, cs='OK')
if result['CS']:
break
if not ask('ERROR: System appears offline, try again?'):
if ask('Continue anyway?'):
break
else:
abort()
def check_secure_boot_status(show_alert=False):
"""Checks UEFI Secure Boot status via PowerShell."""
boot_mode = get_boot_mode()
cmd = ['PowerShell', '-Command', 'Confirm-SecureBootUEFI']
result = run_program(cmd, check=False)
# Check results
if result.returncode == 0:
out = result.stdout.decode()
if 'True' in out:
# It's on, do nothing
return
elif 'False' in out:
if show_alert:
show_alert_box('Secure Boot DISABLED')
raise SecureBootDisabledError
else:
if show_alert:
show_alert_box('Secure Boot status UNKNOWN')
raise SecureBootUnknownError
else:
if boot_mode != 'UEFI':
if (show_alert and
global_vars['OS']['Version'] in ('8', '8.1', '10')):
# OS supports Secure Boot
show_alert_box('Secure Boot DISABLED\n\nOS installed LEGACY')
raise OSInstalledLegacyError
else:
# Check error message
err = result.stderr.decode()
if 'Cmdlet not supported' in err:
if show_alert:
show_alert_box('Secure Boot UNAVAILABLE?')
raise SecureBootNotAvailError
else:
if show_alert:
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
firmware_type = ctypes.c_uint()
# Get value from kernel32 API
try:
kernel.GetFirmwareType(ctypes.byref(firmware_type))
except:
# Just set to zero
firmware_type = ctypes.c_uint(0)
# Set return value
type_str = 'Unknown'
if firmware_type.value == 1:
type_str = 'Legacy'
elif firmware_type.value == 2:
type_str = 'UEFI'
return type_str
def run_autoruns():
"""Run AutoRuns in the background with VirusTotal checks enabled."""
extract_item('Autoruns', filter='autoruns*', silent=True)
# Update AutoRuns settings before running
for path, settings in AUTORUNS_SETTINGS.items():
winreg.CreateKey(HKCU, path)
with winreg.OpenKey(HKCU, path, access=winreg.KEY_WRITE) as key:
for name, value in settings.items():
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)
for bit in [32, 64]:
# Configure
source = r'{}\general.ini'.format(path)
dest = r'{}\HWiNFO{}.ini'.format(path, bit)
shutil.copy(source, dest)
with open(dest, 'a') as f:
f.write('SensorsOnly=1\n')
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)
cmd = [global_vars['Tools']['XMPlay'],
r'{BinDir}\XMPlay\music.7z'.format(**global_vars)]
# Unmute audio first
extract_item('NirCmd', silent=True)
run_nircmd('mutesysvolume', '0')
# Open XMPlay
popen_program(cmd)
def run_hitmanpro():
"""Run HitmanPro in the background."""
extract_item('HitmanPro', silent=True)
cmd = [
global_vars['Tools']['HitmanPro'],
'/quiet', '/noinstall', '/noupload',
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)
# credit to /u/cuddlychops06
prev_dir = os.getcwd()
extract_item('ProcessKiller', silent=True)
os.chdir(r'{BinDir}\ProcessKiller'.format(**global_vars))
run_program(['ProcessKiller.exe', '/silent'], check=False)
os.chdir(prev_dir)
def run_rkill():
"""Run RKill and cleanup afterwards."""
extract_item('RKill', silent=True)
cmd = [
global_vars['Tools']['RKill'],
'-s', '-l', r'{LogDir}\Tools\RKill.log'.format(**global_vars),
'-new_console:n', '-new_console:s33V']
run_program(cmd, check=False)
wait_for_process('RKill')
# RKill cleanup
desktop_path = r'{USERPROFILE}\Desktop'.format(**global_vars['Env'])
if os.path.exists(desktop_path):
for item in os.scandir(desktop_path):
if re.search(r'^RKill', item.name, re.IGNORECASE):
dest = r'{LogDir}\Tools\{name}'.format(
name=dest, **global_vars)
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.")

View file

@ -1,395 +1,414 @@
# Wizard Kit: Functions - Disk # Wizard Kit: Functions - Disk
from functions.common import * from functions.common import *
from functions import partition_uids from settings.partition_uids import *
# Regex # Regex
REGEX_BAD_PARTITION = re.compile(r'(RAW|Unknown)', re.IGNORECASE) REGEX_BAD_PARTITION = re.compile(r'(RAW|Unknown)', re.IGNORECASE)
REGEX_DISK_GPT = re.compile( REGEX_DISK_GPT = re.compile(
r'Disk ID: {[A-Z0-9]+-[A-Z0-9]+-[A-Z0-9]+-[A-Z0-9]+-[A-Z0-9]+}', r'Disk ID: {[A-Z0-9]+-[A-Z0-9]+-[A-Z0-9]+-[A-Z0-9]+-[A-Z0-9]+}',
re.IGNORECASE) re.IGNORECASE)
REGEX_DISK_MBR = re.compile(r'Disk ID: [A-Z0-9]+', re.IGNORECASE) REGEX_DISK_MBR = re.compile(r'Disk ID: [A-Z0-9]+', re.IGNORECASE)
REGEX_DISK_RAW = re.compile(r'Disk ID: 00000000', re.IGNORECASE) REGEX_DISK_RAW = re.compile(r'Disk ID: 00000000', re.IGNORECASE)
def assign_volume_letters(): def assign_volume_letters():
"""Assign a volume letter to all available volumes.""" """Assign a volume letter to all available volumes."""
remove_volume_letters() remove_volume_letters()
# Write script # Write script
script = [] script = []
for vol in get_volumes(): for vol in get_volumes():
script.append('select volume {}'.format(vol['Number'])) script.append('select volume {}'.format(vol['Number']))
script.append('assign') script.append('assign')
# Run
run_diskpart(script)
# Run
run_diskpart(script)
def get_boot_mode(): def get_boot_mode():
"""Check if the boot mode was UEFI or legacy.""" """Check if the boot mode was UEFI or legacy."""
boot_mode = 'Legacy' boot_mode = 'Legacy'
try: try:
reg_key = winreg.OpenKey( reg_key = winreg.OpenKey(
winreg.HKEY_LOCAL_MACHINE, r'System\CurrentControlSet\Control') winreg.HKEY_LOCAL_MACHINE, r'System\CurrentControlSet\Control')
reg_value = winreg.QueryValueEx(reg_key, 'PEFirmwareType')[0] reg_value = winreg.QueryValueEx(reg_key, 'PEFirmwareType')[0]
if reg_value == 2: if reg_value == 2:
boot_mode = 'UEFI' boot_mode = 'UEFI'
except: except:
boot_mode = 'Unknown' boot_mode = 'Unknown'
return boot_mode
return boot_mode
def get_disk_details(disk): def get_disk_details(disk):
"""Get disk details using DiskPart.""" """Get disk details using DiskPart."""
details = {} details = {}
script = [ script = [
'select disk {}'.format(disk['Number']), 'select disk {}'.format(disk['Number']),
'detail disk'] 'detail disk']
# Run # Run
try: try:
result = run_diskpart(script) result = run_diskpart(script)
except subprocess.CalledProcessError: except subprocess.CalledProcessError:
pass pass
else: else:
output = result.stdout.decode().strip() output = result.stdout.decode().strip()
# Remove empty lines # Remove empty lines
tmp = [s.strip() for s in output.splitlines() if s.strip() != ''] tmp = [s.strip() for s in output.splitlines() if s.strip() != '']
# Set disk name # Set disk name
details['Name'] = tmp[4] details['Name'] = tmp[4]
# Split each line on ':' skipping those without ':' # Split each line on ':' skipping those without ':'
tmp = [s.split(':') for s in tmp if ':' in s] tmp = [s.split(':') for s in tmp if ':' in s]
# Add key/value pairs to the details variable and return dict # Add key/value pairs to the details variable and return dict
details.update({key.strip(): value.strip() for (key, value) in tmp}) details.update({key.strip(): value.strip() for (key, value) in tmp})
return details
return details
def get_disks(): def get_disks():
"""Get list of attached disks using DiskPart.""" """Get list of attached disks using DiskPart."""
disks = [] disks = []
try: try:
# Run script # Run script
result = run_diskpart(['list disk']) result = run_diskpart(['list disk'])
except subprocess.CalledProcessError: except subprocess.CalledProcessError:
pass pass
else: else:
# Append disk numbers # Append disk numbers
output = result.stdout.decode().strip() output = result.stdout.decode().strip()
for tmp in re.findall(r'Disk (\d+)\s+\w+\s+(\d+\s+\w+)', output): for tmp in re.findall(r'Disk (\d+)\s+\w+\s+(\d+\s+\w+)', output):
num = tmp[0] num = tmp[0]
size = human_readable_size(tmp[1]) size = human_readable_size(tmp[1])
disks.append({'Number': num, 'Size': size}) disks.append({'Number': num, 'Size': size})
return disks
return disks
def get_partition_details(disk, partition): def get_partition_details(disk, partition):
"""Get partition details using DiskPart and fsutil.""" """Get partition details using DiskPart and fsutil."""
details = {} details = {}
script = [ script = [
'select disk {}'.format(disk['Number']), 'select disk {}'.format(disk['Number']),
'select partition {}'.format(partition['Number']), 'select partition {}'.format(partition['Number']),
'detail partition'] 'detail partition']
# Diskpart details # Diskpart details
try:
# Run script
result = run_diskpart(script)
except subprocess.CalledProcessError:
pass
else:
# Get volume letter or RAW status
output = result.stdout.decode().strip()
tmp = re.search(r'Volume\s+\d+\s+(\w|RAW)\s+', output)
if tmp:
if tmp.group(1).upper() == 'RAW':
details['FileSystem'] = RAW
else:
details['Letter'] = tmp.group(1)
# Remove empty lines from output
tmp = [s.strip() for s in output.splitlines() if s.strip() != '']
# Split each line on ':' skipping those without ':'
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.get(details.get('Type').upper(), {})
if guid:
details.update({
'Description': guid.get('Description', '')[:29],
'OS': guid.get('OS', 'Unknown')[:27]})
if 'Letter' in details:
# Disk usage
try: try:
# Run script tmp = psutil.disk_usage('{}:\\'.format(details['Letter']))
result = run_diskpart(script) except OSError as err:
except subprocess.CalledProcessError: details['FileSystem'] = 'Unknown'
pass details['Error'] = err.strerror
else: else:
# Get volume letter or RAW status details['Used Space'] = human_readable_size(tmp.used)
output = result.stdout.decode().strip()
tmp = re.search(r'Volume\s+\d+\s+(\w|RAW)\s+', output)
if tmp:
if tmp.group(1).upper() == 'RAW':
details['FileSystem'] = RAW
else:
details['Letter'] = tmp.group(1)
# Remove empty lines from output
tmp = [s.strip() for s in output.splitlines() if s.strip() != '']
# Split each line on ':' skipping those without ':'
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 # fsutil details
guid = partition_uids.lookup_guid(details.get('Type')) cmd = [
if guid: 'fsutil',
details.update({ 'fsinfo',
'Description': guid.get('Description', '')[:29], 'volumeinfo',
'OS': guid.get('OS', 'Unknown')[:27]}) '{}:'.format(details['Letter'])
]
try:
result = run_program(cmd)
except subprocess.CalledProcessError:
pass
else:
output = result.stdout.decode().strip()
# Remove empty lines from output
tmp = [s.strip() for s in output.splitlines() if s.strip() != '']
# Add "Feature" lines
details['File System Features'] = [s.strip() for s in tmp
if ':' not in s]
# Split each line on ':' skipping those without ':'
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})
if 'Letter' in details: # Set Volume Name
# Disk usage details['Name'] = details.get('Volume Name', '')
try:
tmp = psutil.disk_usage('{}:\\'.format(details['Letter']))
except OSError as err:
details['FileSystem'] = 'Unknown'
details['Error'] = err.strerror
else:
details['Used Space'] = human_readable_size(tmp.used)
# fsutil details # Set FileSystem Type
cmd = [ if details.get('FileSystem', '') not in ['RAW', 'Unknown']:
'fsutil', details['FileSystem'] = details.get('File System Name', 'Unknown')
'fsinfo',
'volumeinfo',
'{}:'.format(details['Letter'])
]
try:
result = run_program(cmd)
except subprocess.CalledProcessError:
pass
else:
output = result.stdout.decode().strip()
# Remove empty lines from output
tmp = [s.strip() for s in output.splitlines() if s.strip() != '']
# Add "Feature" lines
details['File System Features'] = [s.strip() for s in tmp
if ':' not in s]
# Split each line on ':' skipping those without ':'
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 return details
details['Name'] = details.get('Volume Name', '')
# Set FileSystem Type
if details.get('FileSystem', '') not in ['RAW', 'Unknown']:
details['FileSystem'] = details.get('File System Name', 'Unknown')
return details
def get_partitions(disk): def get_partitions(disk):
"""Get list of partition using DiskPart.""" """Get list of partition using DiskPart."""
partitions = [] partitions = []
script = [ script = [
'select disk {}'.format(disk['Number']), 'select disk {}'.format(disk['Number']),
'list partition'] 'list partition']
try: try:
# Run script # Run script
result = run_diskpart(script) result = run_diskpart(script)
except subprocess.CalledProcessError: except subprocess.CalledProcessError:
pass pass
else: else:
# Append partition numbers # Append partition numbers
output = result.stdout.decode().strip() output = result.stdout.decode().strip()
regex = r'Partition\s+(\d+)\s+\w+\s+(\d+\s+\w+)\s+' regex = r'Partition\s+(\d+)\s+\w+\s+(\d+\s+\w+)\s+'
for tmp in re.findall(regex, output, re.IGNORECASE): for tmp in re.findall(regex, output, re.IGNORECASE):
num = tmp[0] num = tmp[0]
size = human_readable_size(tmp[1]) size = human_readable_size(tmp[1])
partitions.append({'Number': num, 'Size': size}) partitions.append({'Number': num, 'Size': size})
return partitions
return partitions
def get_table_type(disk): def get_table_type(disk):
"""Get disk partition table type using DiskPart.""" """Get disk partition table type using DiskPart."""
part_type = 'Unknown' part_type = 'Unknown'
script = [ script = [
'select disk {}'.format(disk['Number']), 'select disk {}'.format(disk['Number']),
'uniqueid disk'] 'uniqueid disk']
try: try:
result = run_diskpart(script) result = run_diskpart(script)
except subprocess.CalledProcessError: except subprocess.CalledProcessError:
pass pass
else: else:
output = result.stdout.decode().strip() output = result.stdout.decode().strip()
if REGEX_DISK_GPT.search(output): if REGEX_DISK_GPT.search(output):
part_type = 'GPT' part_type = 'GPT'
elif REGEX_DISK_MBR.search(output): elif REGEX_DISK_MBR.search(output):
part_type = 'MBR' part_type = 'MBR'
elif REGEX_DISK_RAW.search(output): elif REGEX_DISK_RAW.search(output):
part_type = 'RAW' part_type = 'RAW'
return part_type
return part_type
def get_volumes(): def get_volumes():
"""Get list of volumes using DiskPart.""" """Get list of volumes using DiskPart."""
vols = [] vols = []
try: try:
result = run_diskpart(['list volume']) result = run_diskpart(['list volume'])
except subprocess.CalledProcessError: except subprocess.CalledProcessError:
pass pass
else: else:
# Append volume numbers # Append volume numbers
output = result.stdout.decode().strip() output = result.stdout.decode().strip()
for tmp in re.findall(r'Volume (\d+)\s+([A-Za-z]?)\s+', output): for tmp in re.findall(r'Volume (\d+)\s+([A-Za-z]?)\s+', output):
vols.append({'Number': tmp[0], 'Letter': tmp[1]}) vols.append({'Number': tmp[0], 'Letter': tmp[1]})
return vols
return vols
def is_bad_partition(par): def is_bad_partition(par):
"""Check if the partition is accessible.""" """Check if the partition is accessible."""
return 'Letter' not in par or REGEX_BAD_PARTITION.search(par['FileSystem']) return 'Letter' not in par or REGEX_BAD_PARTITION.search(par['FileSystem'])
def prep_disk_for_formatting(disk=None): def prep_disk_for_formatting(disk=None):
"""Gather details about the disk and its partitions.""" """Gather details about the disk and its partitions."""
disk['Format Warnings'] = '\n' disk['Format Warnings'] = '\n'
width = len(str(len(disk['Partitions']))) width = len(str(len(disk['Partitions'])))
# Bail early # Bail early
if disk is None: if disk is None:
raise Exception('Disk not provided.') raise Exception('Disk not provided.')
# Set boot method and partition table type # Set boot method and partition table type
disk['Use GPT'] = True disk['Use GPT'] = True
if (get_boot_mode() == 'UEFI'): if (get_boot_mode() == 'UEFI'):
if (not ask("Setup Windows to use UEFI booting?")): if (not ask("Setup Windows to use UEFI booting?")):
disk['Use GPT'] = False disk['Use GPT'] = False
else:
if (ask("Setup Windows to use BIOS/Legacy booting?")):
disk['Use GPT'] = False
# Set Display and Warning Strings
if len(disk['Partitions']) == 0:
disk['Format Warnings'] += 'No partitions found\n'
for partition in disk['Partitions']:
display = '{size} {fs}'.format(
num = partition['Number'],
width = width,
size = partition['Size'],
fs = partition['FileSystem'])
if is_bad_partition(partition):
# Set display string using partition description & OS type
display += '\t\t{q}{name}{q}\t{desc} ({os})'.format(
display = display,
q = '"' if partition['Name'] != '' else '',
name = partition['Name'],
desc = partition['Description'],
os = partition['OS'])
else: else:
if (ask("Setup Windows to use BIOS/Legacy booting?")): # List space used instead of partition description & OS type
disk['Use GPT'] = False display += ' (Used: {used})\t{q}{name}{q}'.format(
used = partition['Used Space'],
q = '"' if partition['Name'] != '' else '',
name = partition['Name'])
# For all partitions
partition['Display String'] = display
# Set Display and Warning Strings
if len(disk['Partitions']) == 0:
disk['Format Warnings'] += 'No partitions found\n'
for partition in disk['Partitions']:
display = '{size} {fs}'.format(
num = partition['Number'],
width = width,
size = partition['Size'],
fs = partition['FileSystem'])
if is_bad_partition(partition):
# Set display string using partition description & OS type
display += '\t\t{q}{name}{q}\t{desc} ({os})'.format(
display = display,
q = '"' if partition['Name'] != '' else '',
name = partition['Name'],
desc = partition['Description'],
os = partition['OS'])
else:
# List space used instead of partition description & OS type
display += ' (Used: {used})\t{q}{name}{q}'.format(
used = partition['Used Space'],
q = '"' if partition['Name'] != '' else '',
name = partition['Name'])
# For all partitions
partition['Display String'] = display
def reassign_volume_letter(letter, new_letter='I'): def reassign_volume_letter(letter, new_letter='I'):
"""Assign a new letter to a volume using DiskPart.""" """Assign a new letter to a volume using DiskPart."""
if not letter: if not letter:
# Ignore # Ignore
return None return None
script = [ script = [
'select volume {}'.format(letter), 'select volume {}'.format(letter),
'remove noerr', 'remove noerr',
'assign letter={}'.format(new_letter)] 'assign letter={}'.format(new_letter)]
try: try:
run_diskpart(script) run_diskpart(script)
except subprocess.CalledProcessError: except subprocess.CalledProcessError:
pass pass
else: else:
return new_letter return new_letter
def remove_volume_letters(keep=None): def remove_volume_letters(keep=None):
"""Remove all assigned volume letters using DiskPart.""" """Remove all assigned volume letters using DiskPart."""
if not keep: if not keep:
keep = '' keep = ''
script = [] script = []
for vol in get_volumes(): for vol in get_volumes():
if vol['Letter'].upper() != keep.upper(): if vol['Letter'].upper() != keep.upper():
script.append('select volume {}'.format(vol['Number'])) script.append('select volume {}'.format(vol['Number']))
script.append('remove noerr') script.append('remove noerr')
# Run script
try:
run_diskpart(script)
except subprocess.CalledProcessError:
pass
# Run script
try:
run_diskpart(script)
except subprocess.CalledProcessError:
pass
def run_diskpart(script): def run_diskpart(script):
"""Run DiskPart script.""" """Run DiskPart script."""
tempfile = r'{}\diskpart.script'.format(global_vars['Env']['TMP']) tempfile = r'{}\diskpart.script'.format(global_vars['Env']['TMP'])
# Write script # Write script
with open(tempfile, 'w') as f: with open(tempfile, 'w') as f:
for line in script: for line in script:
f.write('{}\n'.format(line)) f.write('{}\n'.format(line))
# Run script
cmd = [
r'{}\Windows\System32\diskpart.exe'.format(
global_vars['Env']['SYSTEMDRIVE']),
'/s', tempfile]
result = run_program(cmd)
sleep(2)
return result
# Run script
cmd = [
r'{}\Windows\System32\diskpart.exe'.format(
global_vars['Env']['SYSTEMDRIVE']),
'/s', tempfile]
result = run_program(cmd)
sleep(2)
return result
def scan_disks(): def scan_disks():
"""Get details about the attached disks""" """Get details about the attached disks"""
disks = get_disks() disks = get_disks()
# Get disk details # Get disk details
for disk in disks: for disk in disks:
# Get partition style # Get partition style
disk['Table'] = get_table_type(disk) disk['Table'] = get_table_type(disk)
# Get disk name/model and physical details # Get disk name/model and physical details
disk.update(get_disk_details(disk)) disk.update(get_disk_details(disk))
# Get partition info for disk # Get partition info for disk
disk['Partitions'] = get_partitions(disk) disk['Partitions'] = get_partitions(disk)
for partition in disk['Partitions']: for partition in disk['Partitions']:
# Get partition details # Get partition details
partition.update(get_partition_details(disk, partition)) partition.update(get_partition_details(disk, partition))
# Done
return disks
# Done
return disks
def select_disk(title='Which disk?', disks=[]): def select_disk(title='Which disk?', disks=[]):
"""Select a disk from the attached disks""" """Select a disk from the attached disks"""
# Build menu # Build menu
disk_options = [] disk_options = []
for disk in disks: for disk in disks:
display_name = '{}\t[{}] ({}) {}'.format( display_name = '{}\t[{}] ({}) {}'.format(
disk.get('Size', ''), disk.get('Size', ''),
disk.get('Table', ''), disk.get('Table', ''),
disk.get('Type', ''), disk.get('Type', ''),
disk.get('Name', 'Unknown'), disk.get('Name', 'Unknown'),
) )
pwidth=len(str(len(disk['Partitions']))) pwidth=len(str(len(disk['Partitions'])))
for partition in disk['Partitions']: for partition in disk['Partitions']:
# Main text # Main text
p_name = 'Partition {num:>{width}}: {size} ({fs})'.format( p_name = 'Partition {num:>{width}}: {size} ({fs})'.format(
num = partition['Number'], num = partition['Number'],
width = pwidth, width = pwidth,
size = partition['Size'], size = partition['Size'],
fs = partition['FileSystem']) fs = partition['FileSystem'])
if partition['Name']: if partition['Name']:
p_name += '\t"{}"'.format(partition['Name']) p_name += '\t"{}"'.format(partition['Name'])
# Show unsupported partition(s) # Show unsupported partition(s)
if is_bad_partition(partition): if is_bad_partition(partition):
p_name = '{YELLOW}{p_name}{CLEAR}'.format( p_name = '{YELLOW}{p_name}{CLEAR}'.format(
p_name=p_name, **COLORS) p_name=p_name, **COLORS)
display_name += '\n\t\t\t{}'.format(p_name) display_name += '\n\t\t\t{}'.format(p_name)
if not disk['Partitions']: if not disk['Partitions']:
display_name += '\n\t\t\t{}No partitions found.{}'.format( display_name += '\n\t\t\t{}No partitions found.{}'.format(
COLORS['YELLOW'], COLORS['CLEAR']) COLORS['YELLOW'], COLORS['CLEAR'])
disk_options.append({'Name': display_name, 'Disk': disk}) disk_options.append({'Name': display_name, 'Disk': disk})
actions = [ actions = [
{'Name': 'Main Menu', 'Letter': 'M'}, {'Name': 'Main Menu', 'Letter': 'M'},
] ]
# Menu loop # Menu loop
selection = menu_select( selection = menu_select(
title = title, title = title,
main_entries = disk_options, main_entries = disk_options,
action_entries = actions) action_entries = actions)
if (selection.isnumeric()):
return disk_options[int(selection)-1]['Disk']
elif (selection == 'M'):
raise GenericAbort
if (selection.isnumeric()):
return disk_options[int(selection)-1]['Disk']
elif (selection == 'M'):
raise GenericAbort
if __name__ == '__main__': if __name__ == '__main__':
print("This file is not meant to be called directly.") print("This file is not meant to be called directly.")
# vim: sts=2 sw=2 ts=2

View file

@ -8,6 +8,7 @@ from collections import OrderedDict
from functions.sensors import * from functions.sensors import *
from functions.tmux import * from functions.tmux import *
# STATIC VARIABLES # STATIC VARIABLES
ATTRIBUTES = { ATTRIBUTES = {
'NVMe': { 'NVMe': {
@ -83,13 +84,16 @@ TMUX_LAYOUT = OrderedDict({
'Progress': {'x': SIDE_PANE_WIDTH, 'Check': True}, 'Progress': {'x': SIDE_PANE_WIDTH, 'Check': True},
}) })
# Regex # Regex
REGEX_ERROR_STATUS = re.compile('|'.join(STATUSES['RED'])) REGEX_ERROR_STATUS = re.compile('|'.join(STATUSES['RED']))
# Error Classes # Error Classes
class DeviceTooSmallError(Exception): class DeviceTooSmallError(Exception):
pass pass
# Classes # Classes
class CpuObj(): class CpuObj():
"""Object for tracking CPU specific data.""" """Object for tracking CPU specific data."""
@ -130,6 +134,7 @@ class CpuObj():
return report return report
class DiskObj(): class DiskObj():
"""Object for tracking disk specific data.""" """Object for tracking disk specific data."""
def __init__(self, disk_path): def __init__(self, disk_path):
@ -487,6 +492,7 @@ class DiskObj():
for t in ['badblocks', 'I/O Benchmark']: for t in ['badblocks', 'I/O Benchmark']:
self.disable_test(t, 'Denied') self.disable_test(t, 'Denied')
class State(): class State():
"""Object to track device objects and overall state.""" """Object to track device objects and overall state."""
def __init__(self): def __init__(self):
@ -559,6 +565,7 @@ class State():
if not skip_disk: if not skip_disk:
self.disks.append(disk_obj) self.disks.append(disk_obj)
class TestObj(): class TestObj():
"""Object to track test data.""" """Object to track test data."""
def __init__(self, dev, label=None, info_label=False): def __init__(self, dev, label=None, info_label=False):
@ -589,6 +596,7 @@ class TestObj():
self.status = build_status_string( self.status = build_status_string(
self.label, 'Working', self.info_label) self.label, 'Working', self.info_label)
# Functions # Functions
def build_outer_panes(state): def build_outer_panes(state):
"""Build top and side panes.""" """Build top and side panes."""
@ -611,6 +619,7 @@ def build_outer_panes(state):
lines=SIDE_PANE_WIDTH, lines=SIDE_PANE_WIDTH,
watch=state.progress_out) watch=state.progress_out)
def build_status_string(label, status, info_label=False): def build_status_string(label, status, info_label=False):
"""Build status string with appropriate colors.""" """Build status string with appropriate colors."""
status_color = COLORS['CLEAR'] status_color = COLORS['CLEAR']
@ -626,6 +635,7 @@ def build_status_string(label, status, info_label=False):
s_w=SIDE_PANE_WIDTH-len(label), s_w=SIDE_PANE_WIDTH-len(label),
**COLORS) **COLORS)
def fix_tmux_panes(state, tmux_layout): def fix_tmux_panes(state, tmux_layout):
"""Fix pane sizes if the window has been resized.""" """Fix pane sizes if the window has been resized."""
needs_fixed = False needs_fixed = False
@ -669,6 +679,7 @@ def fix_tmux_panes(state, tmux_layout):
# Resize pane # Resize pane
tmux_resize_pane(pane_id=target, **v) tmux_resize_pane(pane_id=target, **v)
def generate_horizontal_graph(rates, oneline=False): def generate_horizontal_graph(rates, oneline=False):
"""Generate horizontal graph from rates, returns list.""" """Generate horizontal graph from rates, returns list."""
graph = ['', '', '', ''] graph = ['', '', '', '']
@ -714,6 +725,7 @@ def generate_horizontal_graph(rates, oneline=False):
else: else:
return graph return graph
def get_graph_step(rate, scale=16): def get_graph_step(rate, scale=16):
"""Get graph step based on rate and scale, returns int.""" """Get graph step based on rate and scale, returns int."""
m_rate = rate / (1024**2) m_rate = rate / (1024**2)
@ -726,6 +738,7 @@ def get_graph_step(rate, scale=16):
break break
return step return step
def get_read_rate(s): def get_read_rate(s):
"""Get read rate in bytes/s from dd progress output.""" """Get read rate in bytes/s from dd progress output."""
real_rate = None real_rate = None
@ -734,6 +747,7 @@ def get_read_rate(s):
real_rate = convert_to_bytes(human_rate) real_rate = convert_to_bytes(human_rate)
return real_rate return real_rate
def menu_diags(state, args): def menu_diags(state, args):
"""Main menu to select and run HW tests.""" """Main menu to select and run HW tests."""
args = [a.lower() for a in args] args = [a.lower() for a in args]
@ -840,12 +854,14 @@ def menu_diags(state, args):
elif selection == 'S': elif selection == 'S':
run_hw_tests(state) run_hw_tests(state)
def run_audio_test(): def run_audio_test():
"""Run audio test.""" """Run audio test."""
clear_screen() clear_screen()
run_program(['hw-diags-audio'], check=False, pipe=False) run_program(['hw-diags-audio'], check=False, pipe=False)
pause('Press Enter to return to main menu... ') pause('Press Enter to return to main menu... ')
def run_badblocks_test(state, test): def run_badblocks_test(state, test):
"""Run a read-only surface scan with badblocks.""" """Run a read-only surface scan with badblocks."""
# Bail early # Bail early
@ -939,6 +955,7 @@ def run_badblocks_test(state, test):
# Cleanup # Cleanup
tmux_kill_pane(state.panes['badblocks']) tmux_kill_pane(state.panes['badblocks'])
def run_hw_tests(state): def run_hw_tests(state):
"""Run enabled hardware tests.""" """Run enabled hardware tests."""
print_standard('Scanning devices...') print_standard('Scanning devices...')
@ -1016,6 +1033,7 @@ def run_hw_tests(state):
# Cleanup # Cleanup
tmux_kill_pane(*state.panes.values()) tmux_kill_pane(*state.panes.values())
def run_io_benchmark(state, test): def run_io_benchmark(state, test):
"""Run a read-only I/O benchmark using dd.""" """Run a read-only I/O benchmark using dd."""
# Bail early # Bail early
@ -1173,11 +1191,13 @@ def run_io_benchmark(state, test):
# Cleanup # Cleanup
tmux_kill_pane(state.panes['io_benchmark']) tmux_kill_pane(state.panes['io_benchmark'])
def run_keyboard_test(): def run_keyboard_test():
"""Run keyboard test.""" """Run keyboard test."""
clear_screen() clear_screen()
run_program(['xev', '-event', 'keyboard'], check=False, pipe=False) run_program(['xev', '-event', 'keyboard'], check=False, pipe=False)
def run_mprime_test(state, test): def run_mprime_test(state, test):
"""Test CPU with Prime95 and track temps.""" """Test CPU with Prime95 and track temps."""
# Bail early # Bail early
@ -1320,7 +1340,8 @@ def run_mprime_test(state, test):
if re.search(r'(error|fail)', line, re.IGNORECASE): if re.search(r'(error|fail)', line, re.IGNORECASE):
test.failed = True test.failed = True
test.update_status('NS') test.update_status('NS')
test.report.append(' {YELLOW}{line}{CLEAR}'.format(line=line, **COLORS)) test.report.append(
' {YELLOW}{line}{CLEAR}'.format(line=line, **COLORS))
# prime.log (CS check) # prime.log (CS check)
if log == 'prime.log': if log == 'prime.log':
@ -1349,7 +1370,8 @@ def run_mprime_test(state, test):
for line in sorted(_tmp['Pass'].keys()): for line in sorted(_tmp['Pass'].keys()):
test.report.append(' {}'.format(line)) test.report.append(' {}'.format(line))
for line in sorted(_tmp['Warn'].keys()): for line in sorted(_tmp['Warn'].keys()):
test.report.append(' {YELLOW}{line}{CLEAR}'.format(line=line, **COLORS)) test.report.append(
' {YELLOW}{line}{CLEAR}'.format(line=line, **COLORS))
# Unknown result # Unknown result
if not (test.aborted or test.failed or test.passed): if not (test.aborted or test.failed or test.passed):
@ -1369,12 +1391,14 @@ def run_mprime_test(state, test):
tmux_kill_pane(state.panes['mprime'], state.panes['Temps']) tmux_kill_pane(state.panes['mprime'], state.panes['Temps'])
test.monitor_proc.kill() test.monitor_proc.kill()
def run_network_test(): def run_network_test():
"""Run network test.""" """Run network test."""
clear_screen() clear_screen()
run_program(['hw-diags-network'], check=False, pipe=False) run_program(['hw-diags-network'], check=False, pipe=False)
pause('Press Enter to return to main menu... ') pause('Press Enter to return to main menu... ')
def run_nvme_smart_tests(state, test): def run_nvme_smart_tests(state, test):
"""Run NVMe or SMART test for test.dev.""" """Run NVMe or SMART test for test.dev."""
# Bail early # Bail early
@ -1518,6 +1542,7 @@ def run_nvme_smart_tests(state, test):
# Done # Done
update_progress_pane(state) update_progress_pane(state)
def secret_screensaver(screensaver=None): def secret_screensaver(screensaver=None):
"""Show screensaver.""" """Show screensaver."""
if screensaver == 'matrix': if screensaver == 'matrix':
@ -1528,6 +1553,7 @@ def secret_screensaver(screensaver=None):
raise Exception('Invalid screensaver') raise Exception('Invalid screensaver')
run_program(cmd, check=False, pipe=False) run_program(cmd, check=False, pipe=False)
def show_report(report, log_report=False): def show_report(report, log_report=False):
"""Show report on screen and optionally save to log w/out color.""" """Show report on screen and optionally save to log w/out color."""
for line in report: for line in report:
@ -1535,6 +1561,7 @@ def show_report(report, log_report=False):
if log_report: if log_report:
print_log(strip_colors(line)) print_log(strip_colors(line))
def show_results(state): def show_results(state):
"""Show results for all tests.""" """Show results for all tests."""
clear_screen() clear_screen()
@ -1562,6 +1589,7 @@ def show_results(state):
show_report(disk.generate_disk_report(), log_report=True) show_report(disk.generate_disk_report(), log_report=True)
print_standard(' ') print_standard(' ')
def update_main_options(state, selection, main_options): def update_main_options(state, selection, main_options):
"""Update menu and state based on selection.""" """Update menu and state based on selection."""
index = int(selection) - 1 index = int(selection) - 1
@ -1605,6 +1633,7 @@ def update_main_options(state, selection, main_options):
# Done # Done
return main_options return main_options
def update_io_progress(percent, rate, progress_file): def update_io_progress(percent, rate, progress_file):
"""Update I/O progress file.""" """Update I/O progress file."""
bar_color = COLORS['CLEAR'] bar_color = COLORS['CLEAR']
@ -1629,6 +1658,7 @@ def update_io_progress(percent, rate, progress_file):
with open(progress_file, 'a') as f: with open(progress_file, 'a') as f:
f.write(line) f.write(line)
def update_progress_pane(state): def update_progress_pane(state):
"""Update progress file for side pane.""" """Update progress file for side pane."""
output = [] output = []
@ -1656,6 +1686,7 @@ def update_progress_pane(state):
with open(state.progress_out, 'w') as f: with open(state.progress_out, 'w') as f:
f.writelines(output) f.writelines(output)
if __name__ == '__main__': if __name__ == '__main__':
print("This file is not meant to be called directly.") print("This file is not meant to be called directly.")

View file

@ -1,520 +1,547 @@
# Wizard Kit: Functions - Information # Wizard Kit: Functions - Information
from borrowed import knownpaths from borrowed import knownpaths
from functions.activation import *
from operator import itemgetter 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 # STATIC VARIABLES
REG_PROFILE_LIST = r'SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList' REG_PROFILE_LIST = r'SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList'
REG_SHELL_FOLDERS = r'Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders' REG_SHELL_FOLDERS = r'Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders'
TMP_HIVE_PATH = 'TEMP_HIVE_MOUNT' TMP_HIVE_PATH = 'TEMP_HIVE_MOUNT'
EXTRA_FOLDERS = [ EXTRA_FOLDERS = [
'Dropbox', 'Dropbox',
'Google Drive', 'Google Drive',
'OneDrive', 'OneDrive',
'SkyDrive', 'SkyDrive',
] ]
SHELL_FOLDERS = { SHELL_FOLDERS = {
#GUIDs from: https://msdn.microsoft.com/en-us/library/windows/desktop/dd378457(v=vs.85).aspx #GUIDs from: https://msdn.microsoft.com/en-us/library/windows/desktop/dd378457(v=vs.85).aspx
'Desktop': ( 'Desktop': (
'{B4BFCC3A-DB2C-424C-B029-7FE99A87C641}', '{B4BFCC3A-DB2C-424C-B029-7FE99A87C641}',
), ),
'Documents': ( 'Documents': (
'Personal', 'Personal',
'{FDD39AD0-238F-46AF-ADB4-6C85480369C7}', '{FDD39AD0-238F-46AF-ADB4-6C85480369C7}',
), ),
'Downloads': ( 'Downloads': (
'{374DE290-123F-4565-9164-39C4925E467B}', '{374DE290-123F-4565-9164-39C4925E467B}',
), ),
'Favorites': ( 'Favorites': (
'{1777F761-68AD-4D8A-87BD-30B759FA33DD}', '{1777F761-68AD-4D8A-87BD-30B759FA33DD}',
), ),
'Music': ( 'Music': (
'My Music', 'My Music',
'{4BD8D571-6D19-48D3-BE97-422220080E43}', '{4BD8D571-6D19-48D3-BE97-422220080E43}',
), ),
'Pictures': ( 'Pictures': (
'My Pictures', 'My Pictures',
'{33E28130-4E1E-4676-835A-98395C3BC3BB}', '{33E28130-4E1E-4676-835A-98395C3BC3BB}',
), ),
'Videos': ( 'Videos': (
'My Video', 'My Video',
'{18989B1D-99B5-455B-841C-AB7C74E4DDFC}', '{18989B1D-99B5-455B-841C-AB7C74E4DDFC}',
), ),
} }
# 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(): def backup_file_list():
"""Export current file listing for the system.""" """Export current file listing for the system."""
extract_item('Everything', silent=True) extract_item('Everything', silent=True)
cmd = [ cmd = [
global_vars['Tools']['Everything'], global_vars['Tools']['Everything'],
'-nodb', '-nodb',
'-create-filelist', '-create-filelist',
r'{LogDir}\File List.txt'.format(**global_vars), r'{LogDir}\File List.txt'.format(**global_vars),
global_vars['Env']['SYSTEMDRIVE']] global_vars['Env']['SYSTEMDRIVE']]
run_program(cmd) run_program(cmd)
def backup_power_plans(): def backup_power_plans():
"""Export current power plans.""" """Export current power plans."""
os.makedirs(r'{BackupDir}\Power Plans\{Date}'.format( os.makedirs(r'{BackupDir}\Power Plans\{Date}'.format(
**global_vars), exist_ok=True) **global_vars), exist_ok=True)
plans = run_program(['powercfg', '/L']) plans = run_program(['powercfg', '/L'])
plans = plans.stdout.decode().splitlines() plans = plans.stdout.decode().splitlines()
plans = [p for p in plans if re.search(r'^Power Scheme', p)] plans = [p for p in plans if re.search(r'^Power Scheme', p)]
for p in plans: for p in plans:
guid = re.sub(r'Power Scheme GUID:\s+([0-9a-f\-]+).*', r'\1', p) guid = re.sub(r'Power Scheme GUID:\s+([0-9a-f\-]+).*', r'\1', p)
name = re.sub( name = re.sub(
r'Power Scheme GUID:\s+[0-9a-f\-]+\s+\(([^\)]+)\).*', r'\1', p) r'Power Scheme GUID:\s+[0-9a-f\-]+\s+\(([^\)]+)\).*', r'\1', p)
out = r'{BackupDir}\Power Plans\{Date}\{name}.pow'.format( out = r'{BackupDir}\Power Plans\{Date}\{name}.pow'.format(
name=name, **global_vars) name=name, **global_vars)
if not os.path.exists(out): if not os.path.exists(out):
cmd = ['powercfg', '-export', out, guid] cmd = ['powercfg', '-export', out, guid]
run_program(cmd, check=False) run_program(cmd, check=False)
def backup_registry(overwrite=False): def backup_registry(overwrite=False):
"""Backup registry including user hives.""" """Backup registry including user hives."""
extract_item('erunt', silent=True) extract_item('erunt', silent=True)
cmd = [ cmd = [
global_vars['Tools']['ERUNT'], global_vars['Tools']['ERUNT'],
r'{BackupDir}\Registry\{Date}'.format(**global_vars), r'{BackupDir}\Registry\{Date}'.format(**global_vars),
'sysreg', 'sysreg',
'curuser', 'curuser',
'otherusers', 'otherusers',
'/noprogresswindow'] '/noprogresswindow']
if overwrite: if overwrite:
cmd.append('/noconfirmdelete') cmd.append('/noconfirmdelete')
run_program(cmd) run_program(cmd)
def get_folder_size(path): def get_folder_size(path):
"""Get (human-readable) size of folder passed, returns str.""" """Get (human-readable) size of folder passed, returns str."""
size = 'Unknown' size = 'Unknown'
cmd = [global_vars['Tools']['Du'], '-c', '-nobanner', '-q', path] cmd = [global_vars['Tools']['Du'], '-c', '-nobanner', '-q', path]
try:
out = run_program(cmd)
except FileNotFoundError:
# Failed to find folder
pass
except subprocess.CalledProcessError:
# Failed to get folder size
pass
else:
try: try:
out = run_program(cmd) size = out.stdout.decode().split(',')[-2]
except FileNotFoundError: except IndexError:
# Failed to find folder # Failed to parse csv data
pass pass
except subprocess.CalledProcessError:
# Failed to get folder size
pass
else: else:
try: size = human_readable_size(size)
size = out.stdout.decode().split(',')[-2] return size
except IndexError:
# Failed to parse csv data
pass
else:
size = human_readable_size(size)
return size
def get_installed_antivirus(): def get_installed_antivirus():
"""Get list of installed Antivirus programs.""" """Get list of installed Antivirus programs."""
programs = [] programs = []
cmd = ['WMIC', r'/namespace:\\root\SecurityCenter2',
'path', 'AntivirusProduct',
'get', 'displayName', '/value']
out = run_program(cmd)
out = out.stdout.decode().strip()
products = out.splitlines()
products = [p.split('=')[1] for p in products if p]
for prod in sorted(products):
# Get product state and check if it's enabled
# credit: https://jdhitsolutions.com/blog/powershell/5187/get-antivirus-product-status-with-powershell/
cmd = ['WMIC', r'/namespace:\\root\SecurityCenter2', cmd = ['WMIC', r'/namespace:\\root\SecurityCenter2',
'path', 'AntivirusProduct', 'path', 'AntivirusProduct',
'get', 'displayName', '/value'] 'where', 'displayName="{}"'.format(prod),
'get', 'productState', '/value']
out = run_program(cmd) out = run_program(cmd)
out = out.stdout.decode().strip() out = out.stdout.decode().strip()
products = out.splitlines() state = out.split('=')[1]
products = [p.split('=')[1] for p in products if p] state = hex(int(state))
for prod in sorted(products): if str(state)[3:5] != '10':
# Get product state and check if it's enabled programs.append('[Disabled] {}'.format(prod))
# credit: https://jdhitsolutions.com/blog/powershell/5187/get-antivirus-product-status-with-powershell/ else:
cmd = ['WMIC', r'/namespace:\\root\SecurityCenter2', programs.append(prod)
'path', 'AntivirusProduct',
'where', 'displayName="{}"'.format(prod), if len(programs) == 0:
'get', 'productState', '/value'] programs = ['No programs found']
out = run_program(cmd) return programs
out = out.stdout.decode().strip()
state = out.split('=')[1]
state = hex(int(state))
if str(state)[3:5] != '10':
programs.append('[Disabled] {}'.format(prod))
else:
programs.append(prod)
if len(programs) == 0:
programs = ['No programs found']
return programs
def get_installed_office(): def get_installed_office():
"""Get list of installed Office programs.""" """Get list of installed Office programs."""
programs = [] programs = []
log_file = r'{LogDir}\Installed Program List (AIDA64).txt'.format( log_file = r'{LogDir}\Installed Program List (AIDA64).txt'.format(
**global_vars) **global_vars)
with open (log_file, 'r') as f: with open (log_file, 'r') as f:
for line in sorted(f.readlines()): for line in sorted(f.readlines()):
if REGEX_OFFICE.search(line): if REGEX_OFFICE.search(line):
programs.append(line[4:82].strip()) programs.append(line[4:82].strip())
if len(programs) == 0:
programs = ['No programs found']
return programs
if len(programs) == 0:
programs = ['No programs found']
return programs
def get_shell_path(folder, user='current'): def get_shell_path(folder, user='current'):
"""Get shell path using SHGetKnownFolderPath via knownpaths, returns str. """Get shell path using knownpaths, returns str.
NOTE: Only works for the current user. NOTE: Only works for the current user.
Code based on https://gist.github.com/mkropat/7550097 Code based on https://gist.github.com/mkropat/7550097
""" """
path = None path = None
folderid = None folderid = None
if user.lower() == 'public': if user.lower() == 'public':
user = 'common' user = 'common'
try:
folderid = getattr(knownpaths.FOLDERID, folder)
except AttributeError:
# Unknown folder ID, ignore and return None
pass
if folderid:
try: try:
folderid = getattr(knownpaths.FOLDERID, folder) path = knownpaths.get_path(
except AttributeError: folderid, getattr(knownpaths.UserHandle, user))
# Unknown folder ID, ignore and return None except PathNotFoundError:
pass # Folder not found, ignore and return None
pass
if folderid: return path
try:
path = knownpaths.get_path(folderid, getattr(knownpaths.UserHandle, user))
except PathNotFoundError:
# Folder not found, ignore and return None
pass
return path
def get_user_data_paths(user): def get_user_data_paths(user):
"""Get user data paths for provided user, returns dict.""" """Get user data paths for provided user, returns dict."""
hive_path = user['SID'] hive_path = user['SID']
paths = { paths = {
'Profile': { 'Profile': {
'Path': None, 'Path': None,
}, },
'Shell Folders': {}, 'Shell Folders': {},
'Extra Folders': {}, 'Extra Folders': {},
} }
unload_hive = False unload_hive = False
if user['Name'] == global_vars['Env']['USERNAME']: if user['Name'] == global_vars['Env']['USERNAME']:
# We can use SHGetKnownFolderPath for the current user # We can use SHGetKnownFolderPath for the current user
paths['Profile']['Path'] = get_shell_path('Profile') paths['Profile']['Path'] = get_shell_path('Profile')
paths['Shell Folders'] = {f: {'Path': get_shell_path(f)} paths['Shell Folders'] = {f: {'Path': get_shell_path(f)}
for f in SHELL_FOLDERS.keys()} for f in SHELL_FOLDERS.keys()}
else: else:
# We have to use the NTUSER.dat hives which isn't recommended by MS # We have to use the NTUSER.dat hives which isn't recommended by MS
try: try:
key_path = r'{}\{}'.format(REG_PROFILE_LIST, user['SID']) key_path = r'{}\{}'.format(REG_PROFILE_LIST, user['SID'])
with winreg.OpenKey(HKLM, key_path) as key: with winreg.OpenKey(HKLM, key_path) as key:
paths['Profile']['Path'] = winreg.QueryValueEx( paths['Profile']['Path'] = winreg.QueryValueEx(
key, 'ProfileImagePath')[0] key, 'ProfileImagePath')[0]
except Exception: except Exception:
# Profile path not found, leaving as None. # Profile path not found, leaving as None.
pass pass
# Shell folders (Prep) # Shell folders (Prep)
if not reg_path_exists(HKU, hive_path) and paths['Profile']['Path']: if not reg_path_exists(HKU, hive_path) and paths['Profile']['Path']:
# User not logged-in, loading hive # User not logged-in, loading hive
# Also setting unload_hive so it will be unloaded later. # Also setting unload_hive so it will be unloaded later.
hive_path = TMP_HIVE_PATH hive_path = TMP_HIVE_PATH
cmd = ['reg', 'load', r'HKU\{}'.format(TMP_HIVE_PATH), cmd = ['reg', 'load', r'HKU\{}'.format(TMP_HIVE_PATH),
r'{}\NTUSER.DAT'.format(paths['Profile']['Path'])] r'{}\NTUSER.DAT'.format(paths['Profile']['Path'])]
unload_hive = True unload_hive = True
try:
run_program(cmd)
except subprocess.CalledProcessError:
# Failed to load user hive
pass
# Shell folders
shell_folders = r'{}\{}'.format(hive_path, REG_SHELL_FOLDERS)
if (reg_path_exists(HKU, hive_path)
and reg_path_exists(HKU, shell_folders)):
with winreg.OpenKey(HKU, shell_folders) as key:
for folder, values in SHELL_FOLDERS.items():
for value in values:
try: try:
run_program(cmd) path = winreg.QueryValueEx(key, value)[0]
except subprocess.CalledProcessError: except FileNotFoundError:
# Failed to load user hive # Skip missing values
pass pass
else:
paths['Shell Folders'][folder] = {'Path': path}
# Stop checking values for this folder
break
# Shell folders # Shell folder (extra check)
shell_folders = r'{}\{}'.format(hive_path, REG_SHELL_FOLDERS)
if (reg_path_exists(HKU, hive_path)
and reg_path_exists(HKU, shell_folders)):
with winreg.OpenKey(HKU, shell_folders) as key:
for folder, values in SHELL_FOLDERS.items():
for value in values:
try:
path = winreg.QueryValueEx(key, value)[0]
except FileNotFoundError:
# Skip missing values
pass
else:
paths['Shell Folders'][folder] = {'Path': path}
# Stop checking values for this folder
break
# Shell folder (extra check)
if paths['Profile']['Path']:
for folder in SHELL_FOLDERS.keys():
folder_path = r'{Path}\{folder}'.format(
folder=folder, **paths['Profile'])
if (folder not in paths['Shell Folders']
and os.path.exists(folder_path)):
paths['Shell Folders'][folder] = {'Path': folder_path}
# Extra folders
if paths['Profile']['Path']: if paths['Profile']['Path']:
for folder in EXTRA_FOLDERS: for folder in SHELL_FOLDERS.keys():
folder_path = r'{Path}\{folder}'.format( folder_path = r'{Path}\{folder}'.format(
folder=folder, **paths['Profile']) folder=folder, **paths['Profile'])
if os.path.exists(folder_path): if (folder not in paths['Shell Folders']
paths['Extra Folders'][folder] = {'Path': folder_path} and os.path.exists(folder_path)):
paths['Shell Folders'][folder] = {'Path': folder_path}
# Shell folders (cleanup) # Extra folders
if unload_hive: if paths['Profile']['Path']:
cmd = ['reg', 'unload', r'HKU\{}'.format(TMP_HIVE_PATH)] for folder in EXTRA_FOLDERS:
run_program(cmd, check=False) folder_path = r'{Path}\{folder}'.format(
folder=folder, **paths['Profile'])
if os.path.exists(folder_path):
paths['Extra Folders'][folder] = {'Path': folder_path}
# Shell folders (cleanup)
if unload_hive:
cmd = ['reg', 'unload', r'HKU\{}'.format(TMP_HIVE_PATH)]
run_program(cmd, check=False)
# Done
return paths
# Done
return paths
def get_user_folder_sizes(users): def get_user_folder_sizes(users):
"""Update list(users) to include folder paths and sizes.""" """Update list(users) to include folder paths and sizes."""
extract_item('du', filter='du*', silent=True) extract_item('du', filter='du*', silent=True)
# Configure Du # Configure Du
winreg.CreateKey(HKCU, r'Software\Sysinternals\Du') winreg.CreateKey(HKCU, r'Software\Sysinternals\Du')
with winreg.OpenKey(HKCU, with winreg.OpenKey(HKCU,
r'Software\Sysinternals\Du', access=winreg.KEY_WRITE) as key: r'Software\Sysinternals\Du', access=winreg.KEY_WRITE) as key:
winreg.SetValueEx(key, 'EulaAccepted', 0, winreg.REG_DWORD, 1) winreg.SetValueEx(key, 'EulaAccepted', 0, winreg.REG_DWORD, 1)
for u in users:
u.update(get_user_data_paths(u))
if u['Profile']['Path']:
u['Profile']['Size'] = get_folder_size(u['Profile']['Path'])
for folder in u['Shell Folders'].keys():
u['Shell Folders'][folder]['Size'] = get_folder_size(
u['Shell Folders'][folder]['Path'])
for folder in u['Extra Folders'].keys():
u['Extra Folders'][folder]['Size'] = get_folder_size(
u['Extra Folders'][folder]['Path'])
for u in users:
u.update(get_user_data_paths(u))
if u['Profile']['Path']:
u['Profile']['Size'] = get_folder_size(u['Profile']['Path'])
for folder in u['Shell Folders'].keys():
u['Shell Folders'][folder]['Size'] = get_folder_size(
u['Shell Folders'][folder]['Path'])
for folder in u['Extra Folders'].keys():
u['Extra Folders'][folder]['Size'] = get_folder_size(
u['Extra Folders'][folder]['Path'])
def get_user_list(): def get_user_list():
"""Get user list via WMIC, returns list of dicts.""" """Get user list via WMIC, returns list of dicts."""
users = [] users = []
# Get user info from WMI # Get user info from WMI
cmd = ['wmic', 'useraccount', 'get', '/format:csv'] cmd = ['wmic', 'useraccount', 'get', '/format:csv']
try: try:
out = run_program(cmd) out = run_program(cmd)
except subprocess.CalledProcessError: except subprocess.CalledProcessError:
# Meh, return empty list to avoid a full crash # Meh, return empty list to avoid a full crash
return users
entries = out.stdout.decode().splitlines()
entries = [e.strip().split(',') for e in entries if e.strip()]
# Add user(s) to dict
keys = entries[0]
for e in entries[1:]:
# Create dict using 1st line (keys)
e = dict(zip(keys, e))
# Set Active status via 'Disabled' TRUE/FALSE str
e['Active'] = bool(e['Disabled'].upper() == 'FALSE')
# Assume SIDs ending with 1000+ are "Standard" and others are "System"
e['Type'] = 'Standard' if re.search(r'-1\d+$', e['SID']) else 'System'
users.append(e)
# Sort list
users.sort(key=itemgetter('Name'))
# Done
return users return users
entries = out.stdout.decode().splitlines()
entries = [e.strip().split(',') for e in entries if e.strip()]
# Add user(s) to dict
keys = entries[0]
for e in entries[1:]:
# Create dict using 1st line (keys)
e = dict(zip(keys, e))
# Set Active status via 'Disabled' TRUE/FALSE str
e['Active'] = bool(e['Disabled'].upper() == 'FALSE')
# Assume SIDs ending with 1000+ are "Standard" and others are "System"
e['Type'] = 'Standard' if re.search(r'-1\d+$', e['SID']) else 'System'
users.append(e)
# Sort list
users.sort(key=itemgetter('Name'))
# Done
return users
def reg_path_exists(hive, path): def reg_path_exists(hive, path):
"""Test if specified path exists, returns bool.""" """Test if specified path exists, returns bool."""
try: try:
winreg.QueryValue(hive, path) winreg.QueryValue(hive, path)
except FileNotFoundError: except FileNotFoundError:
return False return False
else: else:
return True return True
def run_aida64(): def run_aida64():
"""Run AIDA64 to save system reports.""" """Run AIDA64 to save system reports."""
extract_item('AIDA64', silent=True) extract_item('AIDA64', silent=True)
# All system info # All system info
config = r'{BinDir}\AIDA64\full.rpf'.format(**global_vars) config = r'{BinDir}\AIDA64\full.rpf'.format(**global_vars)
report_file = r'{LogDir}\System Information (AIDA64).html'.format( report_file = r'{LogDir}\System Information (AIDA64).html'.format(
**global_vars) **global_vars)
if not os.path.exists(report_file): if not os.path.exists(report_file):
cmd = [ cmd = [
global_vars['Tools']['AIDA64'], global_vars['Tools']['AIDA64'],
'/R', report_file, '/R', report_file,
'/CUSTOM', config, '/CUSTOM', config,
'/HTML', '/SILENT', '/SAFEST'] '/HTML', '/SILENT', '/SAFEST']
run_program(cmd, check=False) run_program(cmd, check=False)
# Installed Programs # Installed Programs
config = r'{BinDir}\AIDA64\installed_programs.rpf'.format(**global_vars) config = r'{BinDir}\AIDA64\installed_programs.rpf'.format(**global_vars)
report_file = r'{LogDir}\Installed Program List (AIDA64).txt'.format( report_file = r'{LogDir}\Installed Program List (AIDA64).txt'.format(
**global_vars) **global_vars)
if not os.path.exists(report_file): if not os.path.exists(report_file):
cmd = [ cmd = [
global_vars['Tools']['AIDA64'], global_vars['Tools']['AIDA64'],
'/R', report_file, '/R', report_file,
'/CUSTOM', config, '/CUSTOM', config,
'/TEXT', '/SILENT', '/SAFEST'] '/TEXT', '/SILENT', '/SAFEST']
run_program(cmd, check=False) run_program(cmd, check=False)
# Product Keys
config = r'{BinDir}\AIDA64\licenses.rpf'.format(**global_vars)
report_file = r'{LogDir}\Product Keys (AIDA64).txt'.format(**global_vars)
if not os.path.exists(report_file):
cmd = [
global_vars['Tools']['AIDA64'],
'/R', report_file,
'/CUSTOM', config,
'/TEXT', '/SILENT', '/SAFEST']
run_program(cmd, check=False)
# Product Keys
config = r'{BinDir}\AIDA64\licenses.rpf'.format(**global_vars)
report_file = r'{LogDir}\Product Keys (AIDA64).txt'.format(**global_vars)
if not os.path.exists(report_file):
cmd = [
global_vars['Tools']['AIDA64'],
'/R', report_file,
'/CUSTOM', config,
'/TEXT', '/SILENT', '/SAFEST']
run_program(cmd, check=False)
def run_bleachbit(cleaners=None, preview=True): def run_bleachbit(cleaners=None, preview=True):
"""Run BleachBit preview and save log. """Run BleachBit preview and save log.
If preview is True then no files should be deleted.""" If preview is True then no files should be deleted."""
error_path = r'{}\Tools\BleachBit.err'.format(global_vars['LogDir']) error_path = r'{}\Tools\BleachBit.err'.format(global_vars['LogDir'])
log_path = error_path.replace('err', 'log') log_path = error_path.replace('err', 'log')
extract_item('BleachBit', silent=True) extract_item('BleachBit', silent=True)
# Safety check # Safety check
if not cleaners: if not cleaners:
# Disable cleaning and use preset config # Disable cleaning and use preset config
cleaners = ['--preset'] cleaners = ['--preset']
preview = True preview = True
# Run # Run
cmd = [ cmd = [
global_vars['Tools']['BleachBit'], global_vars['Tools']['BleachBit'],
'--preview' if preview else '--clean'] '--preview' if preview else '--clean']
cmd.extend(cleaners) cmd.extend(cleaners)
out = run_program(cmd, check=False) out = run_program(cmd, check=False)
# Save stderr # Save stderr
if out.stderr.decode().splitlines(): if out.stderr.decode().splitlines():
with open(error_path, 'a', encoding='utf-8') as f: with open(error_path, 'a', encoding='utf-8') as f:
for line in out.stderr.decode().splitlines(): for line in out.stderr.decode().splitlines():
f.write(line.strip() + '\n') f.write(line.strip() + '\n')
# Save stdout
with open(log_path, 'a', encoding='utf-8') as f:
for line in out.stdout.decode().splitlines():
f.write(line.strip() + '\n')
# Save stdout
with open(log_path, 'a', encoding='utf-8') as f:
for line in out.stdout.decode().splitlines():
f.write(line.strip() + '\n')
def show_disk_usage(disk): def show_disk_usage(disk):
"""Show free and used space for a specified disk.""" """Show free and used space for a specified disk."""
print_standard('{:5}'.format(disk.device.replace('/', ' ')), print_standard('{:5}'.format(disk.device.replace('/', ' ')),
end='', flush=True, timestamp=False) end='', flush=True, timestamp=False)
try: try:
usage = psutil.disk_usage(disk.device) usage = psutil.disk_usage(disk.device)
display_string = '{percent:>5.2f}% Free ({free} / {total})'.format( display_string = '{percent:>5.2f}% Free ({free} / {total})'.format(
percent = 100 - usage.percent, percent = 100 - usage.percent,
free = human_readable_size(usage.free, 2), free = human_readable_size(usage.free, 2),
total = human_readable_size(usage.total, 2)) total = human_readable_size(usage.total, 2))
if usage.percent > 85: if usage.percent > 85:
print_error(display_string, timestamp=False) print_error(display_string, timestamp=False)
elif usage.percent > 75: elif usage.percent > 75:
print_warning(display_string, timestamp=False) print_warning(display_string, timestamp=False)
else: else:
print_standard(display_string, timestamp=False) print_standard(display_string, timestamp=False)
except Exception: except Exception:
print_warning('Unknown', timestamp=False) print_warning('Unknown', timestamp=False)
def show_free_space(indent=8, width=32): def show_free_space(indent=8, width=32):
"""Show free space info for all fixed disks.""" """Show free space info for all fixed disks."""
message = 'Free Space:' message = 'Free Space:'
for disk in psutil.disk_partitions(): for disk in psutil.disk_partitions():
try: try:
if 'fixed' in disk.opts: if 'fixed' in disk.opts:
try_and_print(message=message, function=show_disk_usage, try_and_print(message=message, function=show_disk_usage,
ns='Unknown', silent_function=False, ns='Unknown', silent_function=False,
indent=indent, width=width, disk=disk) indent=indent, width=width, disk=disk)
message = '' message = ''
except Exception: except Exception:
pass pass
def show_installed_ram(): def show_installed_ram():
"""Show installed RAM.""" """Show installed RAM."""
mem = psutil.virtual_memory() mem = psutil.virtual_memory()
if mem.total > 5905580032: if mem.total > 5905580032:
# > 5.5 Gb so 6Gb or greater # > 5.5 Gb so 6Gb or greater
print_standard(human_readable_size(mem.total).strip(), timestamp=False) print_standard(human_readable_size(mem.total).strip(), timestamp=False)
elif mem.total > 3758096384: elif mem.total > 3758096384:
# > 3.5 Gb so 4Gb or greater # > 3.5 Gb so 4Gb or greater
print_warning(human_readable_size(mem.total).strip(), timestamp=False) print_warning(human_readable_size(mem.total).strip(), timestamp=False)
else: else:
print_error(human_readable_size(mem.total).strip(), timestamp=False) print_error(human_readable_size(mem.total).strip(), timestamp=False)
def show_os_activation(): def show_os_activation():
"""Show OS activation info.""" """Show OS activation info."""
act_str = get_activation_string() act_str = get_activation_string()
if windows_is_activated(): if windows_is_activated():
print_standard(act_str, timestamp=False) print_standard(act_str, timestamp=False)
elif re.search(r'unavailable', act_str, re.IGNORECASE): elif re.search(r'unavailable', act_str, re.IGNORECASE):
print_warning(act_str, timestamp=False) print_warning(act_str, timestamp=False)
else: else:
print_error(act_str, timestamp=False) print_error(act_str, timestamp=False)
def show_os_name(): def show_os_name():
"""Show extended OS name (including warnings).""" """Show extended OS name (including warnings)."""
os_name = global_vars['OS']['DisplayName'] os_name = global_vars['OS']['DisplayName']
if global_vars['OS']['Arch'] == 32: if global_vars['OS']['Arch'] == 32:
# Show all 32-bit installs as an error message # Show all 32-bit installs as an error message
print_error(os_name, timestamp=False) print_error(os_name, timestamp=False)
else:
if re.search(
r'(preview build|unrecognized|unsupported)',
os_name,
re.IGNORECASE):
print_error(os_name, timestamp=False)
elif re.search(r'outdated', os_name, re.IGNORECASE):
print_warning(os_name, timestamp=False)
else: else:
if re.search(r'(preview build|unrecognized|unsupported)', os_name, re.IGNORECASE): print_standard(os_name, timestamp=False)
print_error(os_name, timestamp=False)
elif re.search(r'outdated', os_name, re.IGNORECASE):
print_warning(os_name, timestamp=False)
else:
print_standard(os_name, timestamp=False)
def show_temp_files_size(): def show_temp_files_size():
"""Show total size of temp files identified by BleachBit.""" """Show total size of temp files identified by BleachBit."""
size = None size = None
with open(r'{LogDir}\Tools\BleachBit.log'.format(**global_vars), 'r') as f: with open(r'{LogDir}\Tools\BleachBit.log'.format(**global_vars), 'r') as f:
for line in f.readlines(): for line in f.readlines():
if re.search(r'^disk space to be recovered:', line, re.IGNORECASE): if re.search(r'^disk space to be recovered:', line, re.IGNORECASE):
size = re.sub(r'.*: ', '', line.strip()) size = re.sub(r'.*: ', '', line.strip())
size = re.sub(r'(\w)iB$', r' \1b', size) size = re.sub(r'(\w)iB$', r' \1b', size)
if size is None: if size is None:
print_warning(size, timestamp=False) print_warning(size, timestamp=False)
else: else:
print_standard(size, timestamp=False) print_standard(size, timestamp=False)
def show_user_data_summary(indent=8, width=32): def show_user_data_summary(indent=8, width=32):
"""Print user data folder sizes for all users.""" """Print user data folder sizes for all users."""
users = get_user_list() users = get_user_list()
users = [u for u in users if u['Active']] users = [u for u in users if u['Active']]
get_user_folder_sizes(users) get_user_folder_sizes(users)
for user in users: for user in users:
if ('Size' not in user['Profile'] if ('Size' not in user['Profile']
and not any(user['Shell Folders']) and not any(user['Shell Folders'])
and not any(user['Extra Folders'])): and not any(user['Extra Folders'])):
# Skip empty users # Skip empty users
continue continue
print_success('{indent}User: {user}'.format( print_success('{indent}User: {user}'.format(
indent = ' '*int(indent/2), indent = ' '*int(indent/2),
user = user['Name'])) user = user['Name']))
for section in ['Profile', None, 'Shell Folders', 'Extra Folders']: for section in ['Profile', None, 'Shell Folders', 'Extra Folders']:
folders = [] folders = []
if section is None: if section is None:
# Divider # Divider
print_standard('{}{}'.format(' '*indent, '-'*(width+6))) print_standard('{}{}'.format(' '*indent, '-'*(width+6)))
elif section == 'Profile': elif section == 'Profile':
folders = {'Profile': user['Profile']} folders = {'Profile': user['Profile']}
else: else:
folders = user[section] folders = user[section]
for folder in folders: for folder in folders:
print_standard( print_standard(
'{indent}{folder:<{width}}{size:>6} ({path})'.format( '{indent}{folder:<{width}}{size:>6} ({path})'.format(
indent = ' ' * indent, indent = ' ' * indent,
width = width, width = width,
folder = folder, folder = folder,
size = folders[folder].get('Size', 'Unknown'), size = folders[folder].get('Size', 'Unknown'),
path = folders[folder].get('Path', 'Unknown'))) path = folders[folder].get('Path', 'Unknown')))
if __name__ == '__main__': if __name__ == '__main__':
print("This file is not meant to be called directly.") print("This file is not meant to be called directly.")
# vim: sts=2 sw=2 ts=2

View file

@ -6,67 +6,71 @@ import os
import shutil import shutil
import sys import sys
# Init
os.chdir(os.path.dirname(os.path.realpath(__file__)))
sys.path.append(os.getcwd())
from functions.common import * from functions.common import *
# REGEX # REGEX
REGEX_VALID_IP = re.compile( REGEX_VALID_IP = re.compile(
r'(10.\d+.\d+.\d+' r'(10.\d+.\d+.\d+'
r'|172.(1[6-9]|2\d|3[0-1])' r'|172.(1[6-9]|2\d|3[0-1])'
r'|192.168.\d+.\d+)', r'|192.168.\d+.\d+)',
re.IGNORECASE) re.IGNORECASE)
def connect_to_network(): def connect_to_network():
"""Connect to network if not already connected.""" """Connect to network if not already connected."""
net_ifs = psutil.net_if_addrs() net_ifs = psutil.net_if_addrs()
net_ifs = [i[:2] for i in net_ifs.keys()] net_ifs = [i[:2] for i in net_ifs.keys()]
# Bail if currently connected # Bail if currently connected
if is_connected(): if is_connected():
return return
# WiFi
if 'wl' in net_ifs:
cmd = [
'nmcli', 'dev', 'wifi',
'connect', WIFI_SSID,
'password', WIFI_PASSWORD]
try_and_print(
message = 'Connecting to {}...'.format(WIFI_SSID),
function = run_program,
cmd = cmd)
# WiFi
if 'wl' in net_ifs:
cmd = [
'nmcli', 'dev', 'wifi',
'connect', WIFI_SSID,
'password', WIFI_PASSWORD]
try_and_print(
message = 'Connecting to {}...'.format(WIFI_SSID),
function = run_program,
cmd = cmd)
def is_connected(): def is_connected():
"""Check for a valid private IP.""" """Check for a valid private IP."""
devs = psutil.net_if_addrs() devs = psutil.net_if_addrs()
for dev in devs.values(): for dev in devs.values():
for family in dev: for family in dev:
if REGEX_VALID_IP.search(family.address): if REGEX_VALID_IP.search(family.address):
# Valid IP found # Valid IP found
return True return True
# Else # Else
return False return False
def show_valid_addresses(): def show_valid_addresses():
"""Show all valid private IP addresses assigned to the system.""" """Show all valid private IP addresses assigned to the system."""
devs = psutil.net_if_addrs() devs = psutil.net_if_addrs()
for dev, families in sorted(devs.items()): for dev, families in sorted(devs.items()):
for family in families: for family in families:
if REGEX_VALID_IP.search(family.address): if REGEX_VALID_IP.search(family.address):
# Valid IP found # Valid IP found
show_data(message=dev, data=family.address) show_data(message=dev, data=family.address)
def speedtest(): def speedtest():
"""Run a network speedtest using speedtest-cli.""" """Run a network speedtest using speedtest-cli."""
result = run_program(['speedtest-cli', '--simple']) result = run_program(['speedtest-cli', '--simple'])
output = [line.strip() for line in result.stdout.decode().splitlines() output = [line.strip() for line in result.stdout.decode().splitlines()
if line.strip()] if line.strip()]
output = [line.split() for line in output] output = [line.split() for line in output]
output = [(a, float(b), c) for a, b, c in output] output = [(a, float(b), c) for a, b, c in output]
return ['{:10}{:6.2f} {}'.format(*line) for line in output] return ['{:10}{:6.2f} {}'.format(*line) for line in output]
if __name__ == '__main__': if __name__ == '__main__':
print("This file is not meant to be called directly.") print("This file is not meant to be called directly.")
# vim: sts=2 sw=2 ts=2

View file

@ -1,326 +0,0 @@
# Wizard Kit: Functions - PARTITION UIDs
# sources: https://en.wikipedia.org/wiki/GUID_Partition_Table
# https://en.wikipedia.org/wiki/Partition_type
# NOTE: Info has been trimmed for brevity. As such, there may be some inaccuracy.
PARTITION_UIDS = {
'00': {'OS': 'All','Description': 'Empty partition entry'},
'01': {'OS': 'DOS','Description': 'FAT12 as primary partition'},
'02': {'OS': 'XENIX','Description': 'XENIX root'},
'03': {'OS': 'XENIX','Description': 'XENIX usr'},
'04': {'OS': 'DOS','Description': 'FAT16 with less than 32 MB'},
'05': {'OS': 'DOS / SpeedStor','Description': 'Extended partition'},
'06': {'OS': 'DOS1+','Description': 'FAT16B [over 65K sectors]'},
'07': {'OS': 'Windows / OS/2 / QNX 2','Description': 'NTFS/exFAT/HPFS/IFS/QNX'},
'08': {'OS': 'CBM / DOS / OS/2 / AIX /QNX','Description': 'FAT12-16/AIX/QNY/SplitDrive'},
'09': {'OS': 'AIX / QNX / Coherent / OS-9','Description': 'AIX/QNZ/Coherent/RBF'},
'0A': {'OS': 'OS/2 / Coherent','Description': 'Boot Manager / Swap'},
'0B': {'OS': 'DOS','Description': 'FAT32 with CHS addressing'},
'0C': {'OS': 'DOS','Description': 'FAT32 with LBA'},
'0D': {'OS': 'Silicon Safe','Description': 'Reserved'},
'0E': {'OS': 'DOS','Description': 'FAT16B with LBA'},
'0F': {'OS': 'DOS','Description': 'Extended partition with LBA'},
'10': {'OS': 'OPUS','Description': 'Unknown'},
'11': {'OS': 'Leading Edge MS-DOS / OS/2','Description': 'FAT12/FAT16'},
'12': {'OS': 'Compaq Contura','Description': 'conf/diag/hiber/rescue/serv'},
'14': {'OS': 'AST DOS / OS/2 / MaverickOS','Description': 'FAT12/FAT16/Omega'},
'15': {'OS': 'OS/2 / Maverick OS','Description': 'Hidden extended / Swap'},
'16': {'OS': 'OS/2 Boot Manager','Description': 'Hidden FAT16B'},
'17': {'OS': 'OS/2 Boot Manager','Description': 'Hidden IFS/HPFS/NTFS/exFAT'},
'18': {'OS': 'AST Windows','Description': '0-Volt Suspend/SmartSleep'},
'19': {'OS': 'Willowtech Photon coS','Description': 'Willowtech Photon coS'},
'1B': {'OS': 'OS/2 Boot Manager','Description': 'Hidden FAT32'},
'1C': {'OS': 'OS/2 Boot Manager','Description': 'Hidden FAT32 with LBA'},
'1E': {'OS': 'OS/2 Boot Manager','Description': 'Hidden FAT16 with LBA'},
'1F': {'OS': 'OS/2 Boot Manager','Description': 'Hidden extended with LBA'},
'20': {'OS': 'Windows Mobile','Description': 'update XIP/Willowsoft OFS1'},
'21': {'OS': 'Oxygen','Description': 'SpeedStor / FSo2'},
'22': {'OS': 'Oxygen','Description': 'Oxygen Extended Partition'},
'23': {'OS': 'Windows Mobile','Description': 'Reserved / boot XIP'},
'24': {'OS': 'NEC MS-DOS0','Description': 'Logical FAT12 or FAT16'},
'25': {'OS': 'Windows Mobile','Description': 'IMGFS[citation needed]'},
'26': {'OS': 'Microsoft, IBM','Description': 'Reserved'},
'27': {'OS': 'Win/PQserv/MirOS/RooterBOOT','Description': 'WinRE/Rescue/MirOS/RooterBOOT'},
'2A': {'OS': 'AtheOS','Description': 'AthFS/AFS/Reserved'},
'2B': {'OS': 'SyllableOS','Description': 'SyllableSecure (SylStor)'},
'31': {'OS': 'Microsoft, IBM','Description': 'Reserved'},
'32': {'OS': 'NOS','Description': 'Unknown'},
'33': {'OS': 'Microsoft, IBM','Description': 'Reserved'},
'34': {'OS': 'Microsoft, IBM','Description': 'Reserved'},
'35': {'OS': 'OS/2 Server /eComStation','Description': 'JFS'},
'36': {'OS': 'Microsoft, IBM','Description': 'Reserved'},
'38': {'OS': 'THEOS','Description': 'THEOS version 3.2, 2 GB'},
'39': {'OS': 'Plan 9 / THEOS','Description': 'Plan 9 edition 3 / THEOS v4'},
'3A': {'OS': 'THEOS','Description': 'THEOS v4, 4 GB'},
'3B': {'OS': 'THEOS','Description': 'THEOS v4 extended'},
'3C': {'OS': 'PartitionMagic','Description': 'PqRP (image in progress)'},
'3D': {'OS': 'PartitionMagic','Description': 'Hidden NetWare'},
'3F': {'OS': 'OS/32','Description': 'Unknown'},
'40': {'OS': 'PICK / Venix','Description': 'PICK R83 / Venix 80286'},
'41': {'OS': 'RISC / Linux / PowerPC','Description': 'Boot / Old Linux/Minix'},
'42': {'OS': 'SFS / Linux / Win2K/XP/etc','Description': 'SFS / Old Linux Swap'},
'43': {'OS': 'Linux','Description': 'Old Linux native'},
'44': {'OS': 'GoBack','Description': 'Norton/WildFire/Adaptec/Roxio'},
'45': {'OS': 'Boot-US / EUMEL/ELAN','Description': 'Priam/Boot/EUMEL/ELAN (L2)'},
'46': {'OS': 'EUMEL/ELAN','Description': 'EUMEL/ELAN (L2)'},
'47': {'OS': 'EUMEL/ELAN','Description': 'EUMEL/ELAN (L2)'},
'48': {'OS': 'EUMEL/ELAN','Description': 'EUMEL/ELAN (L2), ERGOS L3'},
'4A': {'OS': 'AdaOS / ALFS/THIN','Description': 'Aquila / ALFS/THIN'},
'4C': {'OS': 'ETH Oberon','Description': 'Aos (A2) file system (76)'},
'4D': {'OS': 'QNX Neutrino','Description': 'Primary QNX POSIX volume'},
'4E': {'OS': 'QNX Neutrino','Description': 'Secondary QNX POSIX volume'},
'4F': {'OS': 'QNX Neutrino / ETH Oberon','Description': '3rd QNX POSIX/Boot/Native'},
'50': {'OS': 'DiskMan4/ETH/LynxOS/Novell','Description': 'Alt FS/Read-only/Lynx RTOS'},
'51': {'OS': 'Disk Manager 4-6','Description': 'R/W partition (Aux 1)'},
'52': {'OS': 'CP/M-80/ System V/AT, V/386','Description': 'CP/M-80'},
'53': {'OS': 'Disk Manager 6','Description': 'Auxiliary 3 (WO)'},
'54': {'OS': 'Disk Manager 6','Description': 'Dynamic Drive Overlay (DDO)'},
'55': {'OS': 'EZ-Drive','Description': 'Maxtor/MaxBlast/DriveGuide'},
'56': {'OS': 'AT&T DOS/EZ-Drive/VFeature','Description': 'FAT12~16/EZ-BIOS/VFeature'},
'57': {'OS': 'DrivePro','Description': 'VNDI partition'},
'5C': {'OS': 'EDISK','Description': 'Priam EDisk Volume'},
'61': {'OS': 'SpeedStor','Description': 'Unknown'},
'63': {'OS': 'Unix','Description': 'Unix,ISC,SysV,ix,BSD,HURD'},
'64': {'OS': 'SpeedStor / NetWare','Description': 'NetWare FS 286/2,PC-ARMOUR'},
'65': {'OS': 'NetWare','Description': 'NetWare File System 386'},
'66': {'OS': 'NetWare / NetWare','Description': 'NetWare FS 386 / SMS'},
'67': {'OS': 'NetWare','Description': 'Wolf Mountain'},
'68': {'OS': 'NetWare','Description': 'Unknown'},
'69': {'OS': 'NetWare 5 / NetWare','Description': 'Novell Storage Services'},
'6E': {'Description': 'Unknown'},
'70': {'OS': 'DiskSecure','Description': 'DiskSecure multiboot'},
'71': {'OS': 'Microsoft, IBM','Description': 'Reserved'},
'72': {'OS': 'APTI systems / Unix V7/x86','Description': 'APTI altFAT12 / V7 / x86'},
'73': {'OS': 'Microsoft, IBM','Description': 'Reserved'},
'74': {'OS': 'Microsoft, IBM','Description': 'Reserved / Scramdisk'},
'75': {'OS': 'PC/IX','Description': 'Unknown'},
'76': {'OS': 'Microsoft, IBM','Description': 'Reserved'},
'77': {'OS': 'Novell','Description': 'VNDI, M2FS, M2CS'},
'78': {'OS': 'Geurt Vos','Description': 'XOSL bootloader file system'},
'79': {'OS': 'APTI conformant systems','Description': 'APTI altFAT16 (CHS, SFN)'},
'7A': {'OS': 'APTI conformant systems','Description': 'APTI altFAT16 (LBA, SFN)'},
'7B': {'OS': 'APTI conformant systems','Description': 'APTI altFAT16B (CHS, SFN)'},
'7C': {'OS': 'APTI conformant systems','Description': 'APTI altFAT32 (LBA, SFN)'},
'7D': {'OS': 'APTI conformant systems','Description': 'APTI altFAT32 (CHS, SFN)'},
'7E': {'OS': 'F.I.X. (claim) / PrimoCache','Description': 'Level 2 cache'},
'7F': {'OS': 'Varies','Description': 'AltOS DevPartition Standard'},
'80': {'OS': 'Minix 1.1-1.4a','Description': 'Minix file system (old)'},
'81': {'OS': 'Minix 1.4b+ / Linux','Description': 'MINIX FS/Mitac AdvDiskManager'},
'82': {'OS': 'Linux / Sun Microsystems','Description': 'Swap / Solaris x86 / Prime'},
'83': {'OS': 'GNU/Linux','Description': 'Any native Linux FS'},
'84': {'OS': 'OS/2 / Windows 7','Description': 'Hibernat/HiddenC/RapidStart'},
'85': {'OS': 'GNU/Linux','Description': 'Linux extended'},
'86': {'OS': 'Windows NT 4 Server / Linux','Description': 'FAT16B mirror/LinuxRAID-old'},
'87': {'OS': 'Windows NT 4 Server','Description': 'HPFS/NTFS mirrored volume'},
'88': {'OS': 'GNU/Linux','Description': 'Plaintext partition table'},
'8A': {'OS': 'AiR-BOOT','Description': 'Linux kernel image'},
'8B': {'OS': 'Windows NT 4 Server','Description': 'FAT32 mirrored volume set'},
'8C': {'OS': 'Windows NT 4 Server','Description': 'FAT32 mirrored volume set'},
'8D': {'OS': 'Free FDISK','Description': 'Hidden FAT12'},
'8E': {'OS': 'Linux','Description': 'Linux LVM'},
'90': {'OS': 'Free FDISK','Description': 'Hidden FAT16'},
'91': {'OS': 'Free FDISK','Description': 'Hidden extended partition'},
'92': {'OS': 'Free FDISK','Description': 'Hidden FAT16B'},
'93': {'OS': 'Amoeba / Linux','Description': 'Amoeba native/Hidden Linux'},
'94': {'OS': 'Amoeba','Description': 'Amoeba bad block table'},
'95': {'OS': 'EXOPC','Description': 'EXOPC native'},
'96': {'OS': 'CHRP','Description': 'ISO-9660 file system'},
'97': {'OS': 'Free FDISK','Description': 'Hidden FAT32'},
'98': {'OS': 'Free FDISK / ROM-DOS','Description': 'Hidden FAT32 / service part'},
'99': {'OS': 'early Unix','Description': 'Unknown'},
'9A': {'OS': 'Free FDISK','Description': 'Hidden FAT16'},
'9B': {'OS': 'Free FDISK','Description': 'Hidden extended partition'},
'9E': {'OS': 'VSTA / ForthOS','Description': 'ForthOS (eForth port)'},
'9F': {'OS': 'BSD/OS 3.0+, BSDI','Description': 'Unknown'},
'A0': {'OS': 'HP/Phoenix/IBM/Toshiba/Sony','Description': 'Diagnostic for HP/Hibernate'},
'A1': {'OS': 'HP / Phoenix, NEC','Description': 'HP Vol Expansion/Hibernate'},
'A2': {'OS': 'Cyclone V','Description': 'Hard Processor System (HPS)'},
'A3': {'OS': 'HP','Description': 'HP Vol Expansion(SpeedStor)'},
'A4': {'OS': 'HP','Description': 'HP Vol Expansion(SpeedStor)'},
'A5': {'OS': 'BSD','Description': 'BSD slice'},
'A6': {'OS': 'OpenBSD','Description': 'HP Vol Expansion/BSD slice'},
'A7': {'OS': 'NeXT','Description': 'NeXTSTEP'},
'A8': {'OS': 'Darwin, Mac OS X','Description': 'Apple Darwin, Mac OS X UFS'},
'A9': {'OS': 'NetBSD','Description': 'NetBSD slice'},
'AA': {'OS': 'MS-DOS','Description': 'Olivetti DOS FAT12(1.44 MB)'},
'AB': {'OS': 'Darwin, Mac OS X / GO! OS','Description': 'Apple Darwin/OS X boot/GO!'},
'AD': {'OS': 'RISC OS','Description': 'ADFS / FileCore format'},
'AE': {'OS': 'ShagOS','Description': 'ShagOS file system'},
'AF': {'OS': 'ShagOS','Description': 'OS X HFS & HFS+/ShagOS Swap'},
'B0': {'OS': 'Boot-Star','Description': 'Boot-Star dummy partition'},
'B1': {'OS': 'QNX 6.x','Description': 'HPVolExpansion/QNX Neutrino'},
'B2': {'OS': 'QNX 6.x','Description': 'QNX Neutrino power-safe FS'},
'B3': {'OS': 'QNX 6.x','Description': 'HPVolExpansion/QNX Neutrino'},
'B4': {'OS': 'HP','Description': 'HP Vol Expansion(SpeedStor)'},
'B6': {'OS': 'Windows NT 4 Server','Description': 'HPVolExpansion/FAT16Bmirror'},
'B7': {'OS': 'BSDI / Windows NT 4 Server','Description': 'BSDI,Swap,HPFS/NTFS mirror'},
'B8': {'OS': 'BSDI (before 3.0)','Description': 'BSDI Swap / native FS'},
'BB': {'OS': 'Acronis/BootWizard/WinNT 4','Description': 'BootWizard/OEM/FAT32 mirror'},
'BC': {'OS': 'Acronis/WinNT/BackupCapsule','Description': 'FAT32RAID/SecureZone/Backup'},
'BD': {'OS': 'BonnyDOS/286','Description': 'Unknown'},
'BE': {'OS': 'Solaris 8','Description': 'Solaris 8 boot'},
'BF': {'OS': 'Solaris','Description': 'Solaris x86'},
'C0': {'OS': 'DR-DOS,MultiuserDOS,REAL/32','Description': 'Secured FAT (under 32 MB)'},
'C1': {'OS': 'DR DOS','Description': 'Secured FAT12'},
'C2': {'OS': 'Power Boot','Description': 'Hidden Linux native FS'},
'C3': {'OS': 'Power Boot','Description': 'Hidden Linux Swap'},
'C4': {'OS': 'DR DOS','Description': 'Secured FAT16'},
'C5': {'OS': 'DR DOS','Description': 'Secured extended partition'},
'C6': {'OS': 'DR DOS / WinNT 4 Server','Description': 'Secured FAT16B/FAT16Bmirror'},
'C7': {'OS': 'Syrinx / WinNT 4 Server','Description': 'Syrinx boot/HPFS/NTFSmirror'},
'C8': {'Description': "DR-DOS Reserved (since '97)"},
'C9': {'Description': "DR-DOS Reserved (since '97)"},
'CA': {'Description': "DR-DOS Reserved (since '97)"},
'CB': {'OS': 'DR-DOSx / WinNT 4 Server','Description': 'Secured FAT32/FAT32 mirror'},
'CC': {'OS': 'DR-DOSx / WinNT 4 Server','Description': 'Secured FAT32/FAT32 mirror'},
'CD': {'OS': 'CTOS','Description': 'Memory dump'},
'CE': {'OS': 'DR-DOSx','Description': 'Secured FAT16B'},
'CF': {'OS': 'DR-DOSx','Description': 'Secured extended partition'},
'D0': {'OS': 'Multiuser DOS, REAL/32','Description': 'Secured FAT (over 32 MB)'},
'D1': {'OS': 'Multiuser DOS','Description': 'Secured FAT12'},
'D4': {'OS': 'Multiuser DOS','Description': 'Secured FAT16'},
'D5': {'OS': 'Multiuser DOS','Description': 'Secured extended partition'},
'D6': {'OS': 'Multiuser DOS','Description': 'Secured FAT16B'},
'D8': {'OS': 'Digital Research','Description': 'CP/M-86 [citation needed]'},
'DA': {'OS': 'Powercopy Backup','Description': 'Non-FS data / Shielded disk'},
'DB': {'OS': 'CP/M-86/CDOS/CTOS/D800/DRMK','Description': 'CP/M-86/ConcDOS/Boot/FAT32'},
'DD': {'OS': 'CTOS','Description': 'Hidden memory dump'},
'DE': {'OS': 'Dell','Description': 'FAT16 utility/diagnostic'},
'DF': {'OS': 'DG/UX / BootIt / Aviion','Description': 'DG/UX Virt DiskMan / EMBRM'},
'E0': {'OS': 'STMicroelectronics','Description': 'ST AVFS'},
'E1': {'OS': 'SpeedStor','Description': 'ExtendedFAT12 >1023cylinder'},
'E2': {'Description': 'DOS read-only (XFDISK)'},
'E3': {'OS': 'SpeedStor','Description': 'DOS read-only'},
'E4': {'OS': 'SpeedStor','Description': 'ExtendedFAT16 <1024cylinder'},
'E5': {'OS': 'Tandy MS-DOS','Description': 'Logical FAT12 or FAT16'},
'E6': {'OS': 'SpeedStor','Description': 'Unknown'},
'E8': {'OS': 'LUKS','Description': 'Linux Unified Key Setup'},
'EB': {'OS': 'BeOS, Haiku','Description': 'BFS'},
'EC': {'OS': 'SkyOS','Description': 'SkyFS'},
'ED': {'OS': 'Sprytix / EDD 4','Description': 'EDC loader / GPT hybrid MBR'},
'EE': {'OS': 'EFI','Description': 'GPT protective MBR'},
'EF': {'OS': 'EFI','Description': 'EFI system partition'},
'F0': {'OS': 'Linux / OS/32','Description': 'PA-RISC Linux boot loader.'},
'F1': {'OS': 'SpeedStor','Description': 'Unknown'},
'F2': {'OS': 'SperryIT DOS/Unisys DOS','Description': 'Logical FAT12/FAT16'},
'F3': {'OS': 'SpeedStor','Description': 'Unknown'},
'F4': {'OS': 'SpeedStor / Prologue','Description': '"large"DOS part/NGF/TwinFS'},
'F5': {'OS': 'Prologue','Description': 'MD0-MD9 part for NGF/TwinFS'},
'F6': {'OS': 'SpeedStor','Description': 'Unknown'},
'F7': {'OS': 'O.S.G. / X1','Description': 'EFAT / Solid State FS'},
'F9': {'OS': 'Linux','Description': 'pCache ext2/ext3 cache'},
'FA': {'OS': 'Bochs','Description': 'x86 emulator'},
'FB': {'OS': 'VMware','Description': 'VMware VMFS partition'},
'FC': {'OS': 'VMware','Description': 'Swap / VMKCORE kernel dump'},
'FD': {'OS': 'Linux / FreeDOS','Description': 'LinuxRAID/Reserved4FreeDOS'},
'FE': {'OS': 'SpeedStor/LANstep/NT/Linux','Description': 'PS/2/DiskAdmin/old LinuxLVM'},
'FF': {'OS': 'XENIX','Description': 'XENIX bad block table'},
'00000000-0000-0000-0000-000000000000': {'Description': 'Unused entry'},
'024DEE41-33E7-11D3-9D69-0008C781F39F': {'Description': 'MBR partition scheme'},
'C12A7328-F81F-11D2-BA4B-00A0C93EC93B': {'Description': 'EFI System partition'},
'21686148-6449-6E6F-744E-656564454649': {'Description': 'BIOS Boot partition'},
'D3BFE2DE-3DAF-11DF-BA40-E3A556D89593': {'Description': 'Intel Fast Flash (iFFS) partition (for Intel Rapid Start technology)'},
'F4019732-066E-4E12-8273-346C5641494F': {'Description': 'Sony boot partition'},
'BFBFAFE7-A34F-448A-9A5B-6213EB736C22': {'Description': 'Lenovo boot partition'},
'E3C9E316-0B5C-4DB8-817D-F92DF00215AE': {'OS': 'Windows', 'Description': 'Microsoft Reserved Partition (MSR)'},
'EBD0A0A2-B9E5-4433-87C0-68B6B72699C7': {'OS': 'Windows', 'Description': 'Basic data partition'},
'5808C8AA-7E8F-42E0-85D2-E1E90434CFB3': {'OS': 'Windows', 'Description': 'Logical Disk Manager (LDM) metadata partition'},
'AF9B60A0-1431-4F62-BC68-3311714A69AD': {'OS': 'Windows', 'Description': 'Logical Disk Manager data partition'},
'DE94BBA4-06D1-4D40-A16A-BFD50179D6AC': {'OS': 'Windows', 'Description': 'Windows Recovery Environment'},
'37AFFC90-EF7D-4E96-91C3-2D7AE055B174': {'OS': 'Windows', 'Description': 'IBM General Parallel File System (GPFS) partition'},
'E75CAF8F-F680-4CEE-AFA3-B001E56EFC2D': {'OS': 'Windows', 'Description': 'Storage Spaces partition'},
'75894C1E-3AEB-11D3-B7C1-7B03A0000000': {'OS': 'HP-UX', 'Description': 'Data partition'},
'E2A1E728-32E3-11D6-A682-7B03A0000000': {'OS': 'HP-UX', 'Description': 'Service Partition'},
'0FC63DAF-8483-4772-8E79-3D69D8477DE4': {'OS': 'Linux', 'Description': 'Linux filesystem data'},
'A19D880F-05FC-4D3B-A006-743F0F84911E': {'OS': 'Linux', 'Description': 'RAID partition'},
'44479540-F297-41B2-9AF7-D131D5F0458A': {'OS': 'Linux', 'Description': 'Root partition (x86)'},
'4F68BCE3-E8CD-4DB1-96E7-FBCAF984B709': {'OS': 'Linux', 'Description': 'Root partition (x86-64)'},
'69DAD710-2CE4-4E3C-B16C-21A1D49ABED3': {'OS': 'Linux', 'Description': 'Root partition (32-bit ARM)'},
'B921B045-1DF0-41C3-AF44-4C6F280D3FAE': {'OS': 'Linux', 'Description': 'Root partition (64-bit ARM)/AArch64)'},
'0657FD6D-A4AB-43C4-84E5-0933C84B4F4F': {'OS': 'Linux', 'Description': 'Swap partition'},
'E6D6D379-F507-44C2-A23C-238F2A3DF928': {'OS': 'Linux', 'Description': 'Logical Volume Manager (LVM) partition'},
'933AC7E1-2EB4-4F13-B844-0E14E2AEF915': {'OS': 'Linux', 'Description': '/home partition'},
'3B8F8425-20E0-4F3B-907F-1A25A76F98E8': {'OS': 'Linux', 'Description': '/srv (server data) partition'},
'7FFEC5C9-2D00-49B7-8941-3EA10A5586B7': {'OS': 'Linux', 'Description': 'Plain dm-crypt partition'},
'CA7D7CCB-63ED-4C53-861C-1742536059CC': {'OS': 'Linux', 'Description': 'LUKS partition'},
'8DA63339-0007-60C0-C436-083AC8230908': {'OS': 'Linux', 'Description': 'Reserved'},
'83BD6B9D-7F41-11DC-BE0B-001560B84F0F': {'OS': 'FreeBSD', 'Description': 'Boot partition'},
'516E7CB4-6ECF-11D6-8FF8-00022D09712B': {'OS': 'FreeBSD', 'Description': 'Data partition'},
'516E7CB5-6ECF-11D6-8FF8-00022D09712B': {'OS': 'FreeBSD', 'Description': 'Swap partition'},
'516E7CB6-6ECF-11D6-8FF8-00022D09712B': {'OS': 'FreeBSD', 'Description': 'Unix File System (UFS) partition'},
'516E7CB8-6ECF-11D6-8FF8-00022D09712B': {'OS': 'FreeBSD', 'Description': 'Vinum volume manager partition'},
'516E7CBA-6ECF-11D6-8FF8-00022D09712B': {'OS': 'FreeBSD', 'Description': 'ZFS partition'},
'48465300-0000-11AA-AA11-00306543ECAC': {'OS': 'OS X Darwin', 'Description': 'Hierarchical File System Plus (HFS+) partition'},
'55465300-0000-11AA-AA11-00306543ECAC': {'OS': 'OS X Darwin', 'Description': 'Apple UFS'},
'6A898CC3-1DD2-11B2-99A6-080020736631': {'OS': 'OS X Darwin', 'Description': 'ZFS'},
'52414944-0000-11AA-AA11-00306543ECAC': {'OS': 'OS X Darwin', 'Description': 'Apple RAID partition'},
'52414944-5F4F-11AA-AA11-00306543ECAC': {'OS': 'OS X Darwin', 'Description': 'Apple RAID partition, offline'},
'426F6F74-0000-11AA-AA11-00306543ECAC': {'OS': 'OS X Darwin', 'Description': 'Apple Boot partition (Recovery HD)'},
'4C616265-6C00-11AA-AA11-00306543ECAC': {'OS': 'OS X Darwin', 'Description': 'Apple Label'},
'5265636F-7665-11AA-AA11-00306543ECAC': {'OS': 'OS X Darwin', 'Description': 'Apple TV Recovery partition'},
'53746F72-6167-11AA-AA11-00306543ECAC': {'OS': 'OS X Darwin', 'Description': 'Apple Core Storage (i.e. Lion FileVault) partition'},
'6A82CB45-1DD2-11B2-99A6-080020736631': {'OS': 'Solaris illumos', 'Description': 'Boot partition'},
'6A85CF4D-1DD2-11B2-99A6-080020736631': {'OS': 'Solaris illumos', 'Description': 'Root partition'},
'6A87C46F-1DD2-11B2-99A6-080020736631': {'OS': 'Solaris illumos', 'Description': 'Swap partition'},
'6A8B642B-1DD2-11B2-99A6-080020736631': {'OS': 'Solaris illumos', 'Description': 'Backup partition'},
'6A898CC3-1DD2-11B2-99A6-080020736631': {'OS': 'Solaris illumos', 'Description': '/usr partition'},
'6A8EF2E9-1DD2-11B2-99A6-080020736631': {'OS': 'Solaris illumos', 'Description': '/var partition'},
'6A90BA39-1DD2-11B2-99A6-080020736631': {'OS': 'Solaris illumos', 'Description': '/home partition'},
'6A9283A5-1DD2-11B2-99A6-080020736631': {'OS': 'Solaris illumos', 'Description': 'Alternate sector'},
'6A945A3B-1DD2-11B2-99A6-080020736631': {'OS': 'Solaris illumos', 'Description': 'Reserved partition'},
'6A9630D1-1DD2-11B2-99A6-080020736631': {'OS': 'Solaris illumos'},
'6A980767-1DD2-11B2-99A6-080020736631': {'OS': 'Solaris illumos'},
'6A96237F-1DD2-11B2-99A6-080020736631': {'OS': 'Solaris illumos'},
'6A8D2AC7-1DD2-11B2-99A6-080020736631': {'OS': 'Solaris illumos'},
'49F48D32-B10E-11DC-B99B-0019D1879648': {'OS': 'NetBSD', 'Description': 'Swap partition'},
'49F48D5A-B10E-11DC-B99B-0019D1879648': {'OS': 'NetBSD', 'Description': 'FFS partition'},
'49F48D82-B10E-11DC-B99B-0019D1879648': {'OS': 'NetBSD', 'Description': 'LFS partition'},
'49F48DAA-B10E-11DC-B99B-0019D1879648': {'OS': 'NetBSD', 'Description': 'RAID partition'},
'2DB519C4-B10F-11DC-B99B-0019D1879648': {'OS': 'NetBSD', 'Description': 'Concatenated partition'},
'2DB519EC-B10F-11DC-B99B-0019D1879648': {'OS': 'NetBSD', 'Description': 'Encrypted partition'},
'FE3A2A5D-4F32-41A7-B725-ACCC3285A309': {'OS': 'ChromeOS', 'Description': 'ChromeOS kernel'},
'3CB8E202-3B7E-47DD-8A3C-7FF2A13CFCEC': {'OS': 'ChromeOS', 'Description': 'ChromeOS rootfs'},
'2E0A753D-9E48-43B0-8337-B15192CB1B5E': {'OS': 'ChromeOS', 'Description': 'ChromeOS future use'},
'42465331-3BA3-10F1-802A-4861696B7521': {'OS': 'Haiku', 'Description': 'Haiku BFS'},
'85D5E45E-237C-11E1-B4B3-E89A8F7FC3A7': {'OS': 'MidnightBSD', 'Description': 'Boot partition'},
'85D5E45A-237C-11E1-B4B3-E89A8F7FC3A7': {'OS': 'MidnightBSD', 'Description': 'Data partition'},
'85D5E45B-237C-11E1-B4B3-E89A8F7FC3A7': {'OS': 'MidnightBSD', 'Description': 'Swap partition'},
'0394EF8B-237E-11E1-B4B3-E89A8F7FC3A7': {'OS': 'MidnightBSD', 'Description': 'Unix File System (UFS) partition'},
'85D5E45C-237C-11E1-B4B3-E89A8F7FC3A7': {'OS': 'MidnightBSD', 'Description': 'Vinum volume manager partition'},
'85D5E45D-237C-11E1-B4B3-E89A8F7FC3A7': {'OS': 'MidnightBSD', 'Description': 'ZFS partition'},
'45B0969E-9B03-4F30-B4C6-B4B80CEFF106': {'OS': 'Ceph', 'Description': 'Ceph Journal'},
'45B0969E-9B03-4F30-B4C6-5EC00CEFF106': {'OS': 'Ceph', 'Description': 'Ceph dm-crypt Encrypted Journal'},
'4FBD7E29-9D25-41B8-AFD0-062C0CEFF05D': {'OS': 'Ceph', 'Description': 'Ceph OSD'},
'4FBD7E29-9D25-41B8-AFD0-5EC00CEFF05D': {'OS': 'Ceph', 'Description': 'Ceph dm-crypt OSD'},
'89C57F98-2FE5-4DC0-89C1-F3AD0CEFF2BE': {'OS': 'Ceph', 'Description': 'Ceph disk in creation'},
'89C57F98-2FE5-4DC0-89C1-5EC00CEFF2BE': {'OS': 'Ceph', 'Description': 'Ceph dm-crypt disk in creation'},
'824CC7A0-36A8-11E3-890A-952519AD3F61': {'OS': 'OpenBSD', 'Description': 'Data partition'},
'CEF5A9AD-73BC-4601-89F3-CDEEEEE321A1': {'OS': 'QNX', 'Description': 'Power-safe (QNX6) file system'},
'C91818F9-8025-47AF-89D2-F030D7000C2C': {'OS': 'Plan 9', 'Description': 'Plan 9 partition'},
'9D275380-40AD-11DB-BF97-000C2911D1B8': {'OS': 'VMware ESX', 'Description': 'vmkcore (coredump partition)'},
'AA31E02A-400F-11DB-9590-000C2911D1B8': {'OS': 'VMware ESX', 'Description': 'VMFS filesystem partition'},
'9198EFFC-31C0-11DB-8F78-000C2911D1B8': {'OS': 'VMware ESX', 'Description': 'VMware Reserved'},
'2568845D-2332-4675-BC39-8FA5A4748D15': {'OS': 'Android-IA', 'Description': 'Bootloader'},
'114EAFFE-1552-4022-B26E-9B053604CF84': {'OS': 'Android-IA', 'Description': 'Bootloader2'},
'49A4D17F-93A3-45C1-A0DE-F50B2EBE2599': {'OS': 'Android-IA', 'Description': 'Boot'},
'4177C722-9E92-4AAB-8644-43502BFD5506': {'OS': 'Android-IA', 'Description': 'Recovery'},
'EF32A33B-A409-486C-9141-9FFB711F6266': {'OS': 'Android-IA', 'Description': 'Misc'},
'20AC26BE-20B7-11E3-84C5-6CFDB94711E9': {'OS': 'Android-IA', 'Description': 'Metadata'},
'38F428E6-D326-425D-9140-6E0EA133647C': {'OS': 'Android-IA', 'Description': 'System'},
'A893EF21-E428-470A-9E55-0668FD91A2D9': {'OS': 'Android-IA', 'Description': 'Cache'},
'DC76DDA9-5AC1-491C-AF42-A82591580C0D': {'OS': 'Android-IA', 'Description': 'Data'},
'EBC597D0-2053-4B15-8B64-E0AAC75F4DB1': {'OS': 'Android-IA', 'Description': 'Persistent'},
'8F68CC74-C5E5-48DA-BE91-A0C8C15E9C80': {'OS': 'Android-IA', 'Description': 'Factory'},
'767941D0-2085-11E3-AD3B-6CFDB94711E9': {'OS': 'Android-IA', 'Description': 'Fastboot / Tertiary'},
'AC6D7924-EB71-4DF8-B48D-E267B27148FF': {'OS': 'Android-IA', 'Description': 'OEM'},
'7412F7D5-A156-4B13-81DC-867174929325': {'OS': 'ONIE', 'Description': 'Boot'},
'D4E6E2CD-4469-46F3-B5CB-1BFF57AFC149': {'OS': 'ONIE', 'Description': 'Config'},
'9E1A2D38-C612-4316-AA26-8B49521E5A8B': {'OS': 'PowerPC', 'Description': 'PReP boot'},
'BC13C2FF-59E6-4262-A352-B275FD6F7172': {'OS': 'Freedesktop', 'Description': 'Extended Boot Partition ($BOOT)'},
}
def lookup_guid(guid):
return PARTITION_UIDS.get(guid.upper(), {})
if __name__ == '__main__':
print("This file is not meant to be called directly.")

View file

@ -2,110 +2,119 @@
from functions.common import * from functions.common import *
# Regex # Regex
REGEX_REGISTRY_DIRS = re.compile( REGEX_REGISTRY_DIRS = re.compile(
r'^(config$|RegBack$|System32$|Transfer|Win)', r'^(config$|RegBack$|System32$|Transfer|Win)',
re.IGNORECASE) re.IGNORECASE)
REGEX_SOFTWARE_HIVE = re.compile(r'^Software$', re.IGNORECASE) REGEX_SOFTWARE_HIVE = re.compile(r'^Software$', re.IGNORECASE)
def extract_keys(): def extract_keys():
"""Extract keys from provided hives and return a dict.""" """Extract keys from provided hives and return a dict."""
keys = {} keys = {}
# Extract keys # Extract keys
extract_item('ProduKey', silent=True) extract_item('ProduKey', silent=True)
for hive in find_software_hives(): for hive in find_software_hives():
cmd = [ cmd = [
global_vars['Tools']['ProduKey'], global_vars['Tools']['ProduKey'],
'/IEKeys', '0', '/IEKeys', '0',
'/WindowsKeys', '1', '/WindowsKeys', '1',
'/OfficeKeys', '1', '/OfficeKeys', '1',
'/ExtractEdition', '1', '/ExtractEdition', '1',
'/nosavereg', '/nosavereg',
'/regfile', hive, '/regfile', hive,
'/scomma', ''] '/scomma', '']
try: try:
out = run_program(cmd) out = run_program(cmd)
except subprocess.CalledProcessError: except subprocess.CalledProcessError:
# Ignore and return empty dict # Ignore and return empty dict
pass pass
else: else:
for line in out.stdout.decode().splitlines(): for line in out.stdout.decode().splitlines():
# Add key to keys under product only if unique # Add key to keys under product only if unique
tmp = line.split(',') tmp = line.split(',')
product = tmp[0] product = tmp[0]
key = tmp[2] key = tmp[2]
if product not in keys: if product not in keys:
keys[product] = [] keys[product] = []
if key not in keys[product]: if key not in keys[product]:
keys[product].append(key) keys[product].append(key)
# Done
return keys
# Done
return keys
def list_clientdir_keys(): def list_clientdir_keys():
"""List product keys found in hives inside the ClientDir.""" """List product keys found in hives inside the ClientDir."""
keys = extract_keys() keys = extract_keys()
key_list = [] key_list = []
if keys: if keys:
for product in sorted(keys): for product in sorted(keys):
key_list.append(product) key_list.append(product)
for key in sorted(keys[product]): for key in sorted(keys[product]):
key_list.append(' {key}'.format(key=key)) key_list.append(' {key}'.format(key=key))
else: else:
key_list.append('No keys found.') key_list.append('No keys found.')
return key_list
return key_list
def find_software_hives(): def find_software_hives():
"""Search for transferred SW hives and return a list.""" """Search for transferred SW hives and return a list."""
hives = [] hives = []
search_paths = [global_vars['ClientDir']] search_paths = [global_vars['ClientDir']]
while len(search_paths) > 0: while len(search_paths) > 0:
for item in os.scandir(search_paths.pop(0)): for item in os.scandir(search_paths.pop(0)):
if item.is_dir() and REGEX_REGISTRY_DIRS.search(item.name): if item.is_dir() and REGEX_REGISTRY_DIRS.search(item.name):
search_paths.append(item.path) search_paths.append(item.path)
if item.is_file() and REGEX_SOFTWARE_HIVE.search(item.name): if item.is_file() and REGEX_SOFTWARE_HIVE.search(item.name):
hives.append(item.path) hives.append(item.path)
return hives
return hives
def get_product_keys(): def get_product_keys():
"""List product keys from saved report.""" """List product keys from saved report."""
keys = [] keys = []
log_file = r'{LogDir}\Product Keys (ProduKey).txt'.format(**global_vars) log_file = r'{LogDir}\Product Keys (ProduKey).txt'.format(**global_vars)
with open (log_file, 'r') as f: with open (log_file, 'r') as f:
for line in f.readlines(): for line in f.readlines():
if re.search(r'^Product Name', line): if re.search(r'^Product Name', line):
line = re.sub(r'^Product Name\s+:\s+(.*)', r'\1', line.strip()) line = re.sub(r'^Product Name\s+:\s+(.*)', r'\1', line.strip())
keys.append(line) keys.append(line)
if keys:
return keys
else:
return ['No product keys found']
if keys:
return keys
else:
return ['No product keys found']
def run_produkey(): def run_produkey():
"""Run ProduKey and save report in the ClientDir.""" """Run ProduKey and save report in the ClientDir."""
extract_item('ProduKey', silent=True) extract_item('ProduKey', silent=True)
log_file = r'{LogDir}\Product Keys (ProduKey).txt'.format(**global_vars) log_file = r'{LogDir}\Product Keys (ProduKey).txt'.format(**global_vars)
if not os.path.exists(log_file): if not os.path.exists(log_file):
# Clear current configuration # Clear current configuration
for config in ['ProduKey.cfg', 'ProduKey64.cfg']: for config in ['ProduKey.cfg', 'ProduKey64.cfg']:
config = r'{BinDir}\ProduKey\{config}'.format( config = r'{BinDir}\ProduKey\{config}'.format(
config=config, **global_vars) config=config, **global_vars)
try: try:
if os.path.exists(config): if os.path.exists(config):
os.remove(config) os.remove(config)
except Exception: except Exception:
pass pass
cmd = [ cmd = [
global_vars['Tools']['ProduKey'], global_vars['Tools']['ProduKey'],
'/nosavereg', '/nosavereg',
'/stext', '/stext',
log_file] log_file]
run_program(cmd, check=False) run_program(cmd, check=False)
if __name__ == '__main__': if __name__ == '__main__':
print("This file is not meant to be called directly.") print("This file is not meant to be called directly.")
# vim: sts=2 sw=2 ts=2

View file

@ -2,125 +2,135 @@
from functions.common import * from functions.common import *
def run_chkdsk(repair=False): def run_chkdsk(repair=False):
"""Run CHKDSK scan or schedule offline repairs.""" """Run CHKDSK scan or schedule offline repairs."""
if repair: if repair:
run_chkdsk_offline() run_chkdsk_offline()
else: else:
run_chkdsk_scan() run_chkdsk_scan()
def run_chkdsk_scan(): def run_chkdsk_scan():
"""Run CHKDSK in a "split window" and report errors.""" """Run CHKDSK in a "split window" and report errors."""
if global_vars['OS']['Version'] in ('8', '8.1', '10'): if global_vars['OS']['Version'] in ('8', '8.1', '10'):
cmd = ['chkdsk', global_vars['Env']['SYSTEMDRIVE'], '/scan', '/perf'] cmd = ['chkdsk', global_vars['Env']['SYSTEMDRIVE'], '/scan', '/perf']
else: else:
cmd = ['chkdsk', global_vars['Env']['SYSTEMDRIVE']] cmd = ['chkdsk', global_vars['Env']['SYSTEMDRIVE']]
out = run_program(cmd, check=False) out = run_program(cmd, check=False)
# retcode == 0: no issues # retcode == 0: no issues
# retcode == 1: fixed issues (also happens when chkdsk.exe is killed?) # retcode == 1: fixed issues (also happens when chkdsk.exe is killed?)
# retcode == 2: issues # retcode == 2: issues
if int(out.returncode) > 0: if int(out.returncode) > 0:
# print_error(' ERROR: CHKDSK encountered errors') # print_error(' ERROR: CHKDSK encountered errors')
raise GenericError raise GenericError
# Save stderr
with open(r'{LogDir}\Tools\CHKDSK.err'.format(**global_vars), 'a') as f:
for line in out.stderr.decode().splitlines():
f.write(line.strip() + '\n')
# Save stdout
with open(r'{LogDir}\Tools\CHKDSK.log'.format(**global_vars), 'a') as f:
for line in out.stdout.decode().splitlines():
f.write(line.strip() + '\n')
# Save stderr
with open(r'{LogDir}\Tools\CHKDSK.err'.format(**global_vars), 'a') as f:
for line in out.stderr.decode().splitlines():
f.write(line.strip() + '\n')
# Save stdout
with open(r'{LogDir}\Tools\CHKDSK.log'.format(**global_vars), 'a') as f:
for line in out.stdout.decode().splitlines():
f.write(line.strip() + '\n')
def run_chkdsk_offline(): def run_chkdsk_offline():
"""Set filesystem 'dirty bit' to force a chkdsk during next boot.""" """Set filesystem 'dirty bit' to force a chkdsk during next boot."""
cmd = [ cmd = [
'fsutil', 'dirty', 'fsutil', 'dirty',
'set', 'set',
global_vars['Env']['SYSTEMDRIVE']] global_vars['Env']['SYSTEMDRIVE']]
out = run_program(cmd, check=False) out = run_program(cmd, check=False)
if int(out.returncode) > 0: if int(out.returncode) > 0:
raise GenericError raise GenericError
def run_dism(repair=False): def run_dism(repair=False):
"""Run DISM /RestoreHealth, then /CheckHealth, and then report errors.""" """Run DISM to either scan or repair component store health."""
if global_vars['OS']['Version'] in ('8', '8.1', '10'): if global_vars['OS']['Version'] in ('8', '8.1', '10'):
if repair: if repair:
# Restore Health # Restore Health
cmd = [ cmd = [
'DISM', '/Online', 'DISM', '/Online',
'/Cleanup-Image', '/RestoreHealth', '/Cleanup-Image', '/RestoreHealth',
r'/LogPath:"{LogDir}\Tools\DISM_RestoreHealth.log"'.format( r'/LogPath:"{LogDir}\Tools\DISM_RestoreHealth.log"'.format(
**global_vars), **global_vars),
'-new_console:n', '-new_console:s33V'] '-new_console:n', '-new_console:s33V']
else:
# Scan Health
cmd = [
'DISM', '/Online',
'/Cleanup-Image', '/ScanHealth',
r'/LogPath:"{LogDir}\Tools\DISM_ScanHealth.log"'.format(
**global_vars),
'-new_console:n', '-new_console:s33V']
run_program(cmd, pipe=False, check=False, shell=True)
wait_for_process('dism')
# Now check health
cmd = [
'DISM', '/Online',
'/Cleanup-Image', '/CheckHealth',
r'/LogPath:"{LogDir}\Tools\DISM_CheckHealth.log"'.format(**global_vars)]
result = run_program(cmd, shell=True).stdout.decode()
# Check result
if 'no component store corruption detected' not in result.lower():
raise GenericError
else: else:
raise UnsupportedOSError # Scan Health
cmd = [
'DISM', '/Online',
'/Cleanup-Image', '/ScanHealth',
r'/LogPath:"{LogDir}\Tools\DISM_ScanHealth.log"'.format(
**global_vars),
'-new_console:n', '-new_console:s33V']
run_program(cmd, pipe=False, check=False, shell=True)
wait_for_process('dism')
# Now check health
cmd = [
'DISM', '/Online',
'/Cleanup-Image', '/CheckHealth',
r'/LogPath:"{LogDir}\Tools\DISM_CheckHealth.log"'.format(**global_vars)]
result = run_program(cmd, shell=True).stdout.decode()
# Check result
if 'no component store corruption detected' not in result.lower():
raise GenericError
else:
raise UnsupportedOSError
def run_kvrt(): def run_kvrt():
"""Run KVRT.""" """Run KVRT."""
extract_item('KVRT', silent=True) extract_item('KVRT', silent=True)
os.makedirs(global_vars['QuarantineDir'], exist_ok=True) os.makedirs(global_vars['QuarantineDir'], exist_ok=True)
cmd = [ cmd = [
global_vars['Tools']['KVRT'], global_vars['Tools']['KVRT'],
'-accepteula', '-dontcryptsupportinfo', '-fixednames', '-accepteula', '-dontcryptsupportinfo', '-fixednames',
'-d', global_vars['QuarantineDir'], '-d', global_vars['QuarantineDir'],
'-processlevel', '3'] '-processlevel', '3']
popen_program(cmd, pipe=False) popen_program(cmd, pipe=False)
def run_sfc_scan(): def run_sfc_scan():
"""Run SFC in a "split window" and report errors.""" """Run SFC in a "split window" and report errors."""
cmd = [ cmd = [
r'{SYSTEMROOT}\System32\sfc.exe'.format(**global_vars['Env']), r'{SYSTEMROOT}\System32\sfc.exe'.format(**global_vars['Env']),
'/scannow'] '/scannow']
out = run_program(cmd, check=False) out = run_program(cmd, check=False)
# Save stderr # Save stderr
with open(r'{LogDir}\Tools\SFC.err'.format(**global_vars), 'a') as f: with open(r'{LogDir}\Tools\SFC.err'.format(**global_vars), 'a') as f:
for line in out.stderr.decode('utf-8', 'ignore').splitlines(): for line in out.stderr.decode('utf-8', 'ignore').splitlines():
f.write(line.strip() + '\n') f.write(line.strip() + '\n')
# Save stdout # Save stdout
with open(r'{LogDir}\Tools\SFC.log'.format(**global_vars), 'a') as f: with open(r'{LogDir}\Tools\SFC.log'.format(**global_vars), 'a') as f:
for line in out.stdout.decode('utf-8', 'ignore').splitlines(): for line in out.stdout.decode('utf-8', 'ignore').splitlines():
f.write(line.strip() + '\n') f.write(line.strip() + '\n')
# Check result # Check result
log_text = out.stdout.decode('utf-8', 'ignore').replace('\0', '') log_text = out.stdout.decode('utf-8', 'ignore').replace('\0', '')
if re.findall(r'did\s+not\s+find\s+any\s+integrity\s+violations', log_text): if re.findall(r'did\s+not\s+find\s+any\s+integrity\s+violations', log_text):
pass pass
elif re.findall(r'successfully\s+repaired\s+them', log_text): elif re.findall(r'successfully\s+repaired\s+them', log_text):
raise GenericRepair raise GenericRepair
else: else:
raise GenericError raise GenericError
def run_tdsskiller(): def run_tdsskiller():
"""Run TDSSKiller.""" """Run TDSSKiller."""
extract_item('TDSSKiller', silent=True) extract_item('TDSSKiller', silent=True)
os.makedirs(r'{QuarantineDir}\TDSSKiller'.format( os.makedirs(r'{QuarantineDir}\TDSSKiller'.format(
**global_vars), exist_ok=True) **global_vars), exist_ok=True)
cmd = [ cmd = [
global_vars['Tools']['TDSSKiller'], global_vars['Tools']['TDSSKiller'],
'-l', r'{LogDir}\Tools\TDSSKiller.log'.format(**global_vars), '-l', r'{LogDir}\Tools\TDSSKiller.log'.format(**global_vars),
'-qpath', r'{QuarantineDir}\TDSSKiller'.format(**global_vars), '-qpath', r'{QuarantineDir}\TDSSKiller'.format(**global_vars),
'-accepteula', '-accepteulaksn', '-accepteula', '-accepteulaksn',
'-dcexact', '-tdlfs'] '-dcexact', '-tdlfs']
run_program(cmd, pipe=False) run_program(cmd, pipe=False)
if __name__ == '__main__': if __name__ == '__main__':
print("This file is not meant to be called directly.") print("This file is not meant to be called directly.")
# vim: sts=2 sw=2 ts=2

View file

@ -2,35 +2,44 @@
from functions.common import * from functions.common import *
# STATIC VARIABLES # STATIC VARIABLES
REG_MSISERVER = r'HKLM\SYSTEM\CurrentControlSet\Control\SafeBoot\Network\MSIServer' REG_MSISERVER = r'HKLM\SYSTEM\CurrentControlSet\Control\SafeBoot\Network\MSIServer'
def disable_safemode_msi(): def disable_safemode_msi():
"""Disable MSI access under safemode.""" """Disable MSI access under safemode."""
cmd = ['reg', 'delete', REG_MSISERVER, '/f'] cmd = ['reg', 'delete', REG_MSISERVER, '/f']
run_program(cmd) run_program(cmd)
def disable_safemode(): def disable_safemode():
"""Edit BCD to remove safeboot value.""" """Edit BCD to remove safeboot value."""
cmd = ['bcdedit', '/deletevalue', '{default}', 'safeboot'] cmd = ['bcdedit', '/deletevalue', '{default}', 'safeboot']
run_program(cmd) run_program(cmd)
def enable_safemode_msi(): def enable_safemode_msi():
"""Enable MSI access under safemode.""" """Enable MSI access under safemode."""
cmd = ['reg', 'add', REG_MSISERVER, '/f'] cmd = ['reg', 'add', REG_MSISERVER, '/f']
run_program(cmd) run_program(cmd)
cmd = ['reg', 'add', REG_MSISERVER, '/ve', cmd = ['reg', 'add', REG_MSISERVER, '/ve',
'/t', 'REG_SZ', '/d', 'Service', '/f'] '/t', 'REG_SZ', '/d', 'Service', '/f']
run_program(cmd) run_program(cmd)
def enable_safemode(): def enable_safemode():
"""Edit BCD to set safeboot as default.""" """Edit BCD to set safeboot as default."""
cmd = ['bcdedit', '/set', '{default}', 'safeboot', 'network'] cmd = ['bcdedit', '/set', '{default}', 'safeboot', 'network']
run_program(cmd) run_program(cmd)
def reboot(delay=3): def reboot(delay=3):
cmd = ['shutdown', '-r', '-t', '{}'.format(delay)] cmd = ['shutdown', '-r', '-t', '{}'.format(delay)]
run_program(cmd, check=False) run_program(cmd, check=False)
if __name__ == '__main__': if __name__ == '__main__':
print("This file is not meant to be called directly.") print("This file is not meant to be called directly.")
# vim: sts=2 sw=2 ts=2

View file

@ -5,6 +5,7 @@ import re
from functions.tmux import * from functions.tmux import *
# STATIC VARIABLES # STATIC VARIABLES
TEMP_LIMITS = { TEMP_LIMITS = {
'GREEN': 60, 'GREEN': 60,
@ -13,9 +14,11 @@ TEMP_LIMITS = {
'RED': 90, 'RED': 90,
} }
# REGEX # REGEX
REGEX_COLORS = re.compile(r'\033\[\d+;?1?m') REGEX_COLORS = re.compile(r'\033\[\d+;?1?m')
def clear_temps(sensor_data): def clear_temps(sensor_data):
"""Clear saved temps but keep structure, returns dict.""" """Clear saved temps but keep structure, returns dict."""
for _section, _adapters in sensor_data.items(): for _section, _adapters in sensor_data.items():
@ -23,6 +26,7 @@ def clear_temps(sensor_data):
for _source, _data in _sources.items(): for _source, _data in _sources.items():
_data['Temps'] = [] _data['Temps'] = []
def fix_sensor_str(s): def fix_sensor_str(s):
"""Cleanup string and return str.""" """Cleanup string and return str."""
s = re.sub(r'^(\w+)-(\w+)-(\w+)', r'\1 (\2 \3)', s, re.IGNORECASE) 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(' ', ' ') s = s.replace(' ', ' ')
return s return s
def generate_sensor_report( def generate_sensor_report(
sensor_data, *temp_labels, sensor_data, *temp_labels,
colors=True, core_only=False): colors=True, core_only=False):
@ -73,6 +78,7 @@ def generate_sensor_report(
# Done # Done
return report return report
def get_colored_temp_str(temp): def get_colored_temp_str(temp):
"""Get colored string based on temp, returns str.""" """Get colored string based on temp, returns str."""
try: try:
@ -97,6 +103,7 @@ def get_colored_temp_str(temp):
temp = temp, temp = temp,
**COLORS) **COLORS)
def get_raw_sensor_data(): def get_raw_sensor_data():
"""Read sensor data and return dict.""" """Read sensor data and return dict."""
data = {} data = {}
@ -110,6 +117,7 @@ def get_raw_sensor_data():
return data return data
def get_sensor_data(): def get_sensor_data():
"""Parse raw sensor data and return new dict.""" """Parse raw sensor data and return new dict."""
json_data = get_raw_sensor_data() json_data = get_raw_sensor_data()
@ -141,6 +149,7 @@ def get_sensor_data():
# Done # Done
return sensor_data return sensor_data
def get_temp_str(temp, colors=True): def get_temp_str(temp, colors=True):
"""Get temp string, returns str.""" """Get temp string, returns str."""
if colors: if colors:
@ -154,6 +163,7 @@ def get_temp_str(temp, colors=True):
'-' if temp < 0 else '', '-' if temp < 0 else '',
temp) temp)
def monitor_sensors(monitor_pane, monitor_file): def monitor_sensors(monitor_pane, monitor_file):
"""Continually update sensor data and report to screen.""" """Continually update sensor data and report to screen."""
sensor_data = get_sensor_data() sensor_data = get_sensor_data()
@ -166,8 +176,9 @@ def monitor_sensors(monitor_pane, monitor_file):
if monitor_pane and not tmux_poll_pane(monitor_pane): if monitor_pane and not tmux_poll_pane(monitor_pane):
break break
def save_average_temp(sensor_data, temp_label, seconds=10): def save_average_temp(sensor_data, temp_label, seconds=10):
"""Calculate average temps and record under temp_label, returns dict.""" """Save average temps under temp_label, returns dict."""
clear_temps(sensor_data) clear_temps(sensor_data)
# Get temps # Get temps
@ -181,6 +192,7 @@ def save_average_temp(sensor_data, temp_label, seconds=10):
for _source, _data in _sources.items(): for _source, _data in _sources.items():
_data[temp_label] = sum(_data['Temps']) / len(_data['Temps']) _data[temp_label] = sum(_data['Temps']) / len(_data['Temps'])
def update_sensor_data(sensor_data): def update_sensor_data(sensor_data):
"""Read sensors and update existing sensor_data, returns dict.""" """Read sensors and update existing sensor_data, returns dict."""
json_data = get_raw_sensor_data() json_data = get_raw_sensor_data()
@ -193,12 +205,14 @@ def update_sensor_data(sensor_data):
_data['Max'] = max(_temp, _data['Max']) _data['Max'] = max(_temp, _data['Max'])
_data['Temps'].append(_temp) _data['Temps'].append(_temp)
def join_columns(column1, column2, width=55): def join_columns(column1, column2, width=55):
return '{:<{}}{}'.format( return '{:<{}}{}'.format(
column1, column1,
55+len(column1)-len(REGEX_COLORS.sub('', column1)), 55+len(column1)-len(REGEX_COLORS.sub('', column1)),
column2) column2)
if __name__ == '__main__': if __name__ == '__main__':
print("This file is not meant to be called directly.") print("This file is not meant to be called directly.")

View file

@ -1,321 +1,339 @@
# Wizard Kit: Functions - Setup # Wizard Kit: Functions - Setup
from functions.common import *
from functions.update import * from functions.update import *
# STATIC VARIABLES # STATIC VARIABLES
HKU = winreg.HKEY_USERS HKU = winreg.HKEY_USERS
HKCR = winreg.HKEY_CLASSES_ROOT HKCR = winreg.HKEY_CLASSES_ROOT
HKCU = winreg.HKEY_CURRENT_USER HKCU = winreg.HKEY_CURRENT_USER
HKLM = winreg.HKEY_LOCAL_MACHINE HKLM = winreg.HKEY_LOCAL_MACHINE
MOZILLA_FIREFOX_UBO_PATH = r'{}\{}\ublock_origin.xpi'.format( MOZILLA_FIREFOX_UBO_PATH = r'{}\{}\ublock_origin.xpi'.format(
os.environ.get('PROGRAMFILES'), os.environ.get('PROGRAMFILES'),
r'Mozilla Firefox\distribution\extensions') r'Mozilla Firefox\distribution\extensions')
OTHER_RESULTS = { OTHER_RESULTS = {
'Error': { 'Error': {
'CalledProcessError': 'Unknown Error', 'CalledProcessError': 'Unknown Error',
'FileNotFoundError': 'File not found', 'FileNotFoundError': 'File not found',
}, },
'Warning': {}} 'Warning': {}}
SETTINGS_CLASSIC_START = { SETTINGS_CLASSIC_START = {
r'Software\IvoSoft\ClassicShell\Settings': {}, r'Software\IvoSoft\ClassicShell\Settings': {},
r'Software\IvoSoft\ClassicStartMenu': { r'Software\IvoSoft\ClassicStartMenu': {
'DWORD Items': {'ShowedStyle2': 1}, 'DWORD Items': {'ShowedStyle2': 1},
}, },
r'Software\IvoSoft\ClassicStartMenu\MRU': {}, r'Software\IvoSoft\ClassicStartMenu\MRU': {},
r'Software\IvoSoft\ClassicStartMenu\Settings': { r'Software\IvoSoft\ClassicStartMenu\Settings': {
'DWORD Items': {'SkipMetro': 1}, 'DWORD Items': {'SkipMetro': 1},
'SZ Items': { 'SZ Items': {
'MenuStyle': 'Win7', 'MenuStyle': 'Win7',
'RecentPrograms': 'Recent', 'RecentPrograms': 'Recent',
}, },
}, },
} }
SETTINGS_EXPLORER_SYSTEM = { SETTINGS_EXPLORER_SYSTEM = {
# Disable Location Tracking # Disable Location Tracking
r'Software\Microsoft\Windows NT\CurrentVersion\Sensor\Overrides\{BFA794E4-F964-4FDB-90F6-51056BFE4B44}': { r'Software\Microsoft\Windows NT\CurrentVersion\Sensor\Overrides\{BFA794E4-F964-4FDB-90F6-51056BFE4B44}': {
'DWORD Items': {'SensorPermissionState': 0}, 'DWORD Items': {'SensorPermissionState': 0},
}, },
r'System\CurrentControlSet\Services\lfsvc\Service\Configuration': { r'System\CurrentControlSet\Services\lfsvc\Service\Configuration': {
'Status': {'Value': 0}, 'Status': {'Value': 0},
}, },
# Disable Telemetry # Disable Telemetry
r'Software\Microsoft\Windows\CurrentVersion\Policies\DataCollection': { r'Software\Microsoft\Windows\CurrentVersion\Policies\DataCollection': {
'DWORD Items': {'AllowTelemetry': 0}, 'DWORD Items': {'AllowTelemetry': 0},
}, },
r'Software\Microsoft\Windows\CurrentVersion\Policies\DataCollection': { r'Software\Microsoft\Windows\CurrentVersion\Policies\DataCollection': {
'DWORD Items': {'AllowTelemetry': 0}, 'DWORD Items': {'AllowTelemetry': 0},
'WOW64_32': True, 'WOW64_32': True,
}, },
r'Software\Policies\Microsoft\Windows\DataCollection': { r'Software\Policies\Microsoft\Windows\DataCollection': {
'DWORD Items': {'AllowTelemetry': 0}, 'DWORD Items': {'AllowTelemetry': 0},
}, },
# Disable Wi-Fi Sense # Disable Wi-Fi Sense
r'Software\Microsoft\PolicyManager\default\WiFi\AllowWiFiHotSpotReporting': { r'Software\Microsoft\PolicyManager\default\WiFi\AllowWiFiHotSpotReporting': {
'DWORD Items': {'Value': 0}, 'DWORD Items': {'Value': 0},
}, },
r'Software\Microsoft\PolicyManager\default\WiFi\AllowAutoConnectToWiFiSenseHotspots': { r'Software\Microsoft\PolicyManager\default\WiFi\AllowAutoConnectToWiFiSenseHotspots': {
'DWORD Items': {'Value': 0}, 'DWORD Items': {'Value': 0},
}, },
} }
SETTINGS_EXPLORER_USER = { SETTINGS_EXPLORER_USER = {
# Disable silently installed apps # Disable silently installed apps
r'Software\Microsoft\Windows\CurrentVersion\ContentDeliveryManager': { r'Software\Microsoft\Windows\CurrentVersion\ContentDeliveryManager': {
'DWORD Items': {'SilentInstalledAppsEnabled': 0}, 'DWORD Items': {'SilentInstalledAppsEnabled': 0},
}, },
# Disable Tips and Tricks # Disable Tips and Tricks
r'Software\Microsoft\Windows\CurrentVersion\ContentDeliveryManager': { r'Software\Microsoft\Windows\CurrentVersion\ContentDeliveryManager': {
'DWORD Items': {'SoftLandingEnabled ': 0}, 'DWORD Items': {'SoftLandingEnabled ': 0},
}, },
# Hide People bar # Hide People bar
r'Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced\People': { r'Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced\People': {
'DWORD Items': {'PeopleBand': 0}, 'DWORD Items': {'PeopleBand': 0},
}, },
# Hide Search button / box # Hide Search button / box
r'Software\Microsoft\Windows\CurrentVersion\Search': { r'Software\Microsoft\Windows\CurrentVersion\Search': {
'DWORD Items': {'SearchboxTaskbarMode': 0}, 'DWORD Items': {'SearchboxTaskbarMode': 0},
}, },
# Change default Explorer view to "Computer" # Change default Explorer view to "Computer"
r'Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced': { r'Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced': {
'DWORD Items': {'LaunchTo': 1}, 'DWORD Items': {'LaunchTo': 1},
}, },
} }
SETTINGS_GOOGLE_CHROME = { SETTINGS_GOOGLE_CHROME = {
r'Software\Google\Chrome\Extensions\cjpalhdlnbpafiamejdnhcphjbkeiagm': { r'Software\Google\Chrome\Extensions\cjpalhdlnbpafiamejdnhcphjbkeiagm': {
'SZ Items': { 'SZ Items': {
'update_url': 'https://clients2.google.com/service/update2/crx'}, 'update_url': 'https://clients2.google.com/service/update2/crx'},
'WOW64_32': True, 'WOW64_32': True,
}, },
r'Software\Google\Chrome\Extensions\pgdnlhfefecpicbbihgmbmffkjpaplco': { r'Software\Google\Chrome\Extensions\pgdnlhfefecpicbbihgmbmffkjpaplco': {
'SZ Items': { 'SZ Items': {
'update_url': 'https://clients2.google.com/service/update2/crx'}, 'update_url': 'https://clients2.google.com/service/update2/crx'},
'WOW64_32': True, 'WOW64_32': True,
}, },
} }
SETTINGS_MOZILLA_FIREFOX_32 = { SETTINGS_MOZILLA_FIREFOX_32 = {
r'Software\Mozilla\Firefox\Extensions': { r'Software\Mozilla\Firefox\Extensions': {
'SZ Items': { 'SZ Items': {
'uBlock0@raymondhill.net': MOZILLA_FIREFOX_UBO_PATH}, 'uBlock0@raymondhill.net': MOZILLA_FIREFOX_UBO_PATH},
'WOW64_32': True, 'WOW64_32': True,
}, },
} }
SETTINGS_MOZILLA_FIREFOX_64 = { SETTINGS_MOZILLA_FIREFOX_64 = {
r'Software\Mozilla\Firefox\Extensions': { r'Software\Mozilla\Firefox\Extensions': {
'SZ Items': { 'SZ Items': {
'uBlock0@raymondhill.net': MOZILLA_FIREFOX_UBO_PATH}, 'uBlock0@raymondhill.net': MOZILLA_FIREFOX_UBO_PATH},
}, },
} }
VCR_REDISTS = [ VCR_REDISTS = [
{'Name': 'Visual C++ 2010 x32...', {'Name': 'Visual C++ 2010 x32...',
'Cmd': [r'2010sp1\x32\vcredist.exe', '/passive', '/norestart']}, 'Cmd': [r'2010sp1\x32\vcredist.exe', '/passive', '/norestart']},
{'Name': 'Visual C++ 2010 x64...', {'Name': 'Visual C++ 2010 x64...',
'Cmd': [r'2010sp1\x64\vcredist.exe', '/passive', '/norestart']}, 'Cmd': [r'2010sp1\x64\vcredist.exe', '/passive', '/norestart']},
{'Name': 'Visual C++ 2012 Update 4 x32...', {'Name': 'Visual C++ 2012 Update 4 x32...',
'Cmd': [r'2012u4\x32\vcredist.exe', '/passive', '/norestart']}, 'Cmd': [r'2012u4\x32\vcredist.exe', '/passive', '/norestart']},
{'Name': 'Visual C++ 2012 Update 4 x64...', {'Name': 'Visual C++ 2012 Update 4 x64...',
'Cmd': [r'2012u4\x64\vcredist.exe', '/passive', '/norestart']}, 'Cmd': [r'2012u4\x64\vcredist.exe', '/passive', '/norestart']},
{'Name': 'Visual C++ 2013 x32...', {'Name': 'Visual C++ 2013 x32...',
'Cmd': [r'2013\x32\vcredist.exe', '/install', 'Cmd': [r'2013\x32\vcredist.exe', '/install',
'/passive', '/norestart']}, '/passive', '/norestart']},
{'Name': 'Visual C++ 2013 x64...', {'Name': 'Visual C++ 2013 x64...',
'Cmd': [r'2013\x64\vcredist.exe', '/install', 'Cmd': [r'2013\x64\vcredist.exe', '/install',
'/passive', '/norestart']}, '/passive', '/norestart']},
{'Name': 'Visual C++ 2017 x32...', {'Name': 'Visual C++ 2017 x32...',
'Cmd': [r'2017\x32\vcredist.exe', '/install', 'Cmd': [r'2017\x32\vcredist.exe', '/install',
'/passive', '/norestart']}, '/passive', '/norestart']},
{'Name': 'Visual C++ 2017 x64...', {'Name': 'Visual C++ 2017 x64...',
'Cmd': [r'2017\x64\vcredist.exe', '/install', 'Cmd': [r'2017\x64\vcredist.exe', '/install',
'/passive', '/norestart']}, '/passive', '/norestart']},
] ]
def config_classicstart(): def config_classicstart():
"""Configure ClassicStart.""" """Configure ClassicStart."""
# User level, not system level # User level, not system level
cs_exe = r'{PROGRAMFILES}\Classic Shell\ClassicStartMenu.exe'.format( cs_exe = r'{PROGRAMFILES}\Classic Shell\ClassicStartMenu.exe'.format(
**global_vars['Env']) **global_vars['Env'])
skin = r'{PROGRAMFILES}\Classic Shell\Skins\Metro-Win10-Black.skin7'.format( skin = r'{PROGRAMFILES}\Classic Shell\Skins\Metro-Win10-Black.skin7'.format(
**global_vars['Env']) **global_vars['Env'])
extract_item('ClassicStartSkin', silent=True) extract_item('ClassicStartSkin', silent=True)
# Stop Classic Start # Stop Classic Start
run_program([cs_exe, '-exit'], check=False) run_program([cs_exe, '-exit'], check=False)
sleep(1) sleep(1)
kill_process('ClassicStartMenu.exe') kill_process('ClassicStartMenu.exe')
# Configure # Configure
write_registry_settings(SETTINGS_CLASSIC_START, all_users=False) write_registry_settings(SETTINGS_CLASSIC_START, all_users=False)
if global_vars['OS']['Version'] == '10' and os.path.exists(skin): if global_vars['OS']['Version'] == '10' and os.path.exists(skin):
# Enable Win10 theme if on Win10 # Enable Win10 theme if on Win10
key_path = r'Software\IvoSoft\ClassicStartMenu\Settings' key_path = r'Software\IvoSoft\ClassicStartMenu\Settings'
with winreg.OpenKey(HKCU, key_path, access=winreg.KEY_WRITE) as key: with winreg.OpenKey(HKCU, key_path, access=winreg.KEY_WRITE) as key:
winreg.SetValueEx( winreg.SetValueEx(
key, 'SkinW7', 0, winreg.REG_SZ, 'Metro-Win10-Black') key, 'SkinW7', 0, winreg.REG_SZ, 'Metro-Win10-Black')
winreg.SetValueEx(key, 'SkinVariationW7', 0, winreg.REG_SZ, '') winreg.SetValueEx(key, 'SkinVariationW7', 0, winreg.REG_SZ, '')
# Pin Browser to Start Menu (Classic) # Pin Browser to Start Menu (Classic)
firefox = r'{PROGRAMDATA}\Start Menu\Programs\Mozilla Firefox.lnk'.format( firefox = r'{PROGRAMDATA}\Start Menu\Programs\Mozilla Firefox.lnk'.format(
**global_vars['Env']) **global_vars['Env'])
chrome = r'{PROGRAMDATA}\Start Menu\Programs\Google Chrome.lnk'.format( chrome = r'{PROGRAMDATA}\Start Menu\Programs\Google Chrome.lnk'.format(
**global_vars['Env']) **global_vars['Env'])
dest_path = r'{APPDATA}\ClassicShell\Pinned'.format(**global_vars['Env']) dest_path = r'{APPDATA}\ClassicShell\Pinned'.format(**global_vars['Env'])
source = None source = None
dest = None dest = None
if os.path.exists(firefox): if os.path.exists(firefox):
source = firefox source = firefox
dest = r'{}\Mozilla Firefox.lnk'.format(dest_path) dest = r'{}\Mozilla Firefox.lnk'.format(dest_path)
elif os.path.exists(chrome): elif os.path.exists(chrome):
source = chrome source = chrome
dest = r'{}\Google Chrome.lnk'.format(dest_path) dest = r'{}\Google Chrome.lnk'.format(dest_path)
if source: if source:
try: try:
os.makedirs(dest_path, exist_ok=True) os.makedirs(dest_path, exist_ok=True)
shutil.copy(source, dest) shutil.copy(source, dest)
except Exception: except Exception:
pass # Meh, it's fine without pass # Meh, it's fine without
# (Re)start Classic Start
run_program([cs_exe, '-exit'], check=False)
sleep(1)
kill_process('ClassicStartMenu.exe')
sleep(1)
popen_program(cs_exe)
# (Re)start Classic Start
run_program([cs_exe, '-exit'], check=False)
sleep(1)
kill_process('ClassicStartMenu.exe')
sleep(1)
popen_program(cs_exe)
def config_explorer_system(): def config_explorer_system():
"""Configure Windows Explorer for all users via Registry settings.""" """Configure Windows Explorer for all users."""
write_registry_settings(SETTINGS_EXPLORER_SYSTEM, all_users=True) write_registry_settings(SETTINGS_EXPLORER_SYSTEM, all_users=True)
def config_explorer_user(): def config_explorer_user():
"""Configure Windows Explorer for current user via Registry settings.""" """Configure Windows Explorer for current user."""
write_registry_settings(SETTINGS_EXPLORER_USER, all_users=False) write_registry_settings(SETTINGS_EXPLORER_USER, all_users=False)
def disable_windows_telemetry(): def disable_windows_telemetry():
"""Disable Windows 10 telemetry settings with O&O ShutUp10.""" """Disable Windows 10 telemetry settings with O&O ShutUp10."""
extract_item('ShutUp10', silent=True) extract_item('ShutUp10', silent=True)
cmd = [ cmd = [
r'{BinDir}\ShutUp10\OOSU10.exe'.format(**global_vars), r'{BinDir}\ShutUp10\OOSU10.exe'.format(**global_vars),
r'{BinDir}\ShutUp10\1201.cfg'.format(**global_vars), r'{BinDir}\ShutUp10\1201.cfg'.format(**global_vars),
'/quiet'] '/quiet']
run_program(cmd) run_program(cmd)
def update_clock(): def update_clock():
"""Set Timezone and sync clock.""" """Set Timezone and sync clock."""
run_program(['tzutil' ,'/s', WINDOWS_TIME_ZONE], check=False) run_program(['tzutil' ,'/s', WINDOWS_TIME_ZONE], check=False)
run_program(['net', 'stop', 'w32ime'], check=False) run_program(['net', 'stop', 'w32ime'], check=False)
run_program( run_program(
['w32tm', '/config', '/syncfromflags:manual', ['w32tm', '/config', '/syncfromflags:manual',
'/manualpeerlist:"us.pool.ntp.org time.nist.gov time.windows.com"', '/manualpeerlist:"us.pool.ntp.org time.nist.gov time.windows.com"',
], ],
check=False) check=False)
run_program(['net', 'start', 'w32ime'], check=False) run_program(['net', 'start', 'w32ime'], check=False)
run_program(['w32tm', '/resync', '/nowait'], check=False) run_program(['w32tm', '/resync', '/nowait'], check=False)
def write_registry_settings(settings, all_users=False): def write_registry_settings(settings, all_users=False):
"""Write registry values from custom dict of dicts.""" """Write registry values from custom dict of dicts."""
hive = HKCU hive = HKCU
if all_users: if all_users:
hive = HKLM hive = HKLM
for k, v in settings.items(): for k, v in settings.items():
# CreateKey # CreateKey
access = winreg.KEY_WRITE access = winreg.KEY_WRITE
if 'WOW64_32' in v: if 'WOW64_32' in v:
access = access | winreg.KEY_WOW64_32KEY access = access | winreg.KEY_WOW64_32KEY
winreg.CreateKeyEx(hive, k, 0, access) winreg.CreateKeyEx(hive, k, 0, access)
# Create values
with winreg.OpenKeyEx(hive, k, 0, access) as key:
for name, value in v.get('DWORD Items', {}).items():
winreg.SetValueEx(key, name, 0, winreg.REG_DWORD, value)
for name, value in v.get('SZ Items', {}).items():
winreg.SetValueEx(key, name, 0, winreg.REG_SZ, value)
# Create values
with winreg.OpenKeyEx(hive, k, 0, access) as key:
for name, value in v.get('DWORD Items', {}).items():
winreg.SetValueEx(key, name, 0, winreg.REG_DWORD, value)
for name, value in v.get('SZ Items', {}).items():
winreg.SetValueEx(key, name, 0, winreg.REG_SZ, value)
# Installations # Installations
def install_adobe_reader(): def install_adobe_reader():
"""Install Adobe Reader.""" """Install Adobe Reader."""
cmd = [ cmd = [
r'{BaseDir}\Installers\Extras\Office\Adobe Reader DC.exe'.format( r'{BaseDir}\Installers\Extras\Office\Adobe Reader DC.exe'.format(
**global_vars), **global_vars),
'/sAll', '/sAll',
'/msi', '/norestart', '/quiet', '/msi', '/norestart', '/quiet',
'ALLUSERS=1', 'ALLUSERS=1',
'EULA_ACCEPT=YES'] 'EULA_ACCEPT=YES']
run_program(cmd) run_program(cmd)
def install_chrome_extensions(): def install_chrome_extensions():
"""Update registry to install Google Chrome extensions for all users.""" """Install Google Chrome extensions for all users."""
write_registry_settings(SETTINGS_GOOGLE_CHROME, all_users=True) write_registry_settings(SETTINGS_GOOGLE_CHROME, all_users=True)
def install_classicstart_skin(): def install_classicstart_skin():
"""Extract ClassicStart skin to installation folder.""" """Extract ClassicStart skin to installation folder."""
if global_vars['OS']['Version'] not in ('8', '8.1', '10'): if global_vars['OS']['Version'] not in ('8', '8.1', '10'):
raise UnsupportedOSError raise UnsupportedOSError
extract_item('ClassicStartSkin', silent=True) extract_item('ClassicStartSkin', silent=True)
source = r'{BinDir}\ClassicStartSkin\Metro-Win10-Black.skin7'.format( source = r'{BinDir}\ClassicStartSkin\Metro-Win10-Black.skin7'.format(
**global_vars) **global_vars)
dest_path = r'{PROGRAMFILES}\Classic Shell\Skins'.format( dest_path = r'{PROGRAMFILES}\Classic Shell\Skins'.format(
**global_vars['Env']) **global_vars['Env'])
dest = r'{}\Metro-Win10-Black.skin7'.format(dest_path) dest = r'{}\Metro-Win10-Black.skin7'.format(dest_path)
os.makedirs(dest_path, exist_ok=True) os.makedirs(dest_path, exist_ok=True)
shutil.copy(source, dest) shutil.copy(source, dest)
def install_firefox_extensions(): def install_firefox_extensions():
"""Update registry to install Firefox extensions for all users.""" """Install Firefox extensions for all users."""
dist_path = r'{PROGRAMFILES}\Mozilla Firefox\distribution\extensions'.format( dist_path = r'{PROGRAMFILES}\Mozilla Firefox\distribution\extensions'.format(
**global_vars['Env']) **global_vars['Env'])
source_path = r'{CBinDir}\FirefoxExtensions.7z'.format(**global_vars) source_path = r'{CBinDir}\FirefoxExtensions.7z'.format(**global_vars)
if not os.path.exists(source_path): if not os.path.exists(source_path):
raise FileNotFoundError raise FileNotFoundError
# Update registry # Update registry
write_registry_settings(SETTINGS_MOZILLA_FIREFOX_32, all_users=True) write_registry_settings(SETTINGS_MOZILLA_FIREFOX_32, all_users=True)
write_registry_settings(SETTINGS_MOZILLA_FIREFOX_64, all_users=True) write_registry_settings(SETTINGS_MOZILLA_FIREFOX_64, all_users=True)
# Extract extension(s) to distribution folder
cmd = [
global_vars['Tools']['SevenZip'], 'e', '-aos', '-bso0', '-bse0',
'-p{ArchivePassword}'.format(**global_vars),
'-o{dist_path}'.format(dist_path=dist_path),
source_path]
run_program(cmd)
# Extract extension(s) to distribution folder
cmd = [
global_vars['Tools']['SevenZip'], 'e', '-aos', '-bso0', '-bse0',
'-p{ArchivePassword}'.format(**global_vars),
'-o{dist_path}'.format(dist_path=dist_path),
source_path]
run_program(cmd)
def install_ninite_bundle(mse=False): def install_ninite_bundle(mse=False):
"""Run Ninite file(s) based on OS version.""" """Run Ninite file(s) based on OS version."""
if global_vars['OS']['Version'] in ('8', '8.1', '10'): if global_vars['OS']['Version'] in ('8', '8.1', '10'):
# Modern selection # Modern selection
popen_program(r'{BaseDir}\Installers\Extras\Bundles\Modern.exe'.format( popen_program(r'{BaseDir}\Installers\Extras\Bundles\Modern.exe'.format(
**global_vars)) **global_vars))
else: else:
# Legacy selection # Legacy selection
if mse: if mse:
cmd = r'{BaseDir}\Installers\Extras\Security'.format(**global_vars) cmd = r'{BaseDir}\Installers\Extras\Security'.format(**global_vars)
cmd += r'\Microsoft Security Essentials.exe' cmd += r'\Microsoft Security Essentials.exe'
popen_program(cmd) popen_program(cmd)
popen_program(r'{BaseDir}\Installers\Extras\Bundles\Legacy.exe'.format( popen_program(r'{BaseDir}\Installers\Extras\Bundles\Legacy.exe'.format(
**global_vars)) **global_vars))
def install_vcredists(): def install_vcredists():
"""Install all supported Visual C++ runtimes.""" """Install all supported Visual C++ runtimes."""
extract_item('_vcredists', silent=True) extract_item('_vcredists', silent=True)
prev_dir = os.getcwd() prev_dir = os.getcwd()
try: try:
os.chdir(r'{BinDir}\_vcredists'.format(**global_vars)) os.chdir(r'{BinDir}\_vcredists'.format(**global_vars))
except FileNotFoundError: except FileNotFoundError:
# Ignored since the loop below will report the errors # Ignored since the loop below will report the errors
pass pass
for vcr in VCR_REDISTS: for vcr in VCR_REDISTS:
try_and_print(message=vcr['Name'], function=run_program, try_and_print(message=vcr['Name'], function=run_program,
cmd=vcr['Cmd'], other_results=OTHER_RESULTS) cmd=vcr['Cmd'], other_results=OTHER_RESULTS)
os.chdir(prev_dir)
os.chdir(prev_dir)
# Misc # Misc
def open_device_manager(): def open_device_manager():
popen_program(['mmc', 'devmgmt.msc']) popen_program(['mmc', 'devmgmt.msc'])
def open_windows_activation(): def open_windows_activation():
popen_program(['slui']) popen_program(['slui'])
def open_windows_updates(): def open_windows_updates():
popen_program(['control', '/name', 'Microsoft.WindowsUpdate']) popen_program(['control', '/name', 'Microsoft.WindowsUpdate'])
if __name__ == '__main__': if __name__ == '__main__':
print("This file is not meant to be called directly.") print("This file is not meant to be called directly.")
# vim: sts=2 sw=2 ts=2

View file

@ -0,0 +1,204 @@
# Wizard Kit: Functions - Diagnostics
import ctypes
from functions.common import *
# STATIC VARIABLES
AUTORUNS_SETTINGS = {
r'Software\Sysinternals\AutoRuns': {
'checkvirustotal': 1,
'EulaAccepted': 1,
'shownomicrosoft': 1,
'shownowindows': 1,
'showonlyvirustotal': 1,
'submitvirustotal': 0,
'verifysignatures': 1,
},
r'Software\Sysinternals\AutoRuns\SigCheck': {
'EulaAccepted': 1,
},
r'Software\Sysinternals\AutoRuns\Streams': {
'EulaAccepted': 1,
},
r'Software\Sysinternals\AutoRuns\VirusTotal': {
'VirusTotalTermsAccepted': 1,
},
}
def check_connection():
"""Check if the system is online and optionally abort the script."""
while True:
result = try_and_print(message='Ping test...', function=ping, cs='OK')
if result['CS']:
break
if not ask('ERROR: System appears offline, try again?'):
if ask('Continue anyway?'):
break
else:
abort()
def check_secure_boot_status(show_alert=False):
"""Checks UEFI Secure Boot status via PowerShell."""
boot_mode = get_boot_mode()
cmd = ['PowerShell', '-Command', 'Confirm-SecureBootUEFI']
result = run_program(cmd, check=False)
# Check results
if result.returncode == 0:
out = result.stdout.decode()
if 'True' in out:
# It's on, do nothing
return
elif 'False' in out:
if show_alert:
show_alert_box('Secure Boot DISABLED')
raise SecureBootDisabledError
else:
if show_alert:
show_alert_box('Secure Boot status UNKNOWN')
raise SecureBootUnknownError
else:
if boot_mode != 'UEFI':
if (show_alert and
global_vars['OS']['Version'] in ('8', '8.1', '10')):
# OS supports Secure Boot
show_alert_box('Secure Boot DISABLED\n\nOS installed LEGACY')
raise OSInstalledLegacyError
else:
# Check error message
err = result.stderr.decode()
if 'Cmdlet not supported' in err:
if show_alert:
show_alert_box('Secure Boot UNAVAILABLE?')
raise SecureBootNotAvailError
else:
if show_alert:
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
firmware_type = ctypes.c_uint()
# Get value from kernel32 API
try:
kernel.GetFirmwareType(ctypes.byref(firmware_type))
except:
# Just set to zero
firmware_type = ctypes.c_uint(0)
# Set return value
type_str = 'Unknown'
if firmware_type.value == 1:
type_str = 'Legacy'
elif firmware_type.value == 2:
type_str = 'UEFI'
return type_str
def run_autoruns():
"""Run AutoRuns in the background with VirusTotal checks enabled."""
extract_item('Autoruns', filter='autoruns*', silent=True)
# Update AutoRuns settings before running
for path, settings in AUTORUNS_SETTINGS.items():
winreg.CreateKey(HKCU, path)
with winreg.OpenKey(HKCU, path, access=winreg.KEY_WRITE) as key:
for name, value in settings.items():
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)
for bit in [32, 64]:
# Configure
source = r'{}\general.ini'.format(path)
dest = r'{}\HWiNFO{}.ini'.format(path, bit)
shutil.copy(source, dest)
with open(dest, 'a') as f:
f.write('SensorsOnly=1\n')
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)
cmd = [global_vars['Tools']['XMPlay'],
r'{BinDir}\XMPlay\music.7z'.format(**global_vars)]
# Unmute audio first
extract_item('NirCmd', silent=True)
run_nircmd('mutesysvolume', '0')
# Open XMPlay
popen_program(cmd)
def run_hitmanpro():
"""Run HitmanPro in the background."""
extract_item('HitmanPro', silent=True)
cmd = [
global_vars['Tools']['HitmanPro'],
'/quiet', '/noinstall', '/noupload',
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)
# credit to /u/cuddlychops06
prev_dir = os.getcwd()
extract_item('ProcessKiller', silent=True)
os.chdir(r'{BinDir}\ProcessKiller'.format(**global_vars))
run_program(['ProcessKiller.exe', '/silent'], check=False)
os.chdir(prev_dir)
def run_rkill():
"""Run RKill and cleanup afterwards."""
extract_item('RKill', silent=True)
cmd = [
global_vars['Tools']['RKill'],
'-s', '-l', r'{LogDir}\Tools\RKill.log'.format(**global_vars),
'-new_console:n', '-new_console:s33V']
run_program(cmd, check=False)
wait_for_process('RKill')
# RKill cleanup
desktop_path = r'{USERPROFILE}\Desktop'.format(**global_vars['Env'])
if os.path.exists(desktop_path):
for item in os.scandir(desktop_path):
if re.search(r'^RKill', item.name, re.IGNORECASE):
dest = r'{LogDir}\Tools\{name}'.format(
name=dest, **global_vars)
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.")
# vim: sts=2 sw=2 ts=2

View file

@ -2,12 +2,14 @@
from functions.common import * from functions.common import *
def create_file(filepath): def create_file(filepath):
"""Create file if it doesn't exist.""" """Create file if it doesn't exist."""
if not os.path.exists(filepath): if not os.path.exists(filepath):
with open(filepath, 'w') as f: with open(filepath, 'w') as f:
f.write('') f.write('')
def tmux_get_pane_size(pane_id=None): def tmux_get_pane_size(pane_id=None):
"""Get target, or current, pane size, returns tuple.""" """Get target, or current, pane size, returns tuple."""
x = -1 x = -1
@ -29,6 +31,7 @@ def tmux_get_pane_size(pane_id=None):
return (x, y) return (x, y)
def tmux_kill_all_panes(pane_id=None): def tmux_kill_all_panes(pane_id=None):
"""Kill all tmux panes except the active pane or pane_id if specified.""" """Kill all tmux panes except the active pane or pane_id if specified."""
cmd = ['tmux', 'kill-pane', '-a'] cmd = ['tmux', 'kill-pane', '-a']
@ -36,12 +39,14 @@ def tmux_kill_all_panes(pane_id=None):
cmd.extend(['-t', pane_id]) cmd.extend(['-t', pane_id])
run_program(cmd, check=False) run_program(cmd, check=False)
def tmux_kill_pane(*panes): def tmux_kill_pane(*panes):
"""Kill tmux pane by id.""" """Kill tmux pane by id."""
cmd = ['tmux', 'kill-pane', '-t'] cmd = ['tmux', 'kill-pane', '-t']
for pane_id in panes: for pane_id in panes:
run_program(cmd+[pane_id], check=False) run_program(cmd+[pane_id], check=False)
def tmux_poll_pane(pane_id): def tmux_poll_pane(pane_id):
"""Check if pane exists, returns bool.""" """Check if pane exists, returns bool."""
cmd = ['tmux', 'list-panes', '-F', '#D'] cmd = ['tmux', 'list-panes', '-F', '#D']
@ -49,6 +54,7 @@ def tmux_poll_pane(pane_id):
panes = result.stdout.decode().splitlines() panes = result.stdout.decode().splitlines()
return pane_id in panes return pane_id in panes
def tmux_resize_pane(pane_id=None, x=None, y=None, **kwargs): def tmux_resize_pane(pane_id=None, x=None, y=None, **kwargs):
"""Resize pane to specific hieght or width.""" """Resize pane to specific hieght or width."""
if not x and not y: 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) run_program(cmd, check=False)
def tmux_split_window( def tmux_split_window(
lines=None, percent=None, lines=None, percent=None,
behind=False, vertical=False, behind=False, vertical=False,
@ -115,6 +122,7 @@ def tmux_split_window(
result = run_program(cmd) result = run_program(cmd)
return result.stdout.decode().strip() return result.stdout.decode().strip()
def tmux_update_pane( def tmux_update_pane(
pane_id, command=None, working_dir=None, pane_id, command=None, working_dir=None,
text=None, watch=None, watch_cmd='cat'): text=None, watch=None, watch_cmd='cat'):
@ -142,6 +150,7 @@ def tmux_update_pane(
run_program(cmd) run_program(cmd)
if __name__ == '__main__': if __name__ == '__main__':
print("This file is not meant to be called directly.") print("This file is not meant to be called directly.")

File diff suppressed because it is too large Load diff

View file

@ -3,236 +3,250 @@
from functions.data import * from functions.data import *
from functions.disk import * from functions.disk import *
# STATIC VARIABLES # STATIC VARIABLES
WINDOWS_VERSIONS = [ WINDOWS_VERSIONS = [
{'Name': 'Windows 7 Home Basic', {'Name': 'Windows 7 Home Basic',
'Image File': 'Win7', 'Image File': 'Win7',
'Image Name': 'Windows 7 HOMEBASIC'}, 'Image Name': 'Windows 7 HOMEBASIC'},
{'Name': 'Windows 7 Home Premium', {'Name': 'Windows 7 Home Premium',
'Image File': 'Win7', 'Image File': 'Win7',
'Image Name': 'Windows 7 HOMEPREMIUM'}, 'Image Name': 'Windows 7 HOMEPREMIUM'},
{'Name': 'Windows 7 Professional', {'Name': 'Windows 7 Professional',
'Image File': 'Win7', 'Image File': 'Win7',
'Image Name': 'Windows 7 PROFESSIONAL'}, 'Image Name': 'Windows 7 PROFESSIONAL'},
{'Name': 'Windows 7 Ultimate', {'Name': 'Windows 7 Ultimate',
'Image File': 'Win7', 'Image File': 'Win7',
'Image Name': 'Windows 7 ULTIMATE'}, 'Image Name': 'Windows 7 ULTIMATE'},
{'Name': 'Windows 8.1', {'Name': 'Windows 8.1',
'Image File': 'Win8', 'Image File': 'Win8',
'Image Name': 'Windows 8.1', 'Image Name': 'Windows 8.1',
'CRLF': True}, 'CRLF': True},
{'Name': 'Windows 8.1 Pro', {'Name': 'Windows 8.1 Pro',
'Image File': 'Win8', 'Image File': 'Win8',
'Image Name': 'Windows 8.1 Pro'}, 'Image Name': 'Windows 8.1 Pro'},
{'Name': 'Windows 10 Home',
'Image File': 'Win10',
'Image Name': 'Windows 10 Home',
'CRLF': True},
{'Name': 'Windows 10 Pro',
'Image File': 'Win10',
'Image Name': 'Windows 10 Pro'},
]
{'Name': 'Windows 10 Home',
'Image File': 'Win10',
'Image Name': 'Windows 10 Home',
'CRLF': True},
{'Name': 'Windows 10 Pro',
'Image File': 'Win10',
'Image Name': 'Windows 10 Pro'},
]
def find_windows_image(windows_version): def find_windows_image(windows_version):
"""Search for a Windows source image file, returns dict. """Search for a Windows source image file, returns dict.
Searches on local disks and then the WINDOWS_SERVER share.""" Searches on local disks and then the WINDOWS_SERVER share."""
image = {} image = {}
imagefile = windows_version['Image File'] imagefile = windows_version['Image File']
imagename = windows_version['Image Name'] imagename = windows_version['Image Name']
# Search local source # Search local source
set_thread_error_mode(silent=True) # Prevents "No disk" popups set_thread_error_mode(silent=True) # Prevents "No disk" popups
for d in psutil.disk_partitions(): for d in psutil.disk_partitions():
for ext in ['esd', 'wim', 'swm']: for ext in ['esd', 'wim', 'swm']:
path = '{}images\{}.{}'.format(d.mountpoint, imagefile, ext) path = '{}images\{}.{}'.format(d.mountpoint, imagefile, ext)
if os.path.isfile(path) and wim_contains_image(path, imagename): if os.path.isfile(path) and wim_contains_image(path, imagename):
image['Path'] = path image['Path'] = path
image['Letter'] = d.mountpoint[:1].upper() image['Letter'] = d.mountpoint[:1].upper()
image['Local'] = True image['Local'] = True
if ext == 'swm': if ext == 'swm':
image['Glob'] = '--ref="{}*.swm"'.format(image['Path'][:-4]) image['Glob'] = '--ref="{}*.swm"'.format(image['Path'][:-4])
break break
set_thread_error_mode(silent=False) # Return to normal set_thread_error_mode(silent=False) # Return to normal
# Check for network source # Check for network source
if not image: if not image:
mount_windows_share() mount_windows_share()
if WINDOWS_SERVER['Mounted']: if WINDOWS_SERVER['Mounted']:
for ext in ['esd', 'wim', 'swm']: for ext in ['esd', 'wim', 'swm']:
path = r'\\{}\{}\images\{}.{}'.format( path = r'\\{}\{}\images\{}.{}'.format(
WINDOWS_SERVER['IP'], WINDOWS_SERVER['IP'],
WINDOWS_SERVER['Share'], WINDOWS_SERVER['Share'],
imagefile, imagefile,
ext) ext)
if os.path.isfile(path) and wim_contains_image(path, imagename): if os.path.isfile(path) and wim_contains_image(path, imagename):
image['Path'] = path image['Path'] = path
image['Letter'] = None image['Letter'] = None
image['Local'] = False image['Local'] = False
if ext == 'swm': if ext == 'swm':
image['Glob'] = '--ref="{}*.swm"'.format( image['Glob'] = '--ref="{}*.swm"'.format(
image['Path'][:-4]) image['Path'][:-4])
break break
# Display image to be used (if any) and return
if image:
print_info('Using image: {}'.format(image['Path']))
return image
else:
print_error('Failed to find Windows source image for {}'.format(
windows_version['Name']))
raise GenericAbort
# Display image to be used (if any) and return
if image:
print_info('Using image: {}'.format(image['Path']))
return image
else:
print_error('Failed to find Windows source image for {}'.format(
windows_version['Name']))
raise GenericAbort
def format_disk(disk, use_gpt): def format_disk(disk, use_gpt):
"""Format disk for use as a Windows OS disk.""" """Format disk for use as a Windows OS disk."""
if use_gpt: if use_gpt:
format_gpt(disk) format_gpt(disk)
else: else:
format_mbr(disk) format_mbr(disk)
def format_gpt(disk): def format_gpt(disk):
"""Format disk for use as a Windows OS disk using the GPT layout.""" """Format disk for use as a Windows OS disk using the GPT layout."""
script = [ script = [
# Partition table # Partition table
'select disk {}'.format(disk['Number']), 'select disk {}'.format(disk['Number']),
'clean', 'clean',
'convert gpt', 'convert gpt',
# System partition # System partition
# NOTE: ESP needs to be >= 260 for Advanced Format 4K disks # NOTE: ESP needs to be >= 260 for Advanced Format 4K disks
'create partition efi size=500', 'create partition efi size=500',
'format quick fs=fat32 label="System"', 'format quick fs=fat32 label="System"',
'assign letter="S"', 'assign letter="S"',
# Microsoft Reserved (MSR) partition # Microsoft Reserved (MSR) partition
'create partition msr size=128', 'create partition msr size=128',
# Windows partition # Windows partition
'create partition primary', 'create partition primary',
'format quick fs=ntfs label="Windows"', 'format quick fs=ntfs label="Windows"',
'assign letter="W"', 'assign letter="W"',
# Recovery Tools partition # Recovery Tools partition
'shrink minimum=500', 'shrink minimum=500',
'create partition primary', 'create partition primary',
'format quick fs=ntfs label="Recovery Tools"', 'format quick fs=ntfs label="Recovery Tools"',
'assign letter="T"', 'assign letter="T"',
'set id="de94bba4-06d1-4d40-a16a-bfd50179d6ac"', 'set id="de94bba4-06d1-4d40-a16a-bfd50179d6ac"',
'gpt attributes=0x8000000000000001', 'gpt attributes=0x8000000000000001',
] ]
# Run
run_diskpart(script)
# Run
run_diskpart(script)
def format_mbr(disk): def format_mbr(disk):
"""Format disk for use as a Windows OS disk using the MBR layout.""" """Format disk for use as a Windows OS disk using the MBR layout."""
script = [ script = [
# Partition table # Partition table
'select disk {}'.format(disk['Number']), 'select disk {}'.format(disk['Number']),
'clean', 'clean',
# System partition # System partition
'create partition primary size=100', 'create partition primary size=100',
'format fs=ntfs quick label="System Reserved"', 'format fs=ntfs quick label="System Reserved"',
'active', 'active',
'assign letter="S"', 'assign letter="S"',
# Windows partition # Windows partition
'create partition primary', 'create partition primary',
'format fs=ntfs quick label="Windows"', 'format fs=ntfs quick label="Windows"',
'assign letter="W"', 'assign letter="W"',
# Recovery Tools partition # Recovery Tools partition
'shrink minimum=500', 'shrink minimum=500',
'create partition primary', 'create partition primary',
'format quick fs=ntfs label="Recovery"', 'format quick fs=ntfs label="Recovery"',
'assign letter="T"', 'assign letter="T"',
'set id=27', 'set id=27',
] ]
# Run
run_diskpart(script)
# Run
run_diskpart(script)
def mount_windows_share(): def mount_windows_share():
"""Mount the Windows images share unless labeled as already mounted.""" """Mount the Windows images share unless already mounted."""
if not WINDOWS_SERVER['Mounted']: if not WINDOWS_SERVER['Mounted']:
# Mounting read-write in case a backup was done in the same session # Mounting read-write in case a backup was done in the same session
# and the server was left mounted read-write. This avoids throwing an # and the server was left mounted read-write. This avoids throwing an
# error by trying to mount the same server with multiple credentials. # error by trying to mount the same server with multiple credentials.
mount_network_share(WINDOWS_SERVER, read_write=True) mount_network_share(WINDOWS_SERVER, read_write=True)
def select_windows_version(): def select_windows_version():
"""Select Windows version from a menu, returns dict.""" """Select Windows version from a menu, returns dict."""
actions = [ actions = [
{'Name': 'Main Menu', 'Letter': 'M'}, {'Name': 'Main Menu', 'Letter': 'M'},
] ]
# Menu loop # Menu loop
selection = menu_select( selection = menu_select(
title = 'Which version of Windows are we installing?', title = 'Which version of Windows are we installing?',
main_entries = WINDOWS_VERSIONS, main_entries = WINDOWS_VERSIONS,
action_entries = actions) action_entries = actions)
if selection.isnumeric():
return WINDOWS_VERSIONS[int(selection)-1]
elif selection == 'M':
raise GenericAbort
if selection.isnumeric():
return WINDOWS_VERSIONS[int(selection)-1]
elif selection == 'M':
raise GenericAbort
def setup_windows(windows_image, windows_version): def setup_windows(windows_image, windows_version):
"""Apply a Windows image to W:""" """Apply a Windows image to W:"""
cmd = [ cmd = [
global_vars['Tools']['wimlib-imagex'], global_vars['Tools']['wimlib-imagex'],
'apply', 'apply',
windows_image['Path'], windows_image['Path'],
windows_version['Image Name'], windows_version['Image Name'],
'W:\\'] 'W:\\']
if 'Glob' in windows_image: if 'Glob' in windows_image:
cmd.extend(windows_image['Glob']) cmd.extend(windows_image['Glob'])
run_program(cmd) run_program(cmd)
def setup_windows_re(windows_version, windows_letter='W', tools_letter='T'): def setup_windows_re(windows_version, windows_letter='W', tools_letter='T'):
"""Setup the WinRE partition.""" """Setup the WinRE partition."""
win = r'{}:\Windows'.format(windows_letter) win = r'{}:\Windows'.format(windows_letter)
winre = r'{}\System32\Recovery\WinRE.wim'.format(win) winre = r'{}\System32\Recovery\WinRE.wim'.format(win)
dest = r'{}:\Recovery\WindowsRE'.format(tools_letter) dest = r'{}:\Recovery\WindowsRE'.format(tools_letter)
# Copy WinRE.wim # Copy WinRE.wim
os.makedirs(dest, exist_ok=True) os.makedirs(dest, exist_ok=True)
shutil.copy(winre, r'{}\WinRE.wim'.format(dest)) shutil.copy(winre, r'{}\WinRE.wim'.format(dest))
# Set location
cmd = [
r'{}\System32\ReAgentc.exe'.format(win),
'/setreimage',
'/path', dest,
'/target', win]
run_program(cmd)
# Set location
cmd = [
r'{}\System32\ReAgentc.exe'.format(win),
'/setreimage',
'/path', dest,
'/target', win]
run_program(cmd)
def update_boot_partition(system_letter='S', windows_letter='W', mode='ALL'): def update_boot_partition(system_letter='S', windows_letter='W', mode='ALL'):
"""Setup the Windows boot partition.""" """Setup the Windows boot partition."""
cmd = [ cmd = [
r'{}\Windows\System32\bcdboot.exe'.format( r'{}\Windows\System32\bcdboot.exe'.format(
global_vars['Env']['SYSTEMDRIVE']), global_vars['Env']['SYSTEMDRIVE']),
r'{}:\Windows'.format(windows_letter), r'{}:\Windows'.format(windows_letter),
'/s', '{}:'.format(system_letter), '/s', '{}:'.format(system_letter),
'/f', mode] '/f', mode]
run_program(cmd) run_program(cmd)
def wim_contains_image(filename, imagename): def wim_contains_image(filename, imagename):
"""Check if an ESD/WIM contains the specified image, returns bool.""" """Check if an ESD/WIM contains the specified image, returns bool."""
cmd = [ cmd = [
global_vars['Tools']['wimlib-imagex'], global_vars['Tools']['wimlib-imagex'],
'info', 'info',
filename, filename,
imagename] imagename]
try: try:
run_program(cmd) run_program(cmd)
except subprocess.CalledProcessError: except subprocess.CalledProcessError:
return False return False
return True
return True
if __name__ == '__main__': if __name__ == '__main__':
print("This file is not meant to be called directly.") print("This file is not meant to be called directly.")
# vim: sts=2 sw=2 ts=2

View file

@ -4,468 +4,478 @@ from functions.backup import *
from functions.disk import * from functions.disk import *
from functions.windows_setup import * from functions.windows_setup import *
# STATIC VARIABLES # STATIC VARIABLES
FAST_COPY_PE_ARGS = [ FAST_COPY_PE_ARGS = [
'/cmd=noexist_only', '/cmd=noexist_only',
'/utf8', '/utf8',
'/skip_empty_dir', '/skip_empty_dir',
'/linkdest', '/linkdest',
'/no_ui', '/no_ui',
'/auto_close', '/auto_close',
'/exclude={}'.format(';'.join(FAST_COPY_EXCLUDES)), '/exclude={}'.format(';'.join(FAST_COPY_EXCLUDES)),
] ]
PE_TOOLS = { PE_TOOLS = {
'BlueScreenView': { 'BlueScreenView': {
'Path': r'BlueScreenView\BlueScreenView.exe', 'Path': r'BlueScreenView\BlueScreenView.exe',
}, },
'FastCopy': { 'FastCopy': {
'Path': r'FastCopy\FastCopy.exe', 'Path': r'FastCopy\FastCopy.exe',
'Args': FAST_COPY_PE_ARGS, 'Args': FAST_COPY_PE_ARGS,
}, },
'HWiNFO': { 'HWiNFO': {
'Path': r'HWiNFO\HWiNFO.exe', 'Path': r'HWiNFO\HWiNFO.exe',
}, },
'NT Password Editor': { 'NT Password Editor': {
'Path': r'NT Password Editor\ntpwedit.exe', 'Path': r'NT Password Editor\ntpwedit.exe',
}, },
'Notepad++': { 'Notepad++': {
'Path': r'NotepadPlusPlus\NotepadPlusPlus.exe', 'Path': r'NotepadPlusPlus\NotepadPlusPlus.exe',
}, },
'PhotoRec': { 'PhotoRec': {
'Path': r'TestDisk\photorec_win.exe', 'Path': r'TestDisk\photorec_win.exe',
'Args': ['-new_console:n'], 'Args': ['-new_console:n'],
}, },
'Prime95': { 'Prime95': {
'Path': r'Prime95\prime95.exe', 'Path': r'Prime95\prime95.exe',
}, },
'ProduKey': { 'ProduKey': {
'Path': r'ProduKey\ProduKey.exe', 'Path': r'ProduKey\ProduKey.exe',
}, },
'Q-Dir': { 'Q-Dir': {
'Path': r'Q-Dir\Q-Dir.exe', 'Path': r'Q-Dir\Q-Dir.exe',
}, },
'TestDisk': { 'TestDisk': {
'Path': r'TestDisk\testdisk_win.exe', 'Path': r'TestDisk\testdisk_win.exe',
'Args': ['-new_console:n'], 'Args': ['-new_console:n'],
}, },
} }
def check_pe_tools(): def check_pe_tools():
"""Fix tool paths for WinPE layout.""" """Fix tool paths for WinPE layout."""
for k in PE_TOOLS.keys(): for k in PE_TOOLS.keys():
PE_TOOLS[k]['Path'] = r'{}\{}'.format( PE_TOOLS[k]['Path'] = r'{}\{}'.format(
global_vars['BinDir'], PE_TOOLS[k]['Path']) global_vars['BinDir'], PE_TOOLS[k]['Path'])
global_vars['Tools']['wimlib-imagex'] = re.sub( global_vars['Tools']['wimlib-imagex'] = re.sub(
r'\\x(32|64)', r'\\x(32|64)',
r'', r'',
global_vars['Tools']['wimlib-imagex'], global_vars['Tools']['wimlib-imagex'],
re.IGNORECASE) re.IGNORECASE)
def menu_backup(): def menu_backup():
"""Take backup images of partition(s) in the WIM format.""" """Take backup images of partition(s) in the WIM format."""
errors = False errors = False
other_results = { other_results = {
'Error': { 'Error': {
'CalledProcessError': 'Unknown Error', 'CalledProcessError': 'Unknown Error',
'PathNotFoundError': 'Missing', 'PathNotFoundError': 'Missing',
}, },
'Warning': { 'Warning': {
'GenericAbort': 'Skipped', 'GenericAbort': 'Skipped',
'GenericRepair': 'Repaired', 'GenericRepair': 'Repaired',
}} }}
set_title('{}: Backup Menu'.format(KIT_NAME_FULL)) set_title('{}: Backup Menu'.format(KIT_NAME_FULL))
# Set backup prefix # Set backup prefix
clear_screen() clear_screen()
print_standard('{}\n'.format(global_vars['Title'])) print_standard('{}\n'.format(global_vars['Title']))
ticket_number = get_ticket_number() ticket_number = get_ticket_number()
if ENABLED_TICKET_NUMBERS: if ENABLED_TICKET_NUMBERS:
backup_prefix = ticket_number backup_prefix = ticket_number
else:
backup_prefix = get_simple_string(prompt='Enter backup name prefix')
backup_prefix = backup_prefix.replace(' ', '_')
# Assign drive letters
try_and_print(
message = 'Assigning letters...',
function = assign_volume_letters,
other_results = other_results)
# Mount backup shares
mount_backup_shares(read_write=True)
# Select destination
destination = select_backup_destination(auto_select=False)
# Scan disks
result = try_and_print(
message = 'Getting disk info...',
function = scan_disks,
other_results = other_results)
if result['CS']:
disks = result['Out']
else:
print_error('ERROR: No disks found.')
raise GenericAbort
# Select disk to backup
disk = select_disk('For which disk are we creating backups?', disks)
if not disk:
raise GenericAbort
# "Prep" disk
prep_disk_for_backup(destination, disk, backup_prefix)
# Display details for backup task
clear_screen()
print_info('Create Backup - Details:\n')
if ENABLED_TICKET_NUMBERS:
show_data(message='Ticket:', data=ticket_number)
show_data(
message = 'Source:',
data = '[{}] ({}) {} {}'.format(
disk.get('Table', ''),
disk.get('Type', ''),
disk.get('Name', 'Unknown'),
disk.get('Size', ''),
),
)
show_data(
message = 'Destination:',
data = destination.get('Display Name', destination['Name']),
)
for par in disk['Partitions']:
message = 'Partition {}:'.format(par['Number'])
data = par['Display String']
if par['Number'] in disk['Bad Partitions']:
show_data(message=message, data=data, width=30, warning=True)
if 'Error' in par:
show_data(message='', data=par['Error'], error=True)
elif par['Image Exists']:
show_data(message=message, data=data, width=30, info=True)
else: else:
backup_prefix = get_simple_string(prompt='Enter backup name prefix') show_data(message=message, data=data, width=30)
backup_prefix = backup_prefix.replace(' ', '_') print_standard(disk['Backup Warnings'])
# Assign drive letters # Ask to proceed
try_and_print( if (not ask('Proceed with backup?')):
message = 'Assigning letters...', raise GenericAbort
function = assign_volume_letters,
other_results = other_results)
# Mount backup shares # Backup partition(s)
mount_backup_shares(read_write=True) print_info('\n\nStarting task.\n')
for par in disk['Partitions']:
# Select destination
destination = select_backup_destination(auto_select=False)
# Scan disks
result = try_and_print( result = try_and_print(
message = 'Getting disk info...', message = 'Partition {} Backup...'.format(par['Number']),
function = scan_disks, function = backup_partition,
other_results = other_results) other_results = other_results,
if result['CS']: disk = disk,
disks = result['Out'] par = par)
else: if not result['CS'] and not isinstance(result['Error'], GenericAbort):
print_error('ERROR: No disks found.') errors = True
raise GenericAbort par['Error'] = result['Error']
# Select disk to backup # Verify backup(s)
disk = select_disk('For which disk are we creating backups?', disks) if disk['Valid Partitions']:
if not disk: print_info('\n\nVerifying backup images(s)\n')
raise GenericAbort
# "Prep" disk
prep_disk_for_backup(destination, disk, backup_prefix)
# Display details for backup task
clear_screen()
print_info('Create Backup - Details:\n')
if ENABLED_TICKET_NUMBERS:
show_data(message='Ticket:', data=ticket_number)
show_data(
message = 'Source:',
data = '[{}] ({}) {} {}'.format(
disk.get('Table', ''),
disk.get('Type', ''),
disk.get('Name', 'Unknown'),
disk.get('Size', ''),
),
)
show_data(
message = 'Destination:',
data = destination.get('Display Name', destination['Name']),
)
for par in disk['Partitions']: for par in disk['Partitions']:
message = 'Partition {}:'.format(par['Number']) if par['Number'] in disk['Bad Partitions']:
data = par['Display String'] continue # Skip verification
if par['Number'] in disk['Bad Partitions']: result = try_and_print(
show_data(message=message, data=data, width=30, warning=True) message = 'Partition {} Image...'.format(par['Number']),
if 'Error' in par: function = verify_wim_backup,
show_data(message='', data=par['Error'], error=True) other_results = other_results,
elif par['Image Exists']: partition = par)
show_data(message=message, data=data, width=30, info=True) if not result['CS']:
else: errors = True
show_data(message=message, data=data, width=30) par['Error'] = result['Error']
print_standard(disk['Backup Warnings'])
# Ask to proceed # Print summary
if (not ask('Proceed with backup?')): if errors:
raise GenericAbort print_warning('\nErrors were encountered and are detailed below.')
for par in [p for p in disk['Partitions'] if 'Error' in p]:
# Backup partition(s) print_standard(' Partition {} Error:'.format(par['Number']))
print_info('\n\nStarting task.\n') if hasattr(par['Error'], 'stderr'):
for par in disk['Partitions']:
result = try_and_print(
message = 'Partition {} Backup...'.format(par['Number']),
function = backup_partition,
other_results = other_results,
disk = disk,
par = par)
if not result['CS'] and not isinstance(result['Error'], GenericAbort):
errors = True
par['Error'] = result['Error']
# Verify backup(s)
if disk['Valid Partitions']:
print_info('\n\nVerifying backup images(s)\n')
for par in disk['Partitions']:
if par['Number'] in disk['Bad Partitions']:
continue # Skip verification
result = try_and_print(
message = 'Partition {} Image...'.format(par['Number']),
function = verify_wim_backup,
other_results = other_results,
partition = par)
if not result['CS']:
errors = True
par['Error'] = result['Error']
# 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_standard(' Partition {} Error:'.format(par['Number']))
if hasattr(par['Error'], 'stderr'):
try:
par['Error'] = par['Error'].stderr.decode()
except:
# Deal with badly formatted error message
pass
try:
par['Error'] = par['Error'].splitlines()
par['Error'] = [line.strip() for line in par['Error']]
par['Error'] = [line for line in par['Error'] if line]
for line in par['Error']:
print_error('\t{}'.format(line))
except:
print_error('\t{}'.format(par['Error']))
else:
print_success('\nNo errors were encountered during imaging.')
if 'LogFile' in global_vars and ask('\nReview log?'):
cmd = [
global_vars['Tools']['NotepadPlusPlus'],
global_vars['LogFile']]
try: try:
popen_program(cmd) par['Error'] = par['Error'].stderr.decode()
except Exception: except:
print_error('ERROR: Failed to open log.') # Deal with badly formatted error message
sleep(30) pass
pause('\nPress Enter to return to main menu... ') try:
par['Error'] = par['Error'].splitlines()
par['Error'] = [line.strip() for line in par['Error']]
par['Error'] = [line for line in par['Error'] if line]
for line in par['Error']:
print_error('\t{}'.format(line))
except:
print_error('\t{}'.format(par['Error']))
else:
print_success('\nNo errors were encountered during imaging.')
if 'LogFile' in global_vars and ask('\nReview log?'):
cmd = [
global_vars['Tools']['NotepadPlusPlus'],
global_vars['LogFile']]
try:
popen_program(cmd)
except Exception:
print_error('ERROR: Failed to open log.')
sleep(30)
pause('\nPress Enter to return to main menu... ')
def menu_root(): def menu_root():
"""Main WinPE menu.""" """Main WinPE menu."""
check_pe_tools() check_pe_tools()
menus = [ menus = [
{'Name': 'Create Backups', 'Menu': menu_backup}, {'Name': 'Create Backups', 'Menu': menu_backup},
{'Name': 'Setup Windows', 'Menu': menu_setup}, {'Name': 'Setup Windows', 'Menu': menu_setup},
{'Name': 'Misc Tools', 'Menu': menu_tools}, {'Name': 'Misc Tools', 'Menu': menu_tools},
] ]
actions = [ actions = [
{'Name': 'Command Prompt', 'Letter': 'C'}, {'Name': 'Command Prompt', 'Letter': 'C'},
{'Name': 'Reboot', 'Letter': 'R'}, {'Name': 'Reboot', 'Letter': 'R'},
{'Name': 'Shutdown', 'Letter': 'S'}, {'Name': 'Shutdown', 'Letter': 'S'},
] ]
# Main loop # Main loop
while True: while True:
set_title(KIT_NAME_FULL) set_title(KIT_NAME_FULL)
selection = menu_select( selection = menu_select(
title = 'Main Menu', title = 'Main Menu',
main_entries = menus, main_entries = menus,
action_entries = actions, action_entries = actions,
secret_exit = True) secret_exit = True)
if (selection.isnumeric()):
try:
menus[int(selection)-1]['Menu']()
except GenericAbort:
print_warning('\nAborted\n')
pause('Press Enter to return to main menu... ')
elif (selection == 'C'):
run_program(['cmd', '-new_console:n'], check=False)
elif (selection == 'R'):
run_program(['wpeutil', 'reboot'])
elif (selection == 'S'):
run_program(['wpeutil', 'shutdown'])
else:
sys.exit()
if (selection.isnumeric()):
try:
menus[int(selection)-1]['Menu']()
except GenericAbort:
print_warning('\nAborted\n')
pause('Press Enter to return to main menu... ')
elif (selection == 'C'):
run_program(['cmd', '-new_console:n'], check=False)
elif (selection == 'R'):
run_program(['wpeutil', 'reboot'])
elif (selection == 'S'):
run_program(['wpeutil', 'shutdown'])
else:
sys.exit()
def menu_setup(): def menu_setup():
"""Format a disk (MBR/GPT), apply a Windows image, and setup boot files.""" """Format a disk, apply a Windows image, and create boot files."""
errors = False errors = False
other_results = { other_results = {
'Error': { 'Error': {
'CalledProcessError': 'Unknown Error', 'CalledProcessError': 'Unknown Error',
'PathNotFoundError': 'Missing', 'PathNotFoundError': 'Missing',
}, },
'Warning': { 'Warning': {
'GenericAbort': 'Skipped', 'GenericAbort': 'Skipped',
'GenericRepair': 'Repaired', 'GenericRepair': 'Repaired',
}} }}
set_title('{}: Setup Menu'.format(KIT_NAME_FULL)) set_title('{}: Setup Menu'.format(KIT_NAME_FULL))
# Set ticket ID # Set ticket ID
clear_screen() clear_screen()
print_standard('{}\n'.format(global_vars['Title'])) print_standard('{}\n'.format(global_vars['Title']))
ticket_number = get_ticket_number() ticket_number = get_ticket_number()
# Select the version of Windows to apply # Select the version of Windows to apply
windows_version = select_windows_version() windows_version = select_windows_version()
# Find Windows image # Find Windows image
# NOTE: Reassign volume letters to ensure all devices are scanned # NOTE: Reassign volume letters to ensure all devices are scanned
try_and_print( try_and_print(
message = 'Assigning volume letters...', message = 'Assigning volume letters...',
function = assign_volume_letters, function = assign_volume_letters,
other_results = other_results) other_results = other_results)
windows_image = find_windows_image(windows_version) windows_image = find_windows_image(windows_version)
# Scan disks # Scan disks
result = try_and_print( result = try_and_print(
message = 'Getting disk info...', message = 'Getting disk info...',
function = scan_disks, function = scan_disks,
other_results = other_results) other_results = other_results)
if result['CS']: if result['CS']:
disks = result['Out'] disks = result['Out']
else: else:
print_error('ERROR: No disks found.') print_error('ERROR: No disks found.')
raise GenericAbort raise GenericAbort
# Select disk to use as the OS disk # Select disk to use as the OS disk
dest_disk = select_disk('To which disk are we installing Windows?', disks) dest_disk = select_disk('To which disk are we installing Windows?', disks)
if not dest_disk: if not dest_disk:
raise GenericAbort raise GenericAbort
# "Prep" disk # "Prep" disk
prep_disk_for_formatting(dest_disk) prep_disk_for_formatting(dest_disk)
# Display details for setup task # Display details for setup task
clear_screen() clear_screen()
print_info('Setup Windows - Details:\n') print_info('Setup Windows - Details:\n')
if ENABLED_TICKET_NUMBERS: if ENABLED_TICKET_NUMBERS:
show_data(message='Ticket:', data=ticket_number) show_data(message='Ticket:', data=ticket_number)
show_data(message='Installing:', data=windows_version['Name']) show_data(message='Installing:', data=windows_version['Name'])
show_data(
message = 'Boot Method:',
data = 'UEFI (GPT)' if dest_disk['Use GPT'] else 'Legacy (MBR)')
show_data(message='Using Image:', data=windows_image['Path'])
show_data(
message = 'ERASING:',
data = '[{}] ({}) {} {}\n'.format(
dest_disk.get('Table', ''),
dest_disk.get('Type', ''),
dest_disk.get('Name', 'Unknown'),
dest_disk.get('Size', ''),
),
warning = True)
for par in dest_disk['Partitions']:
show_data( show_data(
message = 'Boot Method:', message = 'Partition {}:'.format(par['Number']),
data = 'UEFI (GPT)' if dest_disk['Use GPT'] else 'Legacy (MBR)') data = par['Display String'],
show_data(message='Using Image:', data=windows_image['Path']) warning = True)
show_data( print_warning(dest_disk['Format Warnings'])
message = 'ERASING:',
data = '[{}] ({}) {} {}\n'.format(
dest_disk.get('Table', ''),
dest_disk.get('Type', ''),
dest_disk.get('Name', 'Unknown'),
dest_disk.get('Size', ''),
),
warning = True)
for par in dest_disk['Partitions']:
show_data(
message = 'Partition {}:'.format(par['Number']),
data = par['Display String'],
warning = True)
print_warning(dest_disk['Format Warnings'])
if (not ask('Is this correct?')): if (not ask('Is this correct?')):
raise GenericAbort raise GenericAbort
# Safety check # Safety check
print_standard('\nSAFETY CHECK') print_standard('\nSAFETY CHECK')
print_warning('All data will be DELETED from the ' print_warning('All data will be DELETED from the '
'disk and partition(s) listed above.') 'disk and partition(s) listed above.')
print_warning('This is irreversible and will lead ' print_warning('This is irreversible and will lead '
'to {CLEAR}{RED}DATA LOSS.'.format(**COLORS)) 'to {CLEAR}{RED}DATA LOSS.'.format(**COLORS))
if (not ask('Asking again to confirm, is this correct?')): if (not ask('Asking again to confirm, is this correct?')):
raise GenericAbort raise GenericAbort
# Remove volume letters so S, T, & W can be used below # Remove volume letters so S, T, & W can be used below
try_and_print( try_and_print(
message = 'Removing volume letters...', message = 'Removing volume letters...',
function = remove_volume_letters, function = remove_volume_letters,
other_results = other_results, other_results = other_results,
keep=windows_image['Letter']) keep=windows_image['Letter'])
# Assign new letter for local source if necessary # Assign new letter for local source if necessary
if windows_image['Local'] and windows_image['Letter'] in ['S', 'T', 'W']: if windows_image['Local'] and windows_image['Letter'] in ['S', 'T', 'W']:
new_letter = try_and_print( new_letter = try_and_print(
message = 'Reassigning source volume letter...', message = 'Reassigning source volume letter...',
function = reassign_volume_letter, function = reassign_volume_letter,
other_results = other_results, other_results = other_results,
letter=windows_image['Letter']) letter=windows_image['Letter'])
windows_image['Path'] = '{}{}'.format( windows_image['Path'] = '{}{}'.format(
new_letter, windows_image['Path'][1:]) new_letter, windows_image['Path'][1:])
windows_image['Letter'] = new_letter windows_image['Letter'] = new_letter
# Format and partition disk # Format and partition disk
result = try_and_print( result = try_and_print(
message = 'Formatting disk...', message = 'Formatting disk...',
function = format_disk, function = format_disk,
other_results = other_results, other_results = other_results,
disk = dest_disk, disk = dest_disk,
use_gpt = dest_disk['Use GPT']) use_gpt = dest_disk['Use GPT'])
if not result['CS']: if not result['CS']:
# We need to crash as the disk is in an unknown state # We need to crash as the disk is in an unknown state
print_error('ERROR: Failed to format disk.') print_error('ERROR: Failed to format disk.')
raise GenericAbort raise GenericAbort
# Apply Image # Apply Image
result = try_and_print( result = try_and_print(
message = 'Applying image...', message = 'Applying image...',
function = setup_windows, function = setup_windows,
other_results = other_results, other_results = other_results,
windows_image = windows_image, windows_image = windows_image,
windows_version = windows_version) windows_version = windows_version)
if not result['CS']: if not result['CS']:
# We need to crash as the disk is in an unknown state # We need to crash as the disk is in an unknown state
print_error('ERROR: Failed to apply image.') print_error('ERROR: Failed to apply image.')
raise GenericAbort raise GenericAbort
# Create Boot files # Create Boot files
try_and_print( try_and_print(
message = 'Updating boot files...', message = 'Updating boot files...',
function = update_boot_partition, function = update_boot_partition,
other_results = other_results) other_results = other_results)
# Setup WinRE # Setup WinRE
try_and_print( try_and_print(
message = 'Updating recovery tools...', message = 'Updating recovery tools...',
function = setup_windows_re, function = setup_windows_re,
other_results = other_results, other_results = other_results,
windows_version = windows_version) windows_version = windows_version)
# Copy WinPE log(s) # Copy WinPE log(s)
source = r'{}\Logs'.format(global_vars['ClientDir']) source = r'{}\Logs'.format(global_vars['ClientDir'])
dest = r'W:\{}\Logs\WinPE'.format(KIT_NAME_SHORT) dest = r'W:\{}\Logs\WinPE'.format(KIT_NAME_SHORT)
shutil.copytree(source, dest) shutil.copytree(source, dest)
# Print summary
print_standard('\nDone.')
if 'LogFile' in global_vars and ask('\nReview log?'):
cmd = [
global_vars['Tools']['NotepadPlusPlus'],
global_vars['LogFile']]
try:
popen_program(cmd)
except Exception:
print_error('ERROR: Failed to open log.')
sleep(30)
pause('\nPress Enter to return to main menu... ')
# Print summary
print_standard('\nDone.')
if 'LogFile' in global_vars and ask('\nReview log?'):
cmd = [
global_vars['Tools']['NotepadPlusPlus'],
global_vars['LogFile']]
try:
popen_program(cmd)
except Exception:
print_error('ERROR: Failed to open log.')
sleep(30)
pause('\nPress Enter to return to main menu... ')
def menu_tools(): def menu_tools():
"""Tool launcher menu.""" """Tool launcher menu."""
tools = [{'Name': k} for k in sorted(PE_TOOLS.keys())] tools = [{'Name': k} for k in sorted(PE_TOOLS.keys())]
actions = [{'Name': 'Main Menu', 'Letter': 'M'},] actions = [{'Name': 'Main Menu', 'Letter': 'M'},]
set_title(KIT_NAME_FULL) set_title(KIT_NAME_FULL)
# Menu loop
while True:
selection = menu_select(
title = 'Tools Menu',
main_entries = tools,
action_entries = actions)
if (selection.isnumeric()):
name = tools[int(selection)-1]['Name']
cmd = [PE_TOOLS[name]['Path']] + PE_TOOLS[name].get('Args', [])
if name == 'Blue Screen View':
# Select path to scan
minidump_path = select_minidump_path()
if minidump_path:
cmd.extend(['/MiniDumpFolder', minidump_path])
try:
popen_program(cmd)
except Exception:
print_error('Failed to run {}'.format(name))
sleep(2)
pause()
elif (selection == 'M'):
break
# Menu loop
while True:
selection = menu_select(
title = 'Tools Menu',
main_entries = tools,
action_entries = actions)
if (selection.isnumeric()):
name = tools[int(selection)-1]['Name']
cmd = [PE_TOOLS[name]['Path']] + PE_TOOLS[name].get('Args', [])
if name == 'Blue Screen View':
# Select path to scan
minidump_path = select_minidump_path()
if minidump_path:
cmd.extend(['/MiniDumpFolder', minidump_path])
try:
popen_program(cmd)
except Exception:
print_error('Failed to run {}'.format(name))
sleep(2)
pause()
elif (selection == 'M'):
break
def select_minidump_path(): def select_minidump_path():
"""Select BSOD minidump path from a menu.""" """Select BSOD minidump path from a menu."""
dumps = [] dumps = []
# Assign volume letters first # Assign volume letters first
assign_volume_letters() assign_volume_letters()
# Search for minidumps # Search for minidumps
set_thread_error_mode(silent=True) # Prevents "No disk" popups set_thread_error_mode(silent=True) # Prevents "No disk" popups
for d in psutil.disk_partitions(): for d in psutil.disk_partitions():
if global_vars['Env']['SYSTEMDRIVE'].upper() in d.mountpoint: if global_vars['Env']['SYSTEMDRIVE'].upper() in d.mountpoint:
# Skip RAMDisk # Skip RAMDisk
continue continue
if os.path.exists(r'{}Windows\MiniDump'.format(d.mountpoint)): if os.path.exists(r'{}Windows\MiniDump'.format(d.mountpoint)):
dumps.append({'Name': r'{}Windows\MiniDump'.format(d.mountpoint)}) dumps.append({'Name': r'{}Windows\MiniDump'.format(d.mountpoint)})
set_thread_error_mode(silent=False) # Return to normal set_thread_error_mode(silent=False) # Return to normal
# Check results before showing menu # Check results before showing menu
if len(dumps) == 0: if len(dumps) == 0:
print_error('ERROR: No BSoD / MiniDump paths found') print_error('ERROR: No BSoD / MiniDump paths found')
sleep(2) sleep(2)
return None return None
# Menu
selection = menu_select(
title = 'Which BSoD / MiniDump path are we scanning?',
main_entries = dumps)
return dumps[int(selection) - 1]['Name']
# Menu
selection = menu_select(
title = 'Which BSoD / MiniDump path are we scanning?',
main_entries = dumps)
return dumps[int(selection) - 1]['Name']
if __name__ == '__main__': if __name__ == '__main__':
print("This file is not meant to be called directly.") print("This file is not meant to be called directly.")
# vim: sts=2 sw=2 ts=2

View file

@ -12,31 +12,32 @@ from functions.common import *
init_global_vars() init_global_vars()
if __name__ == '__main__': if __name__ == '__main__':
try:
# Prep
clear_screen()
print_standard('Hardware Diagnostics: Audio\n')
# Set volume
try: try:
# Prep run_program('amixer -q set "Master" 80% unmute'.split())
clear_screen() run_program('amixer -q set "PCM" 90% unmute'.split())
print_standard('Hardware Diagnostics: Audio\n') except subprocess.CalledProcessError:
print_error('Failed to set volume')
# Set volume # Run tests
try: for mode in ['pink', 'wav']:
run_program('amixer -q set "Master" 80% unmute'.split()) run_program(
run_program('amixer -q set "PCM" 90% unmute'.split()) cmd = 'speaker-test -c 2 -l 1 -t {}'.format(mode).split(),
except subprocess.CalledProcessError: check = False,
print_error('Failed to set volume') pipe = False)
# Run tests
for mode in ['pink', 'wav']:
run_program(
cmd = 'speaker-test -c 2 -l 1 -t {}'.format(mode).split(),
check = False,
pipe = False)
# Done
#print_standard('\nDone.')
#pause("Press Enter to exit...")
exit_script()
except SystemExit:
pass
except:
major_exception()
# Done
#print_standard('\nDone.')
#pause("Press Enter to exit...")
exit_script()
except SystemExit:
pass
except:
major_exception()
# vim: sts=2 sw=2 ts=2

View file

@ -10,37 +10,40 @@ os.chdir(os.path.dirname(os.path.realpath(__file__)))
sys.path.append(os.getcwd()) sys.path.append(os.getcwd())
from functions.network import * from functions.network import *
def check_connection(): def check_connection():
if not is_connected(): if not is_connected():
# Raise to cause NS in try_and_print() # Raise to cause NS in try_and_print()
raise Exception raise Exception
if __name__ == '__main__': if __name__ == '__main__':
try: try:
# Prep # Prep
clear_screen() clear_screen()
print_standard('Hardware Diagnostics: Network\n') print_standard('Hardware Diagnostics: Network\n')
# Connect # Connect
print_standard('Initializing...') print_standard('Initializing...')
connect_to_network() connect_to_network()
# Tests # Tests
try_and_print( try_and_print(
message='Network connection:', function=check_connection, cs='OK') message='Network connection:', function=check_connection, cs='OK')
show_valid_addresses() show_valid_addresses()
try_and_print(message='Internet connection:', function=ping, try_and_print(message='Internet connection:', function=ping,
addr='8.8.8.8', cs='OK') addr='8.8.8.8', cs='OK')
try_and_print(message='DNS Resolution:', function=ping, cs='OK') try_and_print(message='DNS Resolution:', function=ping, cs='OK')
try_and_print(message='Speedtest:', function=speedtest, try_and_print(message='Speedtest:', function=speedtest,
print_return=True) print_return=True)
# Done
print_standard('\nDone.')
#pause("Press Enter to exit...")
exit_script()
except SystemExit:
pass
except:
major_exception()
# Done
print_standard('\nDone.')
#pause("Press Enter to exit...")
exit_script()
except SystemExit:
pass
except:
major_exception()
# vim: sts=2 sw=2 ts=2

View file

@ -12,27 +12,28 @@ from functions.data import *
init_global_vars() init_global_vars()
if __name__ == '__main__': if __name__ == '__main__':
try: try:
# Prep # Prep
clear_screen() clear_screen()
print_standard('{}: Volume mount tool'.format(KIT_NAME_FULL)) print_standard('{}: Volume mount tool'.format(KIT_NAME_FULL))
# Mount volumes # Mount volumes
report = mount_volumes(all_devices=True) report = mount_volumes(all_devices=True)
# Print report # Print report
print_info('\nResults') print_info('\nResults')
for vol_name, vol_data in sorted(report.items()): for vol_name, vol_data in sorted(report.items()):
show_data(indent=4, width=20, **vol_data['show_data']) show_data(indent=4, width=20, **vol_data['show_data'])
# Done # Done
print_standard('\nDone.') print_standard('\nDone.')
if 'gui' in sys.argv: if 'gui' in sys.argv:
pause("Press Enter to exit...") pause("Press Enter to exit...")
popen_program(['nohup', 'thunar', '/media'], pipe=True) popen_program(['nohup', 'thunar', '/media'], pipe=True)
exit_script() exit_script()
except SystemExit: except SystemExit:
pass pass
except: except:
major_exception() major_exception()
# vim: sts=2 sw=2 ts=2

View file

@ -13,26 +13,27 @@ from functions.network import *
init_global_vars() init_global_vars()
if __name__ == '__main__': if __name__ == '__main__':
try: try:
# Prep # Prep
clear_screen() clear_screen()
# Connect # Connect
connect_to_network() connect_to_network()
# Mount # Mount
if is_connected(): if is_connected():
mount_backup_shares(read_write=True) mount_backup_shares(read_write=True)
else: else:
# Couldn't connect # Couldn't connect
print_error('ERROR: No network connectivity.') print_error('ERROR: No network connectivity.')
# Done
print_standard('\nDone.')
#pause("Press Enter to exit...")
exit_script()
except SystemExit:
pass
except:
major_exception()
# Done
print_standard('\nDone.')
#pause("Press Enter to exit...")
exit_script()
except SystemExit:
pass
except:
major_exception()
# vim: sts=2 sw=2 ts=2

View file

@ -9,10 +9,10 @@ import sys
# STATIC VARIABLES # STATIC VARIABLES
SCANDIR = os.getcwd() SCANDIR = os.getcwd()
USAGE = '''Usage: {script} <search-terms>... USAGE = '''Usage: {script} <search-terms>...
e.g. {script} "Book Title" "Keyword" "etc" e.g. {script} "Book Title" "Keyword" "etc"
This script will search all doc/docx files below the current directory for This script will search all doc/docx files below the current directory for
the search-terms provided (case-insensitive).'''.format(script=__file__) the search-terms provided (case-insensitive).'''.format(script=__file__)
# Init # Init
os.chdir(os.path.dirname(os.path.realpath(__file__))) os.chdir(os.path.dirname(os.path.realpath(__file__)))
@ -22,60 +22,64 @@ init_global_vars()
REGEX_DOC_FILES = re.compile(r'\.docx?$', re.IGNORECASE) REGEX_DOC_FILES = re.compile(r'\.docx?$', re.IGNORECASE)
def scan_for_docs(path): def scan_for_docs(path):
for entry in os.scandir(path): for entry in os.scandir(path):
if entry.is_dir(follow_symlinks=False): if entry.is_dir(follow_symlinks=False):
yield from scantree(entry.path) yield from scan_for_docs(entry.path)
elif entry.is_file and REGEX_DOC_FILES.search(entry.name): elif entry.is_file and REGEX_DOC_FILES.search(entry.name):
yield entry yield entry
def scan_file(file_path, search): def scan_file(file_path, search):
match = False match = False
try: try:
if entry.name.lower().endswith('.docx'): if entry.name.lower().endswith('.docx'):
result = run_program(['unzip', '-p', entry.path]) result = run_program(['unzip', '-p', entry.path])
else: else:
# Assuming .doc # Assuming .doc
result = run_program(['antiword', entry.path]) result = run_program(['antiword', entry.path])
out = result.stdout.decode() out = result.stdout.decode()
match = re.search(search, out, re.IGNORECASE) match = re.search(search, out, re.IGNORECASE)
except Exception: except Exception:
# Ignore errors since files may be corrupted # Ignore errors since files may be corrupted
pass pass
return entry.path if match else None return entry.path if match else None
if __name__ == '__main__': if __name__ == '__main__':
try: try:
# Prep # Prep
clear_screen() clear_screen()
terms = [re.sub(r'\s+', r'\s*', t) for t in sys.argv[1:]] terms = [re.sub(r'\s+', r'\s*', t) for t in sys.argv[1:]]
search = '({})'.format('|'.join(terms)) search = '({})'.format('|'.join(terms))
if len(sys.argv) == 1: if len(sys.argv) == 1:
# Print usage # Print usage
print_standard(USAGE) print_standard(USAGE)
else: else:
matches = [] matches = []
for entry in scan_for_docs(SCANDIR): for entry in scan_for_docs(SCANDIR):
matches.append(scan_file(entry.path, search)) matches.append(scan_file(entry.path, search))
# Strip None values (i.e. non-matching entries) # Strip None values (i.e. non-matching entries)
matches = [m for m in matches if m] matches = [m for m in matches if m]
if matches: if matches:
print_success('Found {} {}:'.format( print_success('Found {} {}:'.format(
len(matches), len(matches),
'Matches' if len(matches) > 1 else 'Match')) 'Matches' if len(matches) > 1 else 'Match'))
for match in matches: for match in matches:
print_standard(match) print_standard(match)
else: else:
print_error('No matches found.') print_error('No matches found.')
# Done
print_standard('\nDone.')
#pause("Press Enter to exit...")
exit_script()
except SystemExit:
pass
except:
major_exception()
# Done
print_standard('\nDone.')
#pause("Press Enter to exit...")
exit_script()
except SystemExit:
pass
except:
major_exception()
# vim: sts=2 sw=2 ts=2

View file

@ -0,0 +1,325 @@
# Wizard Kit: Settings - Partition UIDs
# sources: https://en.wikipedia.org/wiki/GUID_Partition_Table
# https://en.wikipedia.org/wiki/Partition_type
# NOTE: Info has been trimmed for brevity. As such, there may be some inaccuracy.
PARTITION_UIDS = {
'00': {'OS': 'All','Description': 'Empty partition entry'},
'01': {'OS': 'DOS','Description': 'FAT12 as primary partition'},
'02': {'OS': 'XENIX','Description': 'XENIX root'},
'03': {'OS': 'XENIX','Description': 'XENIX usr'},
'04': {'OS': 'DOS','Description': 'FAT16 with less than 32 MB'},
'05': {'OS': 'DOS / SpeedStor','Description': 'Extended partition'},
'06': {'OS': 'DOS1+','Description': 'FAT16B [over 65K sectors]'},
'07': {'OS': 'Windows / OS/2 / QNX 2','Description': 'NTFS/exFAT/HPFS/IFS/QNX'},
'08': {'OS': 'CBM / DOS / OS/2 / AIX /QNX','Description': 'FAT12-16/AIX/QNY/SplitDrive'},
'09': {'OS': 'AIX / QNX / Coherent / OS-9','Description': 'AIX/QNZ/Coherent/RBF'},
'0A': {'OS': 'OS/2 / Coherent','Description': 'Boot Manager / Swap'},
'0B': {'OS': 'DOS','Description': 'FAT32 with CHS addressing'},
'0C': {'OS': 'DOS','Description': 'FAT32 with LBA'},
'0D': {'OS': 'Silicon Safe','Description': 'Reserved'},
'0E': {'OS': 'DOS','Description': 'FAT16B with LBA'},
'0F': {'OS': 'DOS','Description': 'Extended partition with LBA'},
'10': {'OS': 'OPUS','Description': 'Unknown'},
'11': {'OS': 'Leading Edge MS-DOS / OS/2','Description': 'FAT12/FAT16'},
'12': {'OS': 'Compaq Contura','Description': 'conf/diag/hiber/rescue/serv'},
'14': {'OS': 'AST DOS / OS/2 / MaverickOS','Description': 'FAT12/FAT16/Omega'},
'15': {'OS': 'OS/2 / Maverick OS','Description': 'Hidden extended / Swap'},
'16': {'OS': 'OS/2 Boot Manager','Description': 'Hidden FAT16B'},
'17': {'OS': 'OS/2 Boot Manager','Description': 'Hidden IFS/HPFS/NTFS/exFAT'},
'18': {'OS': 'AST Windows','Description': '0-Volt Suspend/SmartSleep'},
'19': {'OS': 'Willowtech Photon coS','Description': 'Willowtech Photon coS'},
'1B': {'OS': 'OS/2 Boot Manager','Description': 'Hidden FAT32'},
'1C': {'OS': 'OS/2 Boot Manager','Description': 'Hidden FAT32 with LBA'},
'1E': {'OS': 'OS/2 Boot Manager','Description': 'Hidden FAT16 with LBA'},
'1F': {'OS': 'OS/2 Boot Manager','Description': 'Hidden extended with LBA'},
'20': {'OS': 'Windows Mobile','Description': 'update XIP/Willowsoft OFS1'},
'21': {'OS': 'Oxygen','Description': 'SpeedStor / FSo2'},
'22': {'OS': 'Oxygen','Description': 'Oxygen Extended Partition'},
'23': {'OS': 'Windows Mobile','Description': 'Reserved / boot XIP'},
'24': {'OS': 'NEC MS-DOS0','Description': 'Logical FAT12 or FAT16'},
'25': {'OS': 'Windows Mobile','Description': 'IMGFS[citation needed]'},
'26': {'OS': 'Microsoft, IBM','Description': 'Reserved'},
'27': {'OS': 'Win/PQserv/MirOS/RooterBOOT','Description': 'WinRE/Rescue/MirOS/RooterBOOT'},
'2A': {'OS': 'AtheOS','Description': 'AthFS/AFS/Reserved'},
'2B': {'OS': 'SyllableOS','Description': 'SyllableSecure (SylStor)'},
'31': {'OS': 'Microsoft, IBM','Description': 'Reserved'},
'32': {'OS': 'NOS','Description': 'Unknown'},
'33': {'OS': 'Microsoft, IBM','Description': 'Reserved'},
'34': {'OS': 'Microsoft, IBM','Description': 'Reserved'},
'35': {'OS': 'OS/2 Server /eComStation','Description': 'JFS'},
'36': {'OS': 'Microsoft, IBM','Description': 'Reserved'},
'38': {'OS': 'THEOS','Description': 'THEOS version 3.2, 2 GB'},
'39': {'OS': 'Plan 9 / THEOS','Description': 'Plan 9 edition 3 / THEOS v4'},
'3A': {'OS': 'THEOS','Description': 'THEOS v4, 4 GB'},
'3B': {'OS': 'THEOS','Description': 'THEOS v4 extended'},
'3C': {'OS': 'PartitionMagic','Description': 'PqRP (image in progress)'},
'3D': {'OS': 'PartitionMagic','Description': 'Hidden NetWare'},
'3F': {'OS': 'OS/32','Description': 'Unknown'},
'40': {'OS': 'PICK / Venix','Description': 'PICK R83 / Venix 80286'},
'41': {'OS': 'RISC / Linux / PowerPC','Description': 'Boot / Old Linux/Minix'},
'42': {'OS': 'SFS / Linux / Win2K/XP/etc','Description': 'SFS / Old Linux Swap'},
'43': {'OS': 'Linux','Description': 'Old Linux native'},
'44': {'OS': 'GoBack','Description': 'Norton/WildFire/Adaptec/Roxio'},
'45': {'OS': 'Boot-US / EUMEL/ELAN','Description': 'Priam/Boot/EUMEL/ELAN (L2)'},
'46': {'OS': 'EUMEL/ELAN','Description': 'EUMEL/ELAN (L2)'},
'47': {'OS': 'EUMEL/ELAN','Description': 'EUMEL/ELAN (L2)'},
'48': {'OS': 'EUMEL/ELAN','Description': 'EUMEL/ELAN (L2), ERGOS L3'},
'4A': {'OS': 'AdaOS / ALFS/THIN','Description': 'Aquila / ALFS/THIN'},
'4C': {'OS': 'ETH Oberon','Description': 'Aos (A2) file system (76)'},
'4D': {'OS': 'QNX Neutrino','Description': 'Primary QNX POSIX volume'},
'4E': {'OS': 'QNX Neutrino','Description': 'Secondary QNX POSIX volume'},
'4F': {'OS': 'QNX Neutrino / ETH Oberon','Description': '3rd QNX POSIX/Boot/Native'},
'50': {'OS': 'DiskMan4/ETH/LynxOS/Novell','Description': 'Alt FS/Read-only/Lynx RTOS'},
'51': {'OS': 'Disk Manager 4-6','Description': 'R/W partition (Aux 1)'},
'52': {'OS': 'CP/M-80/ System V/AT, V/386','Description': 'CP/M-80'},
'53': {'OS': 'Disk Manager 6','Description': 'Auxiliary 3 (WO)'},
'54': {'OS': 'Disk Manager 6','Description': 'Dynamic Drive Overlay (DDO)'},
'55': {'OS': 'EZ-Drive','Description': 'Maxtor/MaxBlast/DriveGuide'},
'56': {'OS': 'AT&T DOS/EZ-Drive/VFeature','Description': 'FAT12 16/EZ-BIOS/VFeature'},
'57': {'OS': 'DrivePro','Description': 'VNDI partition'},
'5C': {'OS': 'EDISK','Description': 'Priam EDisk Volume'},
'61': {'OS': 'SpeedStor','Description': 'Unknown'},
'63': {'OS': 'Unix','Description': 'Unix,ISC,SysV,ix,BSD,HURD'},
'64': {'OS': 'SpeedStor / NetWare','Description': 'NetWare FS 286/2,PC-ARMOUR'},
'65': {'OS': 'NetWare','Description': 'NetWare File System 386'},
'66': {'OS': 'NetWare / NetWare','Description': 'NetWare FS 386 / SMS'},
'67': {'OS': 'NetWare','Description': 'Wolf Mountain'},
'68': {'OS': 'NetWare','Description': 'Unknown'},
'69': {'OS': 'NetWare 5 / NetWare','Description': 'Novell Storage Services'},
'6E': {'Description': 'Unknown'},
'70': {'OS': 'DiskSecure','Description': 'DiskSecure multiboot'},
'71': {'OS': 'Microsoft, IBM','Description': 'Reserved'},
'72': {'OS': 'APTI systems / Unix V7/x86','Description': 'APTI altFAT12 / V7 / x86'},
'73': {'OS': 'Microsoft, IBM','Description': 'Reserved'},
'74': {'OS': 'Microsoft, IBM','Description': 'Reserved / Scramdisk'},
'75': {'OS': 'PC/IX','Description': 'Unknown'},
'76': {'OS': 'Microsoft, IBM','Description': 'Reserved'},
'77': {'OS': 'Novell','Description': 'VNDI, M2FS, M2CS'},
'78': {'OS': 'Geurt Vos','Description': 'XOSL bootloader file system'},
'79': {'OS': 'APTI conformant systems','Description': 'APTI altFAT16 (CHS, SFN)'},
'7A': {'OS': 'APTI conformant systems','Description': 'APTI altFAT16 (LBA, SFN)'},
'7B': {'OS': 'APTI conformant systems','Description': 'APTI altFAT16B (CHS, SFN)'},
'7C': {'OS': 'APTI conformant systems','Description': 'APTI altFAT32 (LBA, SFN)'},
'7D': {'OS': 'APTI conformant systems','Description': 'APTI altFAT32 (CHS, SFN)'},
'7E': {'OS': 'F.I.X. (claim) / PrimoCache','Description': 'Level 2 cache'},
'7F': {'OS': 'Varies','Description': 'AltOS DevPartition Standard'},
'80': {'OS': 'Minix 1.1-1.4a','Description': 'Minix file system (old)'},
'81': {'OS': 'Minix 1.4b+ / Linux','Description': 'MINIX FS/Mitac AdvDiskManager'},
'82': {'OS': 'Linux / Sun Microsystems','Description': 'Swap / Solaris x86 / Prime'},
'83': {'OS': 'GNU/Linux','Description': 'Any native Linux FS'},
'84': {'OS': 'OS/2 / Windows 7','Description': 'Hibernat/HiddenC/RapidStart'},
'85': {'OS': 'GNU/Linux','Description': 'Linux extended'},
'86': {'OS': 'Windows NT 4 Server / Linux','Description': 'FAT16B mirror/LinuxRAID-old'},
'87': {'OS': 'Windows NT 4 Server','Description': 'HPFS/NTFS mirrored volume'},
'88': {'OS': 'GNU/Linux','Description': 'Plaintext partition table'},
'8A': {'OS': 'AiR-BOOT','Description': 'Linux kernel image'},
'8B': {'OS': 'Windows NT 4 Server','Description': 'FAT32 mirrored volume set'},
'8C': {'OS': 'Windows NT 4 Server','Description': 'FAT32 mirrored volume set'},
'8D': {'OS': 'Free FDISK','Description': 'Hidden FAT12'},
'8E': {'OS': 'Linux','Description': 'Linux LVM'},
'90': {'OS': 'Free FDISK','Description': 'Hidden FAT16'},
'91': {'OS': 'Free FDISK','Description': 'Hidden extended partition'},
'92': {'OS': 'Free FDISK','Description': 'Hidden FAT16B'},
'93': {'OS': 'Amoeba / Linux','Description': 'Amoeba native/Hidden Linux'},
'94': {'OS': 'Amoeba','Description': 'Amoeba bad block table'},
'95': {'OS': 'EXOPC','Description': 'EXOPC native'},
'96': {'OS': 'CHRP','Description': 'ISO-9660 file system'},
'97': {'OS': 'Free FDISK','Description': 'Hidden FAT32'},
'98': {'OS': 'Free FDISK / ROM-DOS','Description': 'Hidden FAT32 / service part'},
'99': {'OS': 'early Unix','Description': 'Unknown'},
'9A': {'OS': 'Free FDISK','Description': 'Hidden FAT16'},
'9B': {'OS': 'Free FDISK','Description': 'Hidden extended partition'},
'9E': {'OS': 'VSTA / ForthOS','Description': 'ForthOS (eForth port)'},
'9F': {'OS': 'BSD/OS 3.0+, BSDI','Description': 'Unknown'},
'A0': {'OS': 'HP/Phoenix/IBM/Toshiba/Sony','Description': 'Diagnostic for HP/Hibernate'},
'A1': {'OS': 'HP / Phoenix, NEC','Description': 'HP Vol Expansion/Hibernate'},
'A2': {'OS': 'Cyclone V','Description': 'Hard Processor System (HPS)'},
'A3': {'OS': 'HP','Description': 'HP Vol Expansion(SpeedStor)'},
'A4': {'OS': 'HP','Description': 'HP Vol Expansion(SpeedStor)'},
'A5': {'OS': 'BSD','Description': 'BSD slice'},
'A6': {'OS': 'OpenBSD','Description': 'HP Vol Expansion/BSD slice'},
'A7': {'OS': 'NeXT','Description': 'NeXTSTEP'},
'A8': {'OS': 'Darwin, Mac OS X','Description': 'Apple Darwin, Mac OS X UFS'},
'A9': {'OS': 'NetBSD','Description': 'NetBSD slice'},
'AA': {'OS': 'MS-DOS','Description': 'Olivetti DOS FAT12(1.44 MB)'},
'AB': {'OS': 'Darwin, Mac OS X / GO! OS','Description': 'Apple Darwin/OS X boot/GO!'},
'AD': {'OS': 'RISC OS','Description': 'ADFS / FileCore format'},
'AE': {'OS': 'ShagOS','Description': 'ShagOS file system'},
'AF': {'OS': 'ShagOS','Description': 'OS X HFS & HFS+/ShagOS Swap'},
'B0': {'OS': 'Boot-Star','Description': 'Boot-Star dummy partition'},
'B1': {'OS': 'QNX 6.x','Description': 'HPVolExpansion/QNX Neutrino'},
'B2': {'OS': 'QNX 6.x','Description': 'QNX Neutrino power-safe FS'},
'B3': {'OS': 'QNX 6.x','Description': 'HPVolExpansion/QNX Neutrino'},
'B4': {'OS': 'HP','Description': 'HP Vol Expansion(SpeedStor)'},
'B6': {'OS': 'Windows NT 4 Server','Description': 'HPVolExpansion/FAT16Bmirror'},
'B7': {'OS': 'BSDI / Windows NT 4 Server','Description': 'BSDI,Swap,HPFS/NTFS mirror'},
'B8': {'OS': 'BSDI (before 3.0)','Description': 'BSDI Swap / native FS'},
'BB': {'OS': 'Acronis/BootWizard/WinNT 4','Description': 'BootWizard/OEM/FAT32 mirror'},
'BC': {'OS': 'Acronis/WinNT/BackupCapsule','Description': 'FAT32RAID/SecureZone/Backup'},
'BD': {'OS': 'BonnyDOS/286','Description': 'Unknown'},
'BE': {'OS': 'Solaris 8','Description': 'Solaris 8 boot'},
'BF': {'OS': 'Solaris','Description': 'Solaris x86'},
'C0': {'OS': 'DR-DOS,MultiuserDOS,REAL/32','Description': 'Secured FAT (under 32 MB)'},
'C1': {'OS': 'DR DOS','Description': 'Secured FAT12'},
'C2': {'OS': 'Power Boot','Description': 'Hidden Linux native FS'},
'C3': {'OS': 'Power Boot','Description': 'Hidden Linux Swap'},
'C4': {'OS': 'DR DOS','Description': 'Secured FAT16'},
'C5': {'OS': 'DR DOS','Description': 'Secured extended partition'},
'C6': {'OS': 'DR DOS / WinNT 4 Server','Description': 'Secured FAT16B/FAT16Bmirror'},
'C7': {'OS': 'Syrinx / WinNT 4 Server','Description': 'Syrinx boot/HPFS/NTFSmirror'},
'C8': {'Description': "DR-DOS Reserved (since '97)"},
'C9': {'Description': "DR-DOS Reserved (since '97)"},
'CA': {'Description': "DR-DOS Reserved (since '97)"},
'CB': {'OS': 'DR-DOSx / WinNT 4 Server','Description': 'Secured FAT32/FAT32 mirror'},
'CC': {'OS': 'DR-DOSx / WinNT 4 Server','Description': 'Secured FAT32/FAT32 mirror'},
'CD': {'OS': 'CTOS','Description': 'Memory dump'},
'CE': {'OS': 'DR-DOSx','Description': 'Secured FAT16B'},
'CF': {'OS': 'DR-DOSx','Description': 'Secured extended partition'},
'D0': {'OS': 'Multiuser DOS, REAL/32','Description': 'Secured FAT (over 32 MB)'},
'D1': {'OS': 'Multiuser DOS','Description': 'Secured FAT12'},
'D4': {'OS': 'Multiuser DOS','Description': 'Secured FAT16'},
'D5': {'OS': 'Multiuser DOS','Description': 'Secured extended partition'},
'D6': {'OS': 'Multiuser DOS','Description': 'Secured FAT16B'},
'D8': {'OS': 'Digital Research','Description': 'CP/M-86 [citation needed]'},
'DA': {'OS': 'Powercopy Backup','Description': 'Non-FS data / Shielded disk'},
'DB': {'OS': 'CP/M-86/CDOS/CTOS/D800/DRMK','Description': 'CP/M-86/ConcDOS/Boot/FAT32'},
'DD': {'OS': 'CTOS','Description': 'Hidden memory dump'},
'DE': {'OS': 'Dell','Description': 'FAT16 utility/diagnostic'},
'DF': {'OS': 'DG/UX / BootIt / Aviion','Description': 'DG/UX Virt DiskMan / EMBRM'},
'E0': {'OS': 'STMicroelectronics','Description': 'ST AVFS'},
'E1': {'OS': 'SpeedStor','Description': 'ExtendedFAT12 >1023cylinder'},
'E2': {'Description': 'DOS read-only (XFDISK)'},
'E3': {'OS': 'SpeedStor','Description': 'DOS read-only'},
'E4': {'OS': 'SpeedStor','Description': 'ExtendedFAT16 <1024cylinder'},
'E5': {'OS': 'Tandy MS-DOS','Description': 'Logical FAT12 or FAT16'},
'E6': {'OS': 'SpeedStor','Description': 'Unknown'},
'E8': {'OS': 'LUKS','Description': 'Linux Unified Key Setup'},
'EB': {'OS': 'BeOS, Haiku','Description': 'BFS'},
'EC': {'OS': 'SkyOS','Description': 'SkyFS'},
'ED': {'OS': 'Sprytix / EDD 4','Description': 'EDC loader / GPT hybrid MBR'},
'EE': {'OS': 'EFI','Description': 'GPT protective MBR'},
'EF': {'OS': 'EFI','Description': 'EFI system partition'},
'F0': {'OS': 'Linux / OS/32','Description': 'PA-RISC Linux boot loader.'},
'F1': {'OS': 'SpeedStor','Description': 'Unknown'},
'F2': {'OS': 'SperryIT DOS/Unisys DOS','Description': 'Logical FAT12/FAT16'},
'F3': {'OS': 'SpeedStor','Description': 'Unknown'},
'F4': {'OS': 'SpeedStor / Prologue','Description': '"large"DOS part/NGF/TwinFS'},
'F5': {'OS': 'Prologue','Description': 'MD0-MD9 part for NGF/TwinFS'},
'F6': {'OS': 'SpeedStor','Description': 'Unknown'},
'F7': {'OS': 'O.S.G. / X1','Description': 'EFAT / Solid State FS'},
'F9': {'OS': 'Linux','Description': 'pCache ext2/ext3 cache'},
'FA': {'OS': 'Bochs','Description': 'x86 emulator'},
'FB': {'OS': 'VMware','Description': 'VMware VMFS partition'},
'FC': {'OS': 'VMware','Description': 'Swap / VMKCORE kernel dump'},
'FD': {'OS': 'Linux / FreeDOS','Description': 'LinuxRAID/Reserved4FreeDOS'},
'FE': {'OS': 'SpeedStor/LANstep/NT/Linux','Description': 'PS/2/DiskAdmin/old LinuxLVM'},
'FF': {'OS': 'XENIX','Description': 'XENIX bad block table'},
'00000000-0000-0000-0000-000000000000': {'Description': 'Unused entry'},
'024DEE41-33E7-11D3-9D69-0008C781F39F': {'Description': 'MBR partition scheme'},
'C12A7328-F81F-11D2-BA4B-00A0C93EC93B': {'Description': 'EFI System partition'},
'21686148-6449-6E6F-744E-656564454649': {'Description': 'BIOS Boot partition'},
'D3BFE2DE-3DAF-11DF-BA40-E3A556D89593': {'Description': 'Intel Fast Flash (iFFS) partition (for Intel Rapid Start technology)'},
'F4019732-066E-4E12-8273-346C5641494F': {'Description': 'Sony boot partition'},
'BFBFAFE7-A34F-448A-9A5B-6213EB736C22': {'Description': 'Lenovo boot partition'},
'E3C9E316-0B5C-4DB8-817D-F92DF00215AE': {'OS': 'Windows', 'Description': 'Microsoft Reserved Partition (MSR)'},
'EBD0A0A2-B9E5-4433-87C0-68B6B72699C7': {'OS': 'Windows', 'Description': 'Basic data partition'},
'5808C8AA-7E8F-42E0-85D2-E1E90434CFB3': {'OS': 'Windows', 'Description': 'Logical Disk Manager (LDM) metadata partition'},
'AF9B60A0-1431-4F62-BC68-3311714A69AD': {'OS': 'Windows', 'Description': 'Logical Disk Manager data partition'},
'DE94BBA4-06D1-4D40-A16A-BFD50179D6AC': {'OS': 'Windows', 'Description': 'Windows Recovery Environment'},
'37AFFC90-EF7D-4E96-91C3-2D7AE055B174': {'OS': 'Windows', 'Description': 'IBM General Parallel File System (GPFS) partition'},
'E75CAF8F-F680-4CEE-AFA3-B001E56EFC2D': {'OS': 'Windows', 'Description': 'Storage Spaces partition'},
'75894C1E-3AEB-11D3-B7C1-7B03A0000000': {'OS': 'HP-UX', 'Description': 'Data partition'},
'E2A1E728-32E3-11D6-A682-7B03A0000000': {'OS': 'HP-UX', 'Description': 'Service Partition'},
'0FC63DAF-8483-4772-8E79-3D69D8477DE4': {'OS': 'Linux', 'Description': 'Linux filesystem data'},
'A19D880F-05FC-4D3B-A006-743F0F84911E': {'OS': 'Linux', 'Description': 'RAID partition'},
'44479540-F297-41B2-9AF7-D131D5F0458A': {'OS': 'Linux', 'Description': 'Root partition (x86)'},
'4F68BCE3-E8CD-4DB1-96E7-FBCAF984B709': {'OS': 'Linux', 'Description': 'Root partition (x86-64)'},
'69DAD710-2CE4-4E3C-B16C-21A1D49ABED3': {'OS': 'Linux', 'Description': 'Root partition (32-bit ARM)'},
'B921B045-1DF0-41C3-AF44-4C6F280D3FAE': {'OS': 'Linux', 'Description': 'Root partition (64-bit ARM)/AArch64)'},
'0657FD6D-A4AB-43C4-84E5-0933C84B4F4F': {'OS': 'Linux', 'Description': 'Swap partition'},
'E6D6D379-F507-44C2-A23C-238F2A3DF928': {'OS': 'Linux', 'Description': 'Logical Volume Manager (LVM) partition'},
'933AC7E1-2EB4-4F13-B844-0E14E2AEF915': {'OS': 'Linux', 'Description': '/home partition'},
'3B8F8425-20E0-4F3B-907F-1A25A76F98E8': {'OS': 'Linux', 'Description': '/srv (server data) partition'},
'7FFEC5C9-2D00-49B7-8941-3EA10A5586B7': {'OS': 'Linux', 'Description': 'Plain dm-crypt partition'},
'CA7D7CCB-63ED-4C53-861C-1742536059CC': {'OS': 'Linux', 'Description': 'LUKS partition'},
'8DA63339-0007-60C0-C436-083AC8230908': {'OS': 'Linux', 'Description': 'Reserved'},
'83BD6B9D-7F41-11DC-BE0B-001560B84F0F': {'OS': 'FreeBSD', 'Description': 'Boot partition'},
'516E7CB4-6ECF-11D6-8FF8-00022D09712B': {'OS': 'FreeBSD', 'Description': 'Data partition'},
'516E7CB5-6ECF-11D6-8FF8-00022D09712B': {'OS': 'FreeBSD', 'Description': 'Swap partition'},
'516E7CB6-6ECF-11D6-8FF8-00022D09712B': {'OS': 'FreeBSD', 'Description': 'Unix File System (UFS) partition'},
'516E7CB8-6ECF-11D6-8FF8-00022D09712B': {'OS': 'FreeBSD', 'Description': 'Vinum volume manager partition'},
'516E7CBA-6ECF-11D6-8FF8-00022D09712B': {'OS': 'FreeBSD', 'Description': 'ZFS partition'},
'48465300-0000-11AA-AA11-00306543ECAC': {'OS': 'OS X Darwin', 'Description': 'Hierarchical File System Plus (HFS+) partition'},
'55465300-0000-11AA-AA11-00306543ECAC': {'OS': 'OS X Darwin', 'Description': 'Apple UFS'},
'6A898CC3-1DD2-11B2-99A6-080020736631': {'OS': 'OS X Darwin', 'Description': 'ZFS'},
'52414944-0000-11AA-AA11-00306543ECAC': {'OS': 'OS X Darwin', 'Description': 'Apple RAID partition'},
'52414944-5F4F-11AA-AA11-00306543ECAC': {'OS': 'OS X Darwin', 'Description': 'Apple RAID partition, offline'},
'426F6F74-0000-11AA-AA11-00306543ECAC': {'OS': 'OS X Darwin', 'Description': 'Apple Boot partition (Recovery HD)'},
'4C616265-6C00-11AA-AA11-00306543ECAC': {'OS': 'OS X Darwin', 'Description': 'Apple Label'},
'5265636F-7665-11AA-AA11-00306543ECAC': {'OS': 'OS X Darwin', 'Description': 'Apple TV Recovery partition'},
'53746F72-6167-11AA-AA11-00306543ECAC': {'OS': 'OS X Darwin', 'Description': 'Apple Core Storage (i.e. Lion FileVault) partition'},
'6A82CB45-1DD2-11B2-99A6-080020736631': {'OS': 'Solaris illumos', 'Description': 'Boot partition'},
'6A85CF4D-1DD2-11B2-99A6-080020736631': {'OS': 'Solaris illumos', 'Description': 'Root partition'},
'6A87C46F-1DD2-11B2-99A6-080020736631': {'OS': 'Solaris illumos', 'Description': 'Swap partition'},
'6A8B642B-1DD2-11B2-99A6-080020736631': {'OS': 'Solaris illumos', 'Description': 'Backup partition'},
'6A898CC3-1DD2-11B2-99A6-080020736631': {'OS': 'Solaris illumos', 'Description': '/usr partition'},
'6A8EF2E9-1DD2-11B2-99A6-080020736631': {'OS': 'Solaris illumos', 'Description': '/var partition'},
'6A90BA39-1DD2-11B2-99A6-080020736631': {'OS': 'Solaris illumos', 'Description': '/home partition'},
'6A9283A5-1DD2-11B2-99A6-080020736631': {'OS': 'Solaris illumos', 'Description': 'Alternate sector'},
'6A945A3B-1DD2-11B2-99A6-080020736631': {'OS': 'Solaris illumos', 'Description': 'Reserved partition'},
'6A9630D1-1DD2-11B2-99A6-080020736631': {'OS': 'Solaris illumos'},
'6A980767-1DD2-11B2-99A6-080020736631': {'OS': 'Solaris illumos'},
'6A96237F-1DD2-11B2-99A6-080020736631': {'OS': 'Solaris illumos'},
'6A8D2AC7-1DD2-11B2-99A6-080020736631': {'OS': 'Solaris illumos'},
'49F48D32-B10E-11DC-B99B-0019D1879648': {'OS': 'NetBSD', 'Description': 'Swap partition'},
'49F48D5A-B10E-11DC-B99B-0019D1879648': {'OS': 'NetBSD', 'Description': 'FFS partition'},
'49F48D82-B10E-11DC-B99B-0019D1879648': {'OS': 'NetBSD', 'Description': 'LFS partition'},
'49F48DAA-B10E-11DC-B99B-0019D1879648': {'OS': 'NetBSD', 'Description': 'RAID partition'},
'2DB519C4-B10F-11DC-B99B-0019D1879648': {'OS': 'NetBSD', 'Description': 'Concatenated partition'},
'2DB519EC-B10F-11DC-B99B-0019D1879648': {'OS': 'NetBSD', 'Description': 'Encrypted partition'},
'FE3A2A5D-4F32-41A7-B725-ACCC3285A309': {'OS': 'ChromeOS', 'Description': 'ChromeOS kernel'},
'3CB8E202-3B7E-47DD-8A3C-7FF2A13CFCEC': {'OS': 'ChromeOS', 'Description': 'ChromeOS rootfs'},
'2E0A753D-9E48-43B0-8337-B15192CB1B5E': {'OS': 'ChromeOS', 'Description': 'ChromeOS future use'},
'42465331-3BA3-10F1-802A-4861696B7521': {'OS': 'Haiku', 'Description': 'Haiku BFS'},
'85D5E45E-237C-11E1-B4B3-E89A8F7FC3A7': {'OS': 'MidnightBSD', 'Description': 'Boot partition'},
'85D5E45A-237C-11E1-B4B3-E89A8F7FC3A7': {'OS': 'MidnightBSD', 'Description': 'Data partition'},
'85D5E45B-237C-11E1-B4B3-E89A8F7FC3A7': {'OS': 'MidnightBSD', 'Description': 'Swap partition'},
'0394EF8B-237E-11E1-B4B3-E89A8F7FC3A7': {'OS': 'MidnightBSD', 'Description': 'Unix File System (UFS) partition'},
'85D5E45C-237C-11E1-B4B3-E89A8F7FC3A7': {'OS': 'MidnightBSD', 'Description': 'Vinum volume manager partition'},
'85D5E45D-237C-11E1-B4B3-E89A8F7FC3A7': {'OS': 'MidnightBSD', 'Description': 'ZFS partition'},
'45B0969E-9B03-4F30-B4C6-B4B80CEFF106': {'OS': 'Ceph', 'Description': 'Ceph Journal'},
'45B0969E-9B03-4F30-B4C6-5EC00CEFF106': {'OS': 'Ceph', 'Description': 'Ceph dm-crypt Encrypted Journal'},
'4FBD7E29-9D25-41B8-AFD0-062C0CEFF05D': {'OS': 'Ceph', 'Description': 'Ceph OSD'},
'4FBD7E29-9D25-41B8-AFD0-5EC00CEFF05D': {'OS': 'Ceph', 'Description': 'Ceph dm-crypt OSD'},
'89C57F98-2FE5-4DC0-89C1-F3AD0CEFF2BE': {'OS': 'Ceph', 'Description': 'Ceph disk in creation'},
'89C57F98-2FE5-4DC0-89C1-5EC00CEFF2BE': {'OS': 'Ceph', 'Description': 'Ceph dm-crypt disk in creation'},
'824CC7A0-36A8-11E3-890A-952519AD3F61': {'OS': 'OpenBSD', 'Description': 'Data partition'},
'CEF5A9AD-73BC-4601-89F3-CDEEEEE321A1': {'OS': 'QNX', 'Description': 'Power-safe (QNX6) file system'},
'C91818F9-8025-47AF-89D2-F030D7000C2C': {'OS': 'Plan 9', 'Description': 'Plan 9 partition'},
'9D275380-40AD-11DB-BF97-000C2911D1B8': {'OS': 'VMware ESX', 'Description': 'vmkcore (coredump partition)'},
'AA31E02A-400F-11DB-9590-000C2911D1B8': {'OS': 'VMware ESX', 'Description': 'VMFS filesystem partition'},
'9198EFFC-31C0-11DB-8F78-000C2911D1B8': {'OS': 'VMware ESX', 'Description': 'VMware Reserved'},
'2568845D-2332-4675-BC39-8FA5A4748D15': {'OS': 'Android-IA', 'Description': 'Bootloader'},
'114EAFFE-1552-4022-B26E-9B053604CF84': {'OS': 'Android-IA', 'Description': 'Bootloader2'},
'49A4D17F-93A3-45C1-A0DE-F50B2EBE2599': {'OS': 'Android-IA', 'Description': 'Boot'},
'4177C722-9E92-4AAB-8644-43502BFD5506': {'OS': 'Android-IA', 'Description': 'Recovery'},
'EF32A33B-A409-486C-9141-9FFB711F6266': {'OS': 'Android-IA', 'Description': 'Misc'},
'20AC26BE-20B7-11E3-84C5-6CFDB94711E9': {'OS': 'Android-IA', 'Description': 'Metadata'},
'38F428E6-D326-425D-9140-6E0EA133647C': {'OS': 'Android-IA', 'Description': 'System'},
'A893EF21-E428-470A-9E55-0668FD91A2D9': {'OS': 'Android-IA', 'Description': 'Cache'},
'DC76DDA9-5AC1-491C-AF42-A82591580C0D': {'OS': 'Android-IA', 'Description': 'Data'},
'EBC597D0-2053-4B15-8B64-E0AAC75F4DB1': {'OS': 'Android-IA', 'Description': 'Persistent'},
'8F68CC74-C5E5-48DA-BE91-A0C8C15E9C80': {'OS': 'Android-IA', 'Description': 'Factory'},
'767941D0-2085-11E3-AD3B-6CFDB94711E9': {'OS': 'Android-IA', 'Description': 'Fastboot / Tertiary'},
'AC6D7924-EB71-4DF8-B48D-E267B27148FF': {'OS': 'Android-IA', 'Description': 'OEM'},
'7412F7D5-A156-4B13-81DC-867174929325': {'OS': 'ONIE', 'Description': 'Boot'},
'D4E6E2CD-4469-46F3-B5CB-1BFF57AFC149': {'OS': 'ONIE', 'Description': 'Config'},
'9E1A2D38-C612-4316-AA26-8B49521E5A8B': {'OS': 'PowerPC', 'Description': 'PReP boot'},
'BC13C2FF-59E6-4262-A352-B275FD6F7172': {'OS': 'Freedesktop', 'Description': 'Extended Boot Partition ($BOOT)'},
}
if __name__ == '__main__':
print("This file is not meant to be called directly.")
# vim: sts=2 sw=2 ts=2

View file

@ -8,10 +8,10 @@ os.chdir(os.path.dirname(os.path.realpath(__file__)))
sys.path.append(os.getcwd()) sys.path.append(os.getcwd())
from functions.activation import * from functions.activation import *
from functions.cleanup import * from functions.cleanup import *
from functions.diags import *
from functions.info import * from functions.info import *
from functions.product_keys import * from functions.product_keys import *
from functions.setup import * from functions.setup import *
from functions.sw_diags import *
init_global_vars() init_global_vars()
os.system('title {}: System Checklist Tool'.format(KIT_NAME_FULL)) os.system('title {}: System Checklist Tool'.format(KIT_NAME_FULL))
set_log_file('System Checklist.log') set_log_file('System Checklist.log')

View file

@ -7,10 +7,10 @@ import sys
os.chdir(os.path.dirname(os.path.realpath(__file__))) os.chdir(os.path.dirname(os.path.realpath(__file__)))
sys.path.append(os.getcwd()) sys.path.append(os.getcwd())
from functions.browsers import * from functions.browsers import *
from functions.diags import *
from functions.info import * from functions.info import *
from functions.product_keys import * from functions.product_keys import *
from functions.repairs import * from functions.repairs import *
from functions.sw_diags import *
init_global_vars() init_global_vars()
os.system('title {}: System Diagnostics Tool'.format(KIT_NAME_FULL)) os.system('title {}: System Diagnostics Tool'.format(KIT_NAME_FULL))
set_log_file('System Diagnostics.log') set_log_file('System Diagnostics.log')