* Bugfixes * Windows 10 v1703 / Redstone 2 / Creator's Update now recognized (attempt #2)
2811 lines
119 KiB
Python
2811 lines
119 KiB
Python
# Wizard Kit: Init
|
|
|
|
import os
|
|
import partition_uids
|
|
import psutil
|
|
import re
|
|
import shutil
|
|
import subprocess
|
|
import sys
|
|
import time
|
|
import traceback
|
|
import winreg
|
|
|
|
from operator import itemgetter
|
|
from subprocess import CalledProcessError
|
|
|
|
# STATIC VARIABLES
|
|
ARCHIVE_PASSWORD='Abracadabra'
|
|
COLORS = {
|
|
'CLEAR': '\033[0m',
|
|
'RED': '\033[31m',
|
|
'GREEN': '\033[32m',
|
|
'YELLOW': '\033[33m',
|
|
'BLUE': '\033[34m'
|
|
}
|
|
BACKUP_SERVERS = [
|
|
{ 'IP': '10.0.0.10',
|
|
'Name': 'ServerOne',
|
|
'Mounted': False,
|
|
'Share': 'Backups',
|
|
'User': 'restore',
|
|
'Pass': 'Abracadabra',
|
|
},
|
|
{ 'IP': '10.0.0.11',
|
|
'Name': 'ServerTwo',
|
|
'Mounted': False,
|
|
'Share': 'Backups',
|
|
'User': 'restore',
|
|
'Pass': 'Abracadabra',
|
|
},
|
|
]
|
|
CLIENT_INFO_SERVER = {
|
|
'IP': '10.0.0.10',
|
|
'RegEntry': r'0x10001,0xcc674aebbd889f5fd553564adcf3cab550791eca12542033d52134db893c95aabb6b318a4621d8116f6838d873edfe9db4509e1dfc9177ee7484808a62cbc42b913387f694fd67e81950f85198acf721c5767b54db7b864d69cce65e12c78c87d0fb4fc54996609c9b9274b1de7bae2f95000c9ca8d7e3f9b3f2cdb21cd578adf9ba98d10400a8203bb1a879a4cd2fad99baeb12738b9b4b99fec821f881acb62598a43c059f74af287bc8dceeb4821317aa44e2e0ee66d346927a654c702854a71a2eaed6a53f6be9360c7049974a2597a548361da42ac982ae55f993700a8b1fc9f3b4458314fbd41f239de0a29716cdcefbbb2c8d02b4c2effa4163cfeac9',
|
|
'Share': '/srv/ClientInfo',
|
|
'User': 'wkdiag',
|
|
}
|
|
OFFICE_SERVER = {
|
|
'IP': '10.0.0.10',
|
|
'Name': 'ServerOne',
|
|
'Mounted': False,
|
|
'Share': 'Office',
|
|
'User': 'restore', # Using these credentials in case the backup shares are also mounted.
|
|
'Pass': 'Abracadabra', # This is because Windows only allows one set of credentials to be used per server at a time.
|
|
}
|
|
WINDOWS_SERVER = {
|
|
'IP': '10.0.0.10',
|
|
'Name': 'ServerOne',
|
|
'Mounted': False,
|
|
'Share': 'Windows',
|
|
'User': 'restore', # Using these credentials in case the backup shares are also mounted.
|
|
'Pass': 'Abracadabra', # This is because Windows only allows one set of credentials to be used per server at a time.
|
|
}
|
|
SHELL_FOLDERS = {
|
|
#GUIDs from: https://msdn.microsoft.com/en-us/library/windows/desktop/dd378457(v=vs.85).aspx
|
|
'Desktop': ('{B4BFCC3A-DB2C-424C-B029-7FE99A87C641}'),
|
|
'Documents': ('Personal', '{FDD39AD0-238F-46AF-ADB4-6C85480369C7}'),
|
|
'Downloads': ('{374DE290-123F-4565-9164-39C4925E467B}'),
|
|
'Favorites': ('{1777F761-68AD-4D8A-87BD-30B759FA33DD}'),
|
|
'Music': ('My Music', '{4BD8D571-6D19-48D3-BE97-422220080E43}'),
|
|
'Pictures': ('My Pictures', '{33E28130-4E1E-4676-835A-98395C3BC3BB}'),
|
|
'Videos': ('My Video', '{18989B1D-99B5-455B-841C-AB7C74E4DDFC}'),
|
|
}
|
|
EXTRA_FOLDERS = [
|
|
'Dropbox',
|
|
'Google Drive',
|
|
'OneDrive',
|
|
'SkyDrive',
|
|
]
|
|
TOOLS = {
|
|
# NOTE: The brace variables will be expanded at runtime
|
|
'AIDA64': {
|
|
'32': '{BinDir}\\AIDA64\\aida64.exe'},
|
|
'AutoRuns': {
|
|
'32': '{BinDir}\\SysinternalsSuite\\autoruns.exe',
|
|
'64': '{BinDir}\\SysinternalsSuite\\autoruns64.exe'},
|
|
'BleachBit': {
|
|
'32': '{BinDir}\\BleachBit\\bleachbit_console.exe'},
|
|
'Caffeine': {
|
|
'32': '{BinDir}\\caffeine\\caffeine.exe'},
|
|
'curl': {
|
|
'32': '{BinDir}\\curl\\curl.exe'},
|
|
'Du': {
|
|
'32': '{BinDir}\\SysinternalsSuite\\du.exe',
|
|
'64': '{BinDir}\\SysinternalsSuite\\du64.exe'},
|
|
'ERUNT': {
|
|
'32': '{BinDir}\\erunt\\ERUNT.EXE'},
|
|
'Everything': {
|
|
'32': '{BinDir}\\Everything\\Everything.exe',
|
|
'64': '{BinDir}\\Everything\\Everything64.exe'},
|
|
'FastCopy': {
|
|
'32': '{BinDir}\\FastCopy\\FastCopy.exe',
|
|
'64': '{BinDir}\\FastCopy\\FastCopy64.exe'},
|
|
'HitmanPro': {
|
|
'32': '{BinDir}\\HitmanPro\\HitmanPro.exe',
|
|
'64': '{BinDir}\\HitmanPro\\HitmanPro64.exe'},
|
|
'HWiNFO': {
|
|
'32': '{BinDir}\\HWiNFO\\HWiNFO.exe',
|
|
'64': '{BinDir}\\HWiNFO\\HWiNFO64.exe'},
|
|
'KVRT': {
|
|
'32': '{BinDir}\\KVRT\\KVRT.exe'},
|
|
'NotepadPlusPlus': {
|
|
'32': '{BinDir}\\notepadplusplus\\notepadplusplus.exe'},
|
|
'ProduKey': {
|
|
'32': '{BinDir}\\ProduKey\\ProduKey.exe',
|
|
'64': '{BinDir}\\ProduKey\\ProduKey64.exe'},
|
|
'PuTTY-PSFTP': {
|
|
'32': '{BinDir}\\PuTTY\\PSFTP.EXE'},
|
|
'RKill': {
|
|
'32': '{BinDir}\\RKill\\RKill.exe'},
|
|
'SevenZip': {
|
|
'32': '{BinDir}\\7-Zip\\7za.exe',
|
|
'64': '{BinDir}\\7-Zip\\7za64.exe'},
|
|
'TDSSKiller': {
|
|
'32': '{BinDir}\\TDSSKiller\\TDSSKiller.exe'},
|
|
'wimlib-imagex': {
|
|
'32': '{BinDir}\\wimlib\\x32\\wimlib-imagex.exe',
|
|
'64': '{BinDir}\\wimlib\\x64\\wimlib-imagex.exe'},
|
|
'XMPlay': {
|
|
'32': '{BinDir}\\XMPlay\\xmplay.exe'},
|
|
}
|
|
# Browsers
|
|
DEFAULT_HOMEPAGE = 'https://www.google.com/'
|
|
REGEX_CHROMIUM_ITEMS = re.compile(r'^(Bookmarks|Cookies|Favicons|Google Profile|History|Login Data|Top Sites|TransportSecurity|Visited Links|Web Data).*', re.IGNORECASE)
|
|
REGEX_FIREFOX = re.compile(r'^(bookmarkbackups|(cookies|formhistory|places).sqlite|key3.db|logins.json|persdict.dat)$', re.IGNORECASE)
|
|
REGEX_OFFICE = re.compile(r'(Microsoft (Office\s+(365|Enterprise|Home|Pro(\s|fessional)|Single|Small|Standard|Starter|Ultimate|system)|Works[-\s\d]+\d)|(Libre|Open|Star)\s*Office|WordPerfect|Gnumeric|Abiword)', re.IGNORECASE)
|
|
# Registry
|
|
REGEX_REGISTRY_DIRS = re.compile(r'^(config$|RegBack$|System32$|Transfer|Win)', re.IGNORECASE)
|
|
REGEX_SOFTWARE_HIVE = re.compile(r'^Software$', re.IGNORECASE)
|
|
# Data 1
|
|
REGEX_EXCL_ITEMS = re.compile(r'^(\.(AppleDB|AppleDesktop|AppleDouble|com\.apple\.timemachine\.supported|dbfseventsd|DocumentRevisions-V100.*|DS_Store|fseventsd|PKInstallSandboxManager|Spotlight.*|SymAV.*|symSchedScanLockxz|TemporaryItems|Trash.*|vol|VolumeIcon\.icns)|desktop\.(ini|.*DB|.*DF)|(hiberfil|pagefile)\.sys|lost\+found|Network\.*Trash\.*Folder|Recycle[dr]|System\.*Volume\.*Information|Temporary\.*Items|Thumbs\.db)$', flags=re.IGNORECASE)
|
|
REGEX_EXCL_ROOT_ITEMS = re.compile(r'^\\?(boot(mgr|nxt)$|Config.msi|(eula|globdata|install|vc_?red)|.*.sys$|System Volume Information|RECYCLER?|\$Recycle\.bin|\$?Win(dows(.old.*|\.~BT|)$|RE_)|\$GetCurrent|PerfLogs|Program Files|.*\.(esd|swm|wim|dd|map|dmg|image)$|SYSTEM.SAV|Windows10Upgrade)', flags=re.IGNORECASE)
|
|
REGEX_INCL_ROOT_ITEMS = re.compile(r'^\\?(AdwCleaner|(My\s*|)(Doc(uments?( and Settings|)|s?)|Downloads|WK(-?Info|-?Transfer|)|Media|Music|Pic(ture|)s?|Vid(eo|)s?)|(ProgramData|Recovery|Temp.*|Users)$|.*\.(log|txt|rtf|qb\w*|avi|m4a|m4v|mp4|mkv|jpg|png|tiff?)$)', flags=re.IGNORECASE)
|
|
REGEX_WIM_FILE = re.compile(r'\.wim$', flags=re.IGNORECASE)
|
|
REGEX_WINDOWS_OLD = re.compile(r'^\\Win(dows|)\.old', flags=re.IGNORECASE)
|
|
FAST_COPY_ARGS = [
|
|
'/cmd=noexist_only',
|
|
'/utf8',
|
|
'/skip_empty_dir',
|
|
'/linkdest',
|
|
'/no_ui',
|
|
'/auto_close',
|
|
r'/exclude=\*.esd;\*.swm;\*.wim;\*.dd;\*.dd.tgz;\*.dd.txz;\*.map;\*.dmg;\*.image;$RECYCLE.BIN;$Recycle.Bin;.AppleDB;.AppleDesktop;.AppleDouble;.com.apple.timemachine.supported;.dbfseventsd;.DocumentRevisions-V100*;.DS_Store;.fseventsd;.PKInstallSandboxManager;.Spotlight*;.SymAV*;.symSchedScanLockxz;.TemporaryItems;.Trash*;.vol;.VolumeIcon.icns;desktop.ini;Desktop?DB;Desktop?DF;hiberfil.sys;lost+found;Network?Trash?Folder;pagefile.sys;Recycled;RECYCLER;System?Volume?Information;Temporary?Items;Thumbs.db']
|
|
VCR_REDISTS = [
|
|
{'Name': 'Visual C++ 2005 SP1 x32...', 'Cmd': ['msiexec', '/i', '2005sp1\\x86\\vcredist.msi', '/qb!', '/norestart']},
|
|
{'Name': 'Visual C++ 2005 SP1 x64...', 'Cmd': ['msiexec', '/i', '2005sp1\\x64\\vcredist.msi', '/qb!', '/norestart']},
|
|
{'Name': 'Visual C++ 2008 SP1 x32...', 'Cmd': ['2008sp1\\vcredist_x86.exe', '/qb! /norestart']},
|
|
{'Name': 'Visual C++ 2008 SP1 x64...', 'Cmd': ['2008sp1\\vcredist_x64.exe', '/qb! /norestart']},
|
|
{'Name': 'Visual C++ 2010 x32...', 'Cmd': ['2010\\vcredist_x86.exe', '/passive', '/norestart']},
|
|
{'Name': 'Visual C++ 2010 x64...', 'Cmd': ['2010\\vcredist_x64.exe', '/passive', '/norestart']},
|
|
{'Name': 'Visual C++ 2012 Update 4 x32...', 'Cmd': ['2012u4\\vcredist_x86.exe', '/passive', '/norestart']},
|
|
{'Name': 'Visual C++ 2012 Update 4 x64...', 'Cmd': ['2012u4\\vcredist_x64.exe', '/passive', '/norestart']},
|
|
{'Name': 'Visual C++ 2013 x32...', 'Cmd': ['2013\\vcredist_x86.exe', '/install', '/passive', '/norestart']},
|
|
{'Name': 'Visual C++ 2013 x64...', 'Cmd': ['2013\\vcredist_x64.exe', '/install', '/passive', '/norestart']},
|
|
{'Name': 'Visual C++ 2015 Update 3 x32...', 'Cmd': ['2015u3\\vc_redist.x86.exe', '/install', '/passive', '/norestart']},
|
|
{'Name': 'Visual C++ 2015 Update 3 x64...', 'Cmd': ['2015u3\\vc_redist.x64.exe', '/install', '/passive', '/norestart']}]
|
|
|
|
global_vars = {}
|
|
|
|
# Error Classes
|
|
class BIOSKeyNotFoundError(Exception):
|
|
pass
|
|
|
|
class BinNotFoundError(Exception):
|
|
pass
|
|
|
|
class GenericError(Exception):
|
|
pass
|
|
|
|
class GenericRepair(Exception):
|
|
pass
|
|
|
|
class NotInstalledError(Exception):
|
|
pass
|
|
|
|
class NoProfilesError(Exception):
|
|
pass
|
|
|
|
class UnsupportedOSError(Exception):
|
|
pass
|
|
|
|
# General functions
|
|
def ask(prompt='Kotaero!'):
|
|
"""Prompt the user with a Y/N question, log answer, and return a bool."""
|
|
answer = None
|
|
prompt = prompt + ' [Y/N]: '
|
|
while answer is None:
|
|
tmp = input(prompt)
|
|
if re.search(r'^y(es|)$', tmp, re.IGNORECASE):
|
|
answer = True
|
|
elif re.search(r'^n(o|ope|)$', tmp, re.IGNORECASE):
|
|
answer = False
|
|
_message = '{prompt}{answer_text}'.format(
|
|
prompt = prompt,
|
|
answer_text = 'Yes' if answer else 'No')
|
|
print_log(message=_message)
|
|
return answer
|
|
|
|
def convert_to_bytes(size):
|
|
"""Convert human-readable size str to bytes and return an int."""
|
|
size = str(size)
|
|
tmp = re.search(r'(\d+)\s+([KMGT]B)', size.upper())
|
|
if tmp:
|
|
size = int(tmp.group(1))
|
|
units = tmp.group(2)
|
|
if units == 'TB':
|
|
size *= 1099511627776
|
|
elif units == 'GB':
|
|
size *= 1073741824
|
|
elif units == 'MB':
|
|
size *= 1048576
|
|
elif units == 'KB':
|
|
size *= 1024
|
|
else:
|
|
return -1
|
|
|
|
return size
|
|
|
|
def exit_script():
|
|
# Remove dirs (if empty)
|
|
for dir in ['BackupDir', 'LogDir', 'TmpDir']:
|
|
try:
|
|
dir = global_vars[dir]
|
|
os.rmdir(dir)
|
|
except:
|
|
pass
|
|
|
|
# Open Log (if it exists)
|
|
_log = global_vars.get('LogFile', '')
|
|
if os.path.exists(_log):
|
|
try:
|
|
extract_item('NotepadPlusPlus', silent=True)
|
|
popen_program([global_vars['Tools']['NotepadPlusPlus'], global_vars['LogFile']])
|
|
except:
|
|
print_error('ERROR: Failed to extract Notepad++ and open log.')
|
|
|
|
# Kill Caffeine if still running
|
|
kill_process('caffeine.exe')
|
|
|
|
# Exit
|
|
sys.exit(0)
|
|
|
|
def extract_item(item=None, filter='', silent=False):
|
|
"""Extract item from .cbin into .bin."""
|
|
if item is None:
|
|
raise Exception
|
|
_cmd = [
|
|
global_vars['Tools']['SevenZip'], 'x', '-aos', '-bso0', '-bse0',
|
|
'-p{ArchivePassword}'.format(**global_vars),
|
|
'-o"{BinDir}\\{item}"'.format(item=item, **global_vars),
|
|
'"{CBinDir}\\{item}.7z"'.format(item=item, **global_vars),
|
|
filter]
|
|
if not silent:
|
|
print_standard('Extracting "{item}"...'.format(item=item))
|
|
try:
|
|
run_program(_cmd, shell=True)
|
|
except subprocess.CalledProcessError:
|
|
if not silent:
|
|
print_warning('WARNING: Errors encountered while exctracting data')
|
|
|
|
def get_ticket_number():
|
|
"""Get TicketNumber from user and save it in the info folder."""
|
|
global_vars['TicketNumber'] = None
|
|
while global_vars['TicketNumber'] is None:
|
|
_ticket = input('Enter ticket number: ')
|
|
if re.match(r'^([0-9]+([-_]?\w+|))$', _ticket):
|
|
global_vars['TicketNumber'] = _ticket
|
|
with open('{LogDir}\\TicketNumber'.format(**global_vars), 'w') as f:
|
|
f.write(_ticket)
|
|
|
|
def human_readable_size(size, decimals=0):
|
|
"""Convert size in bytes to a human-readable format and return a str."""
|
|
# Prep string formatting
|
|
width = 3+decimals
|
|
if decimals > 0:
|
|
width += 1
|
|
human_format = '>{width}.{decimals}f'.format(width=width, decimals=decimals)
|
|
tmp = ''
|
|
|
|
# Convert size to int
|
|
try:
|
|
size = int(size)
|
|
except ValueError:
|
|
size = convert_to_bytes(size)
|
|
|
|
# Verify we have a valid size
|
|
if size <= 0:
|
|
return '{size:>{width}} b'.format(size='???', width=width)
|
|
|
|
# Format string
|
|
if size >= 1099511627776:
|
|
size /= 1099511627776
|
|
tmp = '{size:{human_format}} Tb'.format(size=size, human_format=human_format)
|
|
elif size >= 1073741824:
|
|
size /= 1073741824
|
|
tmp = '{size:{human_format}} Gb'.format(size=size, human_format=human_format)
|
|
elif size >= 1048576:
|
|
size /= 1048576
|
|
tmp = '{size:{human_format}} Mb'.format(size=size, human_format=human_format)
|
|
elif size >= 1024:
|
|
size /= 1024
|
|
tmp = '{size:{human_format}} Kb'.format(size=size, human_format=human_format)
|
|
else:
|
|
tmp = '{size:{human_format}} b'.format(size=size, human_format=human_format)
|
|
|
|
# Return
|
|
return tmp
|
|
|
|
def kill_process(name=None):
|
|
"""Kill any running caffeine.exe processes."""
|
|
if name is None:
|
|
raise Exception
|
|
for proc in psutil.process_iter():
|
|
if proc.name() == name:
|
|
proc.kill()
|
|
|
|
def major_exception():
|
|
"""Display traceback and exit"""
|
|
print_error('Major exception')
|
|
print_warning(' Please let The Wizard know and he\'ll look into it (Please include the details below).')
|
|
print(traceback.format_exc())
|
|
print_log(traceback.format_exc())
|
|
sleep(30)
|
|
pause("Press Enter to exit...")
|
|
sys.exit(1)
|
|
|
|
def menu_select(title='~ Untitled Menu ~', main_entries=[], action_entries=[],
|
|
prompt='Please make a selection', secret_exit=False, disabled_label='DISABLED'):
|
|
"""Display options in a menu for user and return selected option as a str."""
|
|
# Bail early
|
|
if (len(main_entries) + len(action_entries) == 0):
|
|
raise Exception("MenuError: No items given")
|
|
|
|
# Build menu
|
|
menu_splash = '{title}\n\n'.format(title=title)
|
|
width = len(str(len(main_entries)))
|
|
valid_answers = []
|
|
if (secret_exit):
|
|
valid_answers.append('Q')
|
|
|
|
# Add main entries
|
|
if (len(main_entries) > 0):
|
|
for i in range(len(main_entries)):
|
|
entry = main_entries[i]
|
|
# Add Spacer
|
|
if ('CRLF' in entry):
|
|
menu_splash += '\n'
|
|
if entry.get('Disabled', False):
|
|
menu_splash += '{YELLOW}{number:>{width}}: {name} ({disabled}){CLEAR}\n'.format(
|
|
number = i+1,
|
|
disabled = disabled_label,
|
|
width = width,
|
|
name = entry.get('Display Name', entry['Name']),
|
|
**COLORS)
|
|
else:
|
|
valid_answers.append(str(i+1))
|
|
menu_splash += '{number:>{width}}: {name}\n'.format(
|
|
number = i+1,
|
|
width = width,
|
|
name = entry.get('Display Name', entry['Name']))
|
|
menu_splash += '\n'
|
|
|
|
# Add action entries
|
|
if (len(action_entries) > 0):
|
|
for entry in action_entries:
|
|
# Add Spacer
|
|
if ('CRLF' in entry):
|
|
menu_splash += '\n'
|
|
valid_answers.append(entry['Letter'])
|
|
menu_splash += '{letter:>{width}}: {name}\n'.format(
|
|
letter = entry['Letter'].upper(),
|
|
width = len(str(len(action_entries))),
|
|
name = entry['Name'])
|
|
menu_splash += '\n'
|
|
|
|
answer = ''
|
|
|
|
while (answer.upper() not in valid_answers):
|
|
os.system('cls')
|
|
print(menu_splash)
|
|
answer = input('{prompt}: '.format(prompt=prompt))
|
|
|
|
return answer.upper()
|
|
|
|
def non_clobber_rename(full_path):
|
|
"""Append suffix to path, if necessary, to avoid clobbering path"""
|
|
new_path = full_path
|
|
_i = 1;
|
|
while os.path.exists(new_path):
|
|
new_path = '{path}_{i}'.format(i=_i, path=full_path)
|
|
_i += 1
|
|
|
|
return new_path
|
|
|
|
def pause(prompt='Press Enter to continue... '):
|
|
"""Simple pause implementation."""
|
|
input(prompt)
|
|
|
|
def popen_program(cmd=None, pipe=False, minimized=False, shell=False):
|
|
"""Run program and return a subprocess.Popen object."""
|
|
if cmd is None:
|
|
raise Exception('No program passed.')
|
|
|
|
startupinfo=None
|
|
if minimized:
|
|
startupinfo = subprocess.STARTUPINFO()
|
|
startupinfo.dwFlags = subprocess.STARTF_USESHOWWINDOW
|
|
startupinfo.wShowWindow = 6
|
|
|
|
if pipe:
|
|
popen_obj = subprocess.Popen(cmd, shell=shell, startupinfo=None, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
|
else:
|
|
popen_obj = subprocess.Popen(cmd, shell=shell, startupinfo=None)
|
|
|
|
return popen_obj
|
|
|
|
def print_error(message='Generic error', end='\n', timestamp=True, **kwargs):
|
|
"""Prints message to screen in RED."""
|
|
print('{RED}{message}{CLEAR}'.format(message=message, **COLORS), end=end, **kwargs)
|
|
print_log(message, end, timestamp)
|
|
|
|
def print_info(message='Generic info', end='\n', timestamp=True, **kwargs):
|
|
"""Prints message to screen in BLUE."""
|
|
print('{BLUE}{message}{CLEAR}'.format(message=message, **COLORS), end=end, **kwargs)
|
|
print_log(message, end, timestamp)
|
|
|
|
def print_warning(message='Generic warning', end='\n', timestamp=True, **kwargs):
|
|
"""Prints message to screen in YELLOW."""
|
|
print('{YELLOW}{message}{CLEAR}'.format(message=message, **COLORS), end=end, **kwargs)
|
|
print_log(message, end, timestamp)
|
|
|
|
def print_standard(message='Generic info', end='\n', timestamp=True, **kwargs):
|
|
"""Prints message to screen."""
|
|
print('{message}'.format(message=message, **COLORS), end=end, **kwargs)
|
|
print_log(message, end, timestamp)
|
|
|
|
def print_success(message='Generic success', end='\n', timestamp=True, **kwargs):
|
|
"""Prints message to screen in GREEN."""
|
|
print('{GREEN}{message}{CLEAR}'.format(message=message, **COLORS), end=end, **kwargs)
|
|
print_log(message, end, timestamp)
|
|
|
|
def print_log(message='', end='\n', timestamp=True):
|
|
if 'LogFile' in global_vars and global_vars['LogFile'] is not None:
|
|
with open(global_vars['LogFile'], 'a') as f:
|
|
for line in message.splitlines():
|
|
f.write('{timestamp}{line}{end}'.format(
|
|
timestamp = time.strftime("%Y-%m-%d %H%M%z: ") if timestamp else '',
|
|
line = line,
|
|
end = end))
|
|
|
|
def run_program(cmd=None, args=[], check=True, pipe=True, shell=False):
|
|
"""Run program and return a subprocess.CompletedProcess object."""
|
|
if cmd is None:
|
|
raise Exception('No program passed.')
|
|
|
|
_cmd = cmd
|
|
if len(args) > 0:
|
|
# BAD Need to refactor all calls to run_program to only use cmd=X
|
|
## That way the cmd var is set the same as the real run() and Popen() calls
|
|
_cmd = [cmd] + args
|
|
if shell:
|
|
_cmd = ' '.join(_cmd)
|
|
|
|
if pipe:
|
|
process_return = subprocess.run(_cmd, check=check, shell=shell, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
|
else:
|
|
process_return = subprocess.run(_cmd, check=check, shell=shell)
|
|
|
|
return process_return
|
|
|
|
def show_info(message='~Some message~', info='~Some info~', indent=8, width=32):
|
|
print_standard('{indent}{message:<{width}}{info}'.format(indent=' '*indent, width=width, message=message, info=info))
|
|
|
|
def sleep(seconds=2):
|
|
time.sleep(seconds)
|
|
|
|
def stay_awake():
|
|
"""Prevent the system from sleeping or hibernating."""
|
|
# Bail if caffeine is already running
|
|
for proc in psutil.process_iter():
|
|
if proc.name() == 'caffeine.exe':
|
|
return
|
|
# Extract and run
|
|
extract_item('caffeine', silent=True)
|
|
try:
|
|
popen_program(global_vars['Tools']['Caffeine'])
|
|
except:
|
|
print_error('ERROR: No caffeine available; please set the power setting to High Performace.')
|
|
|
|
def try_and_print(function=None, message='Trying...', cs='CS', ns='NS', other_results={},
|
|
catch_all=True, indent=8, width=32, print_return=False, silent_function=True, *args, **kwargs):
|
|
"""Run function, print if successful or not, and return dict.
|
|
|
|
other_results is in the form of {'Warning': {'ExceptionClassName': 'Result Message'}, 'Error': {'ExceptionClassName': 'Result Message'}}
|
|
The the ExceptionClassNames will be additionally excepted conditions and the result string will be printed in the correct color.
|
|
catch_all=False will result in unspecified exceptions being re-raised."""
|
|
if function is None:
|
|
raise Exception
|
|
err = ''
|
|
wrn_exceptions = other_results.get('Warning', {}).keys()
|
|
wrn_exceptions = tuple(getattr(sys.modules[__name__], e) for e in wrn_exceptions)
|
|
err_exceptions = other_results.get('Error', {}).keys()
|
|
err_exceptions = tuple(getattr(sys.modules[__name__], e) for e in err_exceptions)
|
|
wrn_results = other_results.get('Warning', {})
|
|
err_results = other_results.get('Error', {})
|
|
|
|
# Run function and catch errors
|
|
print_standard('{indent}{message:<{width}}'.format(indent=' '*indent, message=message, width=width), end='', flush=True)
|
|
try:
|
|
out = function(*args, **kwargs)
|
|
if print_return:
|
|
print_standard(out[0], timestamp=False)
|
|
for item in out[1:]:
|
|
print_standard('{indent}{item}'.format(indent=' '*(indent+width), item=item))
|
|
elif silent_function:
|
|
print_success(cs, timestamp=False)
|
|
except wrn_exceptions as e:
|
|
_result = wrn_results.get(e.__class__.__name__, 'Warning')
|
|
print_warning(_result, timestamp=False)
|
|
err = e
|
|
except err_exceptions as e:
|
|
_result = err_results.get(e.__class__.__name__, 'Error')
|
|
print_error(_result, timestamp=False)
|
|
err = e
|
|
except:
|
|
print_error(ns, timestamp=False)
|
|
err = traceback.format_exc()
|
|
|
|
# Return or raise?
|
|
if bool(err) and not catch_all:
|
|
raise
|
|
else:
|
|
return {'CS': not bool(err), 'Error': err}
|
|
|
|
def upload_data(path=None, file=None):
|
|
"""Add CLIENT_INFO_SERVER to authorized connections and upload file."""
|
|
extract_item('PuTTY', filter='WK.ppk psftp.exe', silent=True)
|
|
|
|
# Authorize connection to the server
|
|
winreg.CreateKey(winreg.HKEY_CURRENT_USER, r'Software\SimonTatham\PuTTY\SshHostKeys')
|
|
with winreg.OpenKey(winreg.HKEY_CURRENT_USER, r'Software\SimonTatham\PuTTY\SshHostKeys', access=winreg.KEY_WRITE) as _key:
|
|
winreg.SetValueEx(_key, 'rsa2@22:{IP}'.format(**CLIENT_INFO_SERVER), 0, winreg.REG_SZ, CLIENT_INFO_SERVER['RegEntry'])
|
|
|
|
# Write batch file
|
|
with open('{TmpDir}\\psftp.batch'.format(**global_vars), 'w', encoding='ascii') as f:
|
|
f.write('lcd "{path}"\n'.format(path=path))
|
|
f.write('cd "{Share}"\n'.format(**CLIENT_INFO_SERVER))
|
|
f.write('mkdir {TicketNumber}\n'.format(**global_vars))
|
|
f.write('cd {TicketNumber}\n'.format(**global_vars))
|
|
f.write('put "{file}"\n'.format(file=file))
|
|
|
|
# Upload Info
|
|
_cmd = [
|
|
global_vars['Tools']['PuTTY-PSFTP'],
|
|
'-noagent',
|
|
'-i', '{BinDir}\\PuTTY\\WK.ppk'.format(**global_vars),
|
|
'{User}@{IP}'.format(**CLIENT_INFO_SERVER),
|
|
'-b', '{TmpDir}\\psftp.batch'.format(**global_vars)]
|
|
run_program(_cmd)
|
|
|
|
def wait_for_process(name=None):
|
|
"""Wait for process by name."""
|
|
if name is None:
|
|
raise Exception
|
|
_still_running = True
|
|
while _still_running:
|
|
sleep(1)
|
|
_still_running = False
|
|
for proc in psutil.process_iter():
|
|
if re.search(r'^{name}'.format(name=name), proc.name(), re.IGNORECASE):
|
|
_still_running = True
|
|
sleep(1)
|
|
|
|
# global_vars functions
|
|
def init_global_vars():
|
|
"""Sets global variables based on system info."""
|
|
print_info('Initializing')
|
|
try:
|
|
try_and_print(message='Checking .bin...', function=find_bin, catch_all=False, cs='Done', ns='Error')
|
|
try_and_print(message='Checking environment...', function=set_common_vars, catch_all=False, cs='Done', ns='Error')
|
|
try_and_print(message='Checking OS...', function=check_os, catch_all=False, cs='Done', ns='Error')
|
|
try_and_print(message='Checking tools...', function=check_tools, catch_all=False, cs='Done', ns='Error')
|
|
try_and_print(message='Creating folders...', function=make_tmp_dirs, catch_all=False, cs='Done', ns='Error')
|
|
try_and_print(message='Clearing collisions...', function=clean_env_vars, catch_all=False, cs='Done', ns='Error')
|
|
except:
|
|
major_exception()
|
|
|
|
def check_os():
|
|
_vars_os = {}
|
|
# Query registry
|
|
_reg_path = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, 'SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion')
|
|
for key in ['CSDVersion', 'CurrentBuild', 'CurrentBuildNumber', 'CurrentVersion', 'ProductName']:
|
|
try:
|
|
_vars_os[key] = winreg.QueryValueEx(_reg_path, key)[0]
|
|
if key in ['CurrentBuild', 'CurrentBuildNumber']:
|
|
_vars_os[key] = int(_vars_os[key])
|
|
except ValueError:
|
|
# Couldn't convert Build to int so this should return interesting results...
|
|
_vars_os[key] = 0
|
|
except:
|
|
_vars_os[key] = 'Unknown'
|
|
|
|
# Determine OS bit depth
|
|
_vars_os['Arch'] = 32
|
|
if 'PROGRAMFILES(X86)' in global_vars['Env']:
|
|
_vars_os['Arch'] = 64
|
|
|
|
# Determine OS Name
|
|
_vars_os['Name'] = '{ProductName} {CSDVersion}'.format(**_vars_os)
|
|
if _vars_os['CurrentBuild'] == 9600:
|
|
_vars_os['Name'] += ' Update'
|
|
if _vars_os['CurrentBuild'] == 10240:
|
|
_vars_os['Name'] += ' Release 1507 "Threshold 1"'
|
|
if _vars_os['CurrentBuild'] == 10586:
|
|
_vars_os['Name'] += ' Release 1511 "Threshold 2"'
|
|
if _vars_os['CurrentBuild'] == 14393:
|
|
_vars_os['Name'] += ' Release 1607 "Redstone 1" / "Anniversary Update"'
|
|
if _vars_os['CurrentBuild'] == 15063:
|
|
_vars_os['Name'] += ' Release 1703 "Redstone 1" / "Creators Update"'
|
|
_vars_os['Name'] = _vars_os['Name'].replace('Service Pack ', 'SP')
|
|
_vars_os['Name'] = _vars_os['Name'].replace('Unknown Release', 'Release')
|
|
_vars_os['Name'] = re.sub(r'\s+', ' ', _vars_os['Name'])
|
|
# == vista ==
|
|
# 6.0.6000
|
|
# 6.0.6001
|
|
# 6.0.6002
|
|
# ==== 7 ====
|
|
# 6.1.7600
|
|
# 6.1.7601
|
|
# 6.1.7602
|
|
# ==== 8 ====
|
|
# 6.2.9200
|
|
# === 8.1 ===
|
|
# 6.3.9200
|
|
# === 8.1u ==
|
|
# 6.3.9600
|
|
# === 10 v1507 "Threshold 1" ==
|
|
# 6.3.10240
|
|
# === 10 v1511 "Threshold 2" ==
|
|
# 6.3.10586
|
|
# === 10 v1607 "Redstone 1" "Anniversary Update" ==
|
|
# 6.3.14393
|
|
# === 10 v1703 "Redstone 2" "Creators Update" ==
|
|
# 6.3.15063
|
|
# === 10 v???? "Redstone 3" "Fall Creators Update" ==
|
|
# 6.3.?????
|
|
|
|
# Determine OS version
|
|
_os_name = '{Name} x{Arch}'.format(**_vars_os)
|
|
if _vars_os['CurrentVersion'] == '6.0':
|
|
_vars_os['Version'] = 'Vista'
|
|
_os_name = _os_name + ' (very outdated)'
|
|
elif _vars_os['CurrentVersion'] == '6.1':
|
|
_vars_os['Version'] = '7'
|
|
if _vars_os['CSDVersion'] == 'Service Pack 1':
|
|
_os_name = _os_name + ' (outdated)'
|
|
else:
|
|
_os_name = _os_name + ' (very outdated)'
|
|
elif _vars_os['CurrentVersion'] == '6.2':
|
|
_vars_os['Version'] = '8'
|
|
_os_name = _os_name + ' (very outdated)'
|
|
elif _vars_os['CurrentVersion'] == '6.3':
|
|
if int(_vars_os['CurrentBuildNumber']) <= 9600:
|
|
_vars_os['Version'] = '8'
|
|
elif int(_vars_os['CurrentBuildNumber']) >= 10240:
|
|
_vars_os['Version'] = '10'
|
|
if _vars_os['CurrentBuild'] == 9200:
|
|
_os_name = _os_name + ' (very outdated)'
|
|
elif _vars_os['CurrentBuild'] == 9600:
|
|
_os_name = _os_name + ' (outdated)'
|
|
elif _vars_os['CurrentBuild'] == 10240:
|
|
_os_name = _os_name + ' (very outdated)'
|
|
elif _vars_os['CurrentBuild'] == 10586:
|
|
_os_name = _os_name + ' (outdated)'
|
|
elif _vars_os['CurrentBuild'] == 14393:
|
|
_os_name = _os_name + ' (outdated)'
|
|
elif _vars_os['CurrentBuild'] == 15063:
|
|
pass # Current Win10
|
|
else:
|
|
_os_name = _os_name + ' (unrecognized)'
|
|
_vars_os['DisplayName'] = _os_name
|
|
|
|
# Determine bootup type
|
|
_vars_os['SafeMode'] = False
|
|
if 'SAFEBOOT_OPTION' in global_vars['Env']:
|
|
_vars_os['SafeMode'] = True
|
|
|
|
# Ignore activation status if in Safe Mode
|
|
if _vars_os['SafeMode']:
|
|
_vars_os['Activation'] = 'Activation status unavailable in safe mode'
|
|
else:
|
|
_vars_os['Activation'] = 'Unknown'
|
|
|
|
global_vars['OS'] = _vars_os
|
|
|
|
# Update activation status
|
|
update_windows_activation_status()
|
|
|
|
def check_tools():
|
|
# Add tools to dict
|
|
if global_vars['OS'].get('Arch', 32) == 64:
|
|
global_vars['Tools'] = {k: v.get('64', v.get('32')) for (k, v) in TOOLS.items()}
|
|
else:
|
|
global_vars['Tools'] = {k: v.get('32') for (k, v) in TOOLS.items()}
|
|
|
|
# Fix paths
|
|
global_vars['Tools'] = {k: v.format(**global_vars) for (k, v) in global_vars['Tools'].items()}
|
|
|
|
def clean_env_vars():
|
|
# This fixes an issue where both global_vars and global_vars['Env'] are expanded at the same time
|
|
for key in global_vars.keys():
|
|
global_vars['Env'].pop(key, None)
|
|
|
|
def find_bin():
|
|
_wd = os.getcwd()
|
|
_base = None
|
|
while _base is None:
|
|
if os.path.exists('.bin'):
|
|
_base = os.getcwd()
|
|
break
|
|
if re.fullmatch(r'\w:\\', os.getcwd()):
|
|
break
|
|
os.chdir('..')
|
|
os.chdir(_wd)
|
|
if _base is None:
|
|
raise BinNotFoundError
|
|
global_vars['BaseDir'] = _base
|
|
|
|
def make_tmp_dirs():
|
|
os.makedirs(global_vars['BackupDir'], exist_ok=True)
|
|
os.makedirs(global_vars['LogDir'], exist_ok=True)
|
|
os.makedirs(global_vars['TmpDir'], exist_ok=True)
|
|
|
|
def set_common_vars():
|
|
global_vars['Date'] = time.strftime("%Y-%m-%d")
|
|
global_vars['Date-Time'] = time.strftime("%Y-%m-%d_%H%M_%z")
|
|
global_vars['Env'] = os.environ.copy()
|
|
|
|
global_vars['ArchivePassword'] = ARCHIVE_PASSWORD
|
|
global_vars['BinDir'] = '{BaseDir}\\.bin'.format(**global_vars)
|
|
global_vars['CBinDir'] = '{BaseDir}\\.cbin'.format(**global_vars)
|
|
global_vars['ClientDir'] = '{SYSTEMDRIVE}\\WK'.format(**global_vars['Env'])
|
|
global_vars['BackupDir'] = '{ClientDir}\\Backups\\{Date}'.format(**global_vars)
|
|
global_vars['LogDir'] = '{ClientDir}\\Info\\{Date}'.format(**global_vars)
|
|
global_vars['QuarantineDir'] = '{ClientDir}\\Quarantine'.format(**global_vars)
|
|
global_vars['TmpDir'] = '{BinDir}\\tmp'.format(**global_vars)
|
|
|
|
# Browsers
|
|
def backup_browsers():
|
|
functions = [
|
|
backup_chromium,
|
|
backup_chrome,
|
|
backup_chrome_canary,
|
|
backup_firefox,
|
|
backup_internet_explorer,
|
|
backup_opera,
|
|
backup_opera_beta,
|
|
backup_opera_dev]
|
|
errors = False
|
|
for function in functions:
|
|
try:
|
|
function()
|
|
except NoProfilesError:
|
|
pass
|
|
except:
|
|
errors = True
|
|
if errors:
|
|
raise GenericError
|
|
|
|
def backup_chromium():
|
|
"""Create backup of Chromium in the BackupDir."""
|
|
if os.path.exists('{LOCALAPPDATA}\\Chromium\\User Data'.format(**global_vars['Env'])):
|
|
cmd = [
|
|
global_vars['Tools']['SevenZip'], 'a', '-aoa', '-bso0', '-bse0', '-mx=1',
|
|
'{BackupDir}\\Browsers ({USERNAME})\\Chromium.7z'.format(**global_vars, **global_vars['Env']),
|
|
'{LOCALAPPDATA}\\Chromium\\User Data'.format(**global_vars['Env'])]
|
|
run_program(cmd, check=False)
|
|
else:
|
|
raise NoProfilesError
|
|
|
|
def backup_chrome():
|
|
"""Create backup of Google Chrome in the BackupDir."""
|
|
if os.path.exists('{LOCALAPPDATA}\\Google\\Chrome\\User Data'.format(**global_vars['Env'])):
|
|
cmd = [
|
|
global_vars['Tools']['SevenZip'], 'a', '-aoa', '-bso0', '-bse0', '-mx=1',
|
|
'{BackupDir}\\Browsers ({USERNAME})\\Google Chrome.7z'.format(**global_vars, **global_vars['Env']),
|
|
'{LOCALAPPDATA}\\Google\\Chrome\\User Data'.format(**global_vars['Env'])]
|
|
run_program(cmd, check=False)
|
|
else:
|
|
raise NoProfilesError
|
|
|
|
def backup_chrome_canary():
|
|
"""Create backup of Google Chrome Canary in the BackupDir."""
|
|
if os.path.exists('{LOCALAPPDATA}\\Google\\Chrome SxS\\User Data'.format(**global_vars['Env'])):
|
|
cmd = [
|
|
global_vars['Tools']['SevenZip'], 'a', '-aoa', '-bso0', '-bse0', '-mx=1',
|
|
'{BackupDir}\\Browsers ({USERNAME})\\Google Chrome Canary.7z'.format(**global_vars, **global_vars['Env']),
|
|
'{LOCALAPPDATA}\\Google\\Chrome SxS\\User Data'.format(**global_vars['Env'])]
|
|
run_program(cmd, check=False)
|
|
else:
|
|
raise NoProfilesError
|
|
|
|
def backup_internet_explorer():
|
|
"""Create backup of Internet Explorer in the BackupDir."""
|
|
run_program('reg export "hkcu\\Software\\Microsoft\\Internet Explorer" "{TmpDir}\\Internet Explorer (HKCU).reg" /y'.format(**global_vars), check=False)
|
|
run_program('reg export "hklm\\Software\\Microsoft\\Internet Explorer" "{TmpDir}\\Internet Explorer (HKLM).reg" /y'.format(**global_vars), check=False)
|
|
cmd = [
|
|
global_vars['Tools']['SevenZip'], 'a', '-aoa', '-bso0', '-bse0', '-mx=1',
|
|
'{BackupDir}\\Browsers ({USERNAME})\\Internet Explorer.7z'.format(**global_vars, **global_vars['Env']),
|
|
'{TmpDir}\\Internet*.reg'.format(**global_vars),
|
|
'{USERPROFILE}\\Favorites'.format(**global_vars['Env'])]
|
|
run_program(cmd, check=False)
|
|
|
|
def backup_firefox():
|
|
"""Create backup of Mozilla Firefox in the BackupDir."""
|
|
if os.path.exists('{APPDATA}\\Mozilla\\Firefox'.format(**global_vars['Env'])):
|
|
cmd = [
|
|
global_vars['Tools']['SevenZip'], 'a', '-aoa', '-bso0', '-bse0', '-mx=1',
|
|
'{BackupDir}\\Browsers ({USERNAME})\\Mozilla Firefox.7z'.format(**global_vars, **global_vars['Env']),
|
|
'{APPDATA}\\Mozilla\\Firefox\\Profile*'.format(**global_vars['Env'])]
|
|
run_program(cmd, check=False)
|
|
else:
|
|
raise NoProfilesError
|
|
|
|
def backup_opera():
|
|
"""Create backup of Opera Chromium in the BackupDir."""
|
|
if os.path.exists('{APPDATA}\\Opera Software\\Opera Stable'.format(**global_vars['Env'])):
|
|
cmd = [
|
|
global_vars['Tools']['SevenZip'], 'a', '-aoa', '-bso0', '-bse0', '-mx=1',
|
|
'{BackupDir}\\Browsers ({USERNAME})\\Opera.7z'.format(**global_vars, **global_vars['Env']),
|
|
'{APPDATA}\\Opera Software\\Opera Stable'.format(**global_vars['Env'])]
|
|
run_program(cmd, check=False)
|
|
else:
|
|
raise NoProfilesError
|
|
|
|
def backup_opera_beta():
|
|
"""Create backup of Opera Chromium Beta in the BackupDir."""
|
|
if os.path.exists('{APPDATA}\\Opera Software\\Opera Next'.format(**global_vars['Env'])):
|
|
cmd = [
|
|
global_vars['Tools']['SevenZip'], 'a', '-aoa', '-bso0', '-bse0', '-mx=1',
|
|
'{BackupDir}\\Browsers ({USERNAME})\\Opera Beta.7z'.format(**global_vars, **global_vars['Env']),
|
|
'{APPDATA}\\Opera Software\\Opera Next'.format(**global_vars['Env'])]
|
|
run_program(cmd, check=False)
|
|
else:
|
|
raise NoProfilesError
|
|
|
|
def backup_opera_dev():
|
|
"""Create backup of Opera Chromium Developer in the BackupDir."""
|
|
if os.path.exists('{APPDATA}\\Opera Software\\Opera Developer'.format(**global_vars['Env'])):
|
|
cmd = [
|
|
global_vars['Tools']['SevenZip'], 'a', '-aoa', '-bso0', '-bse0', '-mx=1',
|
|
'{BackupDir}\\Browsers ({USERNAME})\\Opera Dev.7z'.format(**global_vars, **global_vars['Env']),
|
|
'{APPDATA}\\Opera Software\\Opera Developer'.format(**global_vars['Env'])]
|
|
run_program(cmd, check=False)
|
|
else:
|
|
raise NoProfilesError
|
|
|
|
def clean_chromium_profile(profile):
|
|
"""Renames profile folder as backup and then recreates the folder with only the essential files."""
|
|
if profile is None:
|
|
raise Exception
|
|
# print_info(' Resetting profile: {name}'.format(name=profile.name))
|
|
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, '{path}\\{name}'.format(path=profile.path, name=entry.name))
|
|
|
|
def clean_internet_explorer():
|
|
"""Uses the built-in function to reset IE and sets the homepage."""
|
|
kill_process('iexplore.exe')
|
|
run_program('rundll32.exe', ['inetcpl.cpl,ResetIEtoDefaults'], check=False)
|
|
key = r'Software\Microsoft\Internet Explorer\Main'
|
|
|
|
# Set homepage
|
|
with winreg.OpenKey(winreg.HKEY_CURRENT_USER, 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_firefox_profile(profile):
|
|
"""Renames profile folder as backup and then recreates the folder with only the essential files."""
|
|
if profile is None:
|
|
raise Exception
|
|
# print_info(' Resetting profile: {name}'.format(name=profile.name))
|
|
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
|
|
for entry in os.scandir(backup_path):
|
|
if REGEX_FIREFOX.search(entry.name):
|
|
if entry.is_dir():
|
|
shutil.copytree(entry.path, '{path}\\{name}'.format(path=profile.path, name=entry.name))
|
|
else:
|
|
shutil.copy(entry.path, '{path}\\{name}'.format(path=profile.path, name=entry.name))
|
|
|
|
# Set profile defaults
|
|
with open('{path}\\prefs.js'.format(path=profile.path), 'a', encoding='ascii') as f:
|
|
f.write('user_pref("browser.search.geoSpecificDefaults", false);\n')
|
|
|
|
# Set search to Google
|
|
f.write('user_pref("browser.search.defaultenginename", "Google");\n')
|
|
f.write('user_pref("browser.search.defaultenginename.US", "Google");\n')
|
|
|
|
# Set homepage
|
|
f.write('user_pref("browser.startup.homepage", "{homepage}");\n'.format(homepage=DEFAULT_HOMEPAGE))
|
|
|
|
def config_internet_explorer():
|
|
ie_exe = get_iexplorer_exe()
|
|
run_program(ie_exe, ['https://www.microsoft.com/en-us/iegallery'], check=False)
|
|
|
|
def config_google_chrome():
|
|
chrome_exe = get_chrome_exe()
|
|
if chrome_exe is None:
|
|
raise NotInstalledError
|
|
|
|
# Check for system exensions
|
|
_ublock_origin = None
|
|
_ublock_extra = None
|
|
try:
|
|
_ublock_origin = winreg.QueryValue(winreg.HKEY_LOCAL_MACHINE, r'Software\Wow6432Node\Google\Chrome\Extensions\cjpalhdlnbpafiamejdnhcphjbkeiagm')
|
|
except FileNotFoundError:
|
|
pass
|
|
try:
|
|
_ublock_extra = winreg.QueryValue(winreg.HKEY_LOCAL_MACHINE, r'Software\Wow6432Node\Google\Chrome\Extensions\pgdnlhfefecpicbbihgmbmffkjpaplco')
|
|
except FileNotFoundError:
|
|
pass
|
|
|
|
# Open Chrome
|
|
_args = [
|
|
'https://chrome.google.com/webstore/detail/ublock-origin/cjpalhdlnbpafiamejdnhcphjbkeiagm?hl=en',
|
|
'https://chrome.google.com/webstore/detail/ublock-origin-extra/pgdnlhfefecpicbbihgmbmffkjpaplco?hl=en']
|
|
if _ublock_origin is None and _ublock_extra is None:
|
|
run_program(chrome_exe, _args, check=False)
|
|
elif _ublock_origin is None:
|
|
run_program(chrome_exe, [_args[0]], check=False)
|
|
elif _ublock_extra is None:
|
|
run_program(chrome_exe, [_args[1]], check=False)
|
|
else:
|
|
run_program(chrome_exe, ['chrome://extensions'], check=False)
|
|
|
|
def config_google_chrome_canary():
|
|
chrome_canary_exe = get_chrome_canary_exe()
|
|
if chrome_canary_exe is None:
|
|
raise NotInstalledError
|
|
_args = [
|
|
'https://chrome.google.com/webstore/detail/ublock-origin/cjpalhdlnbpafiamejdnhcphjbkeiagm?hl=en',
|
|
'https://chrome.google.com/webstore/detail/ublock-origin-extra/pgdnlhfefecpicbbihgmbmffkjpaplco?hl=en']
|
|
run_program(chrome_canary_exe, _args, check=False)
|
|
|
|
def config_mozilla_firefox():
|
|
firefox_exe = get_firefox_exe()
|
|
if firefox_exe is None:
|
|
raise NotInstalledError
|
|
|
|
# Check for system extension(s)
|
|
_ublock_origin = '{PROGRAMFILES}\\Mozilla Firefox\\distribution\\extensions\\uBlock0@raymondhill.net'.format(**global_vars['Env'])
|
|
if 'PROGRAMFILES(X86)' in global_vars['Env']:
|
|
_ublock_origin = '{PROGRAMFILES(X86)}\\Mozilla Firefox\\distribution\\extensions\\uBlock0@raymondhill.net'.format(**global_vars['Env'])
|
|
|
|
# Open Firefox
|
|
if os.path.exists(_ublock_origin):
|
|
run_program(firefox_exe, ['about:addons'], check=False)
|
|
else:
|
|
run_program(firefox_exe, ['https://addons.mozilla.org/en-us/firefox/addon/ublock-origin/'], check=False)
|
|
|
|
def config_mozilla_firefox_dev():
|
|
firefox_dev_exe = get_firefox_dev_exe()
|
|
if firefox_dev_exe is None:
|
|
raise NotInstalledError
|
|
run_program(firefox_dev_exe, ['https://addons.mozilla.org/en-us/firefox/addon/ublock-origin/'], check=False)
|
|
|
|
def config_opera():
|
|
opera_exe = get_opera_exe()
|
|
if opera_exe is None:
|
|
raise NotInstalledError
|
|
run_program(opera_exe, ['https://addons.opera.com/en/extensions/details/ublock/?display=en'], check=False)
|
|
|
|
def config_opera_beta():
|
|
opera_beta_exe = get_opera_beta_exe()
|
|
if opera_beta_exe is None:
|
|
raise NotInstalledError
|
|
run_program(opera_beta_exe, ['https://addons.opera.com/en/extensions/details/ublock/?display=en'], check=False)
|
|
|
|
def config_opera_dev():
|
|
opera_dev_exe = get_opera_dev_exe()
|
|
if opera_dev_exe is None:
|
|
raise NotInstalledError
|
|
run_program(opera_dev_exe, ['https://addons.opera.com/en/extensions/details/ublock/?display=en'], check=False)
|
|
|
|
def create_firefox_default_profiles():
|
|
"""Create new default profile for Mozilla Firefox for both stable and dev releases."""
|
|
firefox_exe = get_firefox_exe()
|
|
firefox_dev_exe = get_firefox_dev_exe()
|
|
profiles_ini_path = '{APPDATA}\\Mozilla\\Firefox\\profiles.ini'.format(**global_vars['Env'])
|
|
|
|
# Rename profiles.ini
|
|
if os.path.exists(profiles_ini_path):
|
|
backup_path = '{path}_{Date}.bak'.format(path=profiles_ini_path, **global_vars)
|
|
backup_path = non_clobber_rename(backup_path)
|
|
shutil.move(profiles_ini_path, backup_path)
|
|
|
|
# Create profile(s)
|
|
if firefox_exe is not None:
|
|
run_program(firefox_exe, ['-createprofile', 'default'], check=False)
|
|
if firefox_dev_exe is not None:
|
|
run_program(firefox_dev_exe, ['-createprofile'], check=False)
|
|
|
|
def get_chrome_exe():
|
|
"""Check for conflicting Chrome installations and return chrome.exe path as str."""
|
|
install_multi = '{PROGRAMFILES}\\Google\\Chrome\\Application\\chrome.exe'.format(**global_vars['Env'])
|
|
if 'PROGRAMFILES(X86)' in global_vars['Env']:
|
|
install_multi = '{PROGRAMFILES(X86)}\\Google\\Chrome\\Application\\chrome.exe'.format(**global_vars['Env'])
|
|
install_single = '{LOCALAPPDATA}\\Google\\Chrome\\Application\\chrome.exe'.format(**global_vars['Env'])
|
|
if os.path.exists(install_multi):
|
|
if os.path.exists(install_single):
|
|
print_log(' WARNING: Single-user and multi-user installations present.')
|
|
print_log(' It is recommended to move to only having the multi-user installation.')
|
|
return install_multi
|
|
elif os.path.exists(install_single):
|
|
return install_single
|
|
else:
|
|
return None
|
|
|
|
def get_chrome_profiles():
|
|
"""Find any existing Chrome profiles and return as a list of os.DirEntry objects."""
|
|
profiles = []
|
|
try:
|
|
for entry in os.scandir('{LOCALAPPDATA}\\Google\\Chrome\\User Data'.format(**global_vars['Env'])):
|
|
if entry.is_dir() and re.search(r'^(Default|Profile)', entry.name, re.IGNORECASE):
|
|
profiles.append(entry)
|
|
profiles = [p for p in profiles if not re.search(r'\.(wk|)bak.*', p.name, re.IGNORECASE)]
|
|
except:
|
|
pass
|
|
|
|
return profiles
|
|
|
|
def get_chrome_canary_exe():
|
|
"""Check for Google Chrome Canary installation and return chrome.exe path as str."""
|
|
prog_exe = '{LOCALAPPDATA}\\Google\\Chrome SxS\\Application\\chrome.exe'.format(**global_vars['Env'])
|
|
if os.path.exists(prog_exe):
|
|
return prog_exe
|
|
else:
|
|
return None
|
|
|
|
def get_chrome_canary_profiles():
|
|
"""Find any existing Chrome profiles and return as a list of os.DirEntry objects."""
|
|
profiles = []
|
|
try:
|
|
for entry in os.scandir('{LOCALAPPDATA}\\Google\\Chrome SxS\\User Data'.format(**global_vars['Env'])):
|
|
if entry.is_dir() and re.search(r'^(Default|Profile)', entry.name, re.IGNORECASE):
|
|
profiles.append(entry)
|
|
profiles = [p for p in profiles if not re.search(r'\.(wk|)bak.*', p.name, re.IGNORECASE)]
|
|
except:
|
|
pass
|
|
|
|
return profiles
|
|
|
|
def get_iexplorer_exe():
|
|
"""Find and return iexplorer.exe path as str."""
|
|
ie_exe = '{PROGRAMFILES}\\Internet Explorer\\iexplore.exe'.format(**global_vars['Env'])
|
|
if 'PROGRAMFILES(X86)' in global_vars['Env']:
|
|
ie_exe = '{PROGRAMFILES(X86)}\\Internet Explorer\\iexplore.exe'.format(**global_vars['Env'])
|
|
return ie_exe
|
|
|
|
def get_firefox_exe():
|
|
"""Check for Mozilla Firefox installation and return firefox.exe path as str."""
|
|
prog_exe = '{PROGRAMFILES}\\Mozilla Firefox\\firefox.exe'.format(**global_vars['Env'])
|
|
if 'PROGRAMFILES(X86)' in global_vars['Env']:
|
|
prog_exe = '{PROGRAMFILES(X86)}\\Mozilla Firefox\\firefox.exe'.format(**global_vars['Env'])
|
|
if os.path.exists(prog_exe):
|
|
return prog_exe
|
|
else:
|
|
return None
|
|
|
|
def get_firefox_dev_exe():
|
|
"""Check for Mozilla Firefox Developer Edition installation and return firefox.exe path as str."""
|
|
prog_exe = '{PROGRAMFILES}\\Firefox Developer Edition\\firefox.exe'.format(**global_vars['Env'])
|
|
if 'PROGRAMFILES(X86)' in global_vars['Env']:
|
|
prog_exe = '{PROGRAMFILES(X86)}\\Firefox Developer Edition\\firefox.exe'.format(**global_vars['Env'])
|
|
if os.path.exists(prog_exe):
|
|
return prog_exe
|
|
else:
|
|
return None
|
|
|
|
def get_firefox_profiles():
|
|
"""Find any existing Chrome profiles and return as a list of os.DirEntry objects."""
|
|
profiles = []
|
|
try:
|
|
for entry in os.scandir('{APPDATA}\\Mozilla\\Firefox\\Profiles'.format(**global_vars['Env'])):
|
|
if entry.is_dir():
|
|
profiles.append(entry)
|
|
profiles = [p for p in profiles if not re.search(r'\.(wk|)bak.*', p.name, re.IGNORECASE)]
|
|
except:
|
|
pass
|
|
|
|
return profiles
|
|
|
|
def get_opera_exe():
|
|
"""Check for Opera installation and return launcher.exe path as str."""
|
|
prog_exe = '{PROGRAMFILES}\\Opera\\launcher.exe'.format(**global_vars['Env'])
|
|
if 'PROGRAMFILES(X86)' in global_vars['Env']:
|
|
prog_exe = '{PROGRAMFILES(X86)}\\Opera\\launcher.exe'.format(**global_vars['Env'])
|
|
if os.path.exists(prog_exe):
|
|
return prog_exe
|
|
else:
|
|
return None
|
|
|
|
def get_opera_beta_exe():
|
|
"""Check for Opera Beta installation and return launcher.exe path as str."""
|
|
prog_exe = '{PROGRAMFILES}\\Opera beta\\launcher.exe'.format(**global_vars['Env'])
|
|
# Installs as 64-bit on a 64-bit OS so PROGRAMFILES should always be correct
|
|
|
|
if os.path.exists(prog_exe):
|
|
return prog_exe
|
|
else:
|
|
return None
|
|
|
|
def get_opera_dev_exe():
|
|
"""Check for Opera Beta installation and return launcher.exe path as str."""
|
|
prog_exe = '{PROGRAMFILES}\\Opera developer\\launcher.exe'.format(**global_vars['Env'])
|
|
# Installs as 64-bit on a 64-bit OS so PROGRAMFILES should always be correct
|
|
|
|
if os.path.exists(prog_exe):
|
|
return prog_exe
|
|
else:
|
|
return None
|
|
|
|
def get_opera_profile():
|
|
"""Find an existing Opera profile and return as a length-1 list of os.DirEntry objects."""
|
|
profiles = []
|
|
try:
|
|
for entry in os.scandir('{APPDATA}\\Opera Software'.format(**global_vars['Env'])):
|
|
if entry.is_dir() and entry.name == 'Opera Stable':
|
|
return [entry]
|
|
except:
|
|
pass
|
|
|
|
return profiles
|
|
|
|
def get_opera_beta_profile():
|
|
"""Find an existing Opera Beta profile and return as a length-1 list of os.DirEntry objects."""
|
|
profiles = []
|
|
try:
|
|
for entry in os.scandir('{APPDATA}\\Opera Software'.format(**global_vars['Env'])):
|
|
if entry.is_dir() and entry.name == 'Opera Next':
|
|
return [entry]
|
|
except:
|
|
pass
|
|
|
|
return profiles
|
|
|
|
def get_opera_dev_profile():
|
|
"""Find an existing Opera Dev profile and return as a length-1 list of os.DirEntry objects."""
|
|
profiles = []
|
|
try:
|
|
for entry in os.scandir('{APPDATA}\\Opera Software'.format(**global_vars['Env'])):
|
|
if entry.is_dir() and entry.name == 'Opera Developer':
|
|
return [entry]
|
|
except:
|
|
pass
|
|
|
|
return profiles
|
|
|
|
def list_homepages(indent=8, width=32):
|
|
"""List current homepages for reference."""
|
|
print_standard('{indent}{browser:<{width}}'.format(indent=' '*indent, width=width, browser='Google Chrome...'), end='', flush=True)
|
|
print_warning('Currently not possible', timestamp=False)
|
|
|
|
# Firefox
|
|
profiles = get_firefox_profiles()
|
|
if len(profiles) > 0:
|
|
print_standard('{indent}{browser:<{width}}'.format(indent=' '*indent, width=width, browser='Mozilla Firefox...'))
|
|
|
|
for profile in profiles:
|
|
homepages = []
|
|
try:
|
|
with open('{path}\\prefs.js'.format(path=profile.path), 'r') as f:
|
|
_search = re.search(r'browser\.startup\.homepage", "([^"]*)"', f.read(), re.IGNORECASE)
|
|
if _search:
|
|
homepages = _search.group(1).split('|')
|
|
except FileNotFoundError:
|
|
pass
|
|
|
|
for page in homepages:
|
|
print_standard('{indent}{name:<{width}}{page}'.format(indent=' '*(indent+4), width=width-4, name=profile.name, page=page))
|
|
|
|
# IE
|
|
homepage = ''
|
|
secondary_homepages = []
|
|
key = r'Software\Microsoft\Internet Explorer\Main'
|
|
with winreg.OpenKey(winreg.HKEY_CURRENT_USER, key) as _key:
|
|
homepage = winreg.QueryValueEx(_key, 'Start Page')[0]
|
|
try:
|
|
secondary_homepages = winreg.QueryValueEx(_key, 'Secondary Start Pages')[0]
|
|
except FileNotFoundError:
|
|
pass
|
|
print_standard('{indent}{browser:<{width}}{page}'.format(indent=' '*indent, width=width, browser='Internet Explorer...', page=homepage))
|
|
for page in secondary_homepages:
|
|
print_standard('{indent}{page}'.format(indent=' '*(indent+width), page=page))
|
|
|
|
def reset_google_chrome():
|
|
kill_process('chrome.exe')
|
|
chrome_exe = get_chrome_exe()
|
|
profiles = get_chrome_profiles()
|
|
if len(profiles) == 0:
|
|
raise NoProfilesError
|
|
|
|
for profile in profiles:
|
|
clean_chromium_profile(profile)
|
|
|
|
def reset_google_chrome_canary():
|
|
kill_process('chrome.exe')
|
|
chrome_canary_exe = get_chrome_canary_exe()
|
|
profiles = get_chrome_canary_profiles()
|
|
if len(profiles) == 0:
|
|
raise NoProfilesError
|
|
|
|
for profile in profiles:
|
|
clean_chromium_profile(profile)
|
|
|
|
def reset_mozilla_firefox():
|
|
kill_process('firefox.exe')
|
|
profiles = get_firefox_profiles()
|
|
|
|
if len(profiles) == 0:
|
|
create_firefox_default_profiles()
|
|
kill_process('firefox.exe')
|
|
raise NoProfilesError
|
|
else:
|
|
for profile in profiles:
|
|
clean_firefox_profile(profile)
|
|
|
|
def reset_opera():
|
|
kill_process('opera.exe')
|
|
opera_exe = get_opera_exe()
|
|
profiles = get_opera_profile()
|
|
if len(profiles) == 0:
|
|
raise NoProfilesError
|
|
|
|
# Reset browser (Opera only supports one profile)
|
|
clean_chromium_profile(profiles[0])
|
|
|
|
def reset_opera_beta():
|
|
kill_process('opera.exe')
|
|
opera_beta_exe = get_opera_beta_exe()
|
|
profiles = get_opera_beta_profile()
|
|
if len(profiles) == 0:
|
|
raise NoProfilesError
|
|
|
|
# Reset browser (Opera only supports one profile)
|
|
clean_chromium_profile(profiles[0])
|
|
|
|
def reset_opera_dev():
|
|
kill_process('opera.exe')
|
|
opera_dev_exe = get_opera_dev_exe()
|
|
profiles = get_opera_dev_profile()
|
|
if len(profiles) == 0:
|
|
raise NoProfilesError
|
|
|
|
# Reset browser (Opera only supports one profile)
|
|
clean_chromium_profile(profiles[0])
|
|
|
|
def set_chrome_as_default():
|
|
chrome_exe = get_chrome_exe()
|
|
if chrome_exe is None:
|
|
raise NotInstalledError
|
|
run_program(chrome_exe, ['--make-default-browser'], check=False)
|
|
if global_vars['OS']['Version'] in ['10']:
|
|
popen_program('ms-settings:defaultapps')
|
|
|
|
# Cleanup
|
|
def cleanup_adwcleaner():
|
|
_path = '{SYSTEMDRIVE}\\AdwCleaner'.format(**global_vars['Env'])
|
|
if os.path.exists(_path):
|
|
os.makedirs('{ClientDir}\\Info'.format(**global_vars), exist_ok=True)
|
|
for entry in os.scandir(_path):
|
|
if entry.is_file() and re.search(r'*.(log|txt)', entry.name):
|
|
_name = re.sub(r'^(.*)\.', '\1_{Date-Time}'.format(**global_vars), entry.name, re.IGNORECASE)
|
|
_name = '{ClientDir}\\Info\\{name}'.format(name=_name, **global_vars)
|
|
shutil.move(entry.path, non_clobber_rename(_name))
|
|
elif entry.name == 'Quarantine':
|
|
os.makedirs(global_vars['QuarantineDir'], exist_ok=True)
|
|
_name = '{QuarantineDir}\\AdwCleaner_{Date-Time}'.format(**global_vars)
|
|
shutil.move(entry.path, non_clobber_rename(_name))
|
|
shutil.rmtree(_path)
|
|
|
|
def cleanup_desktop():
|
|
os.makedirs('{ClientDir}\\Info'.format(**global_vars), exist_ok=True)
|
|
if os.path.exists('{USERPROFILE}\\Desktop'.format(**global_vars['Env'])):
|
|
for entry in os.scandir('{USERPROFILE}\\Desktop'.format(**global_vars['Env'])):
|
|
# JRT, RKill, Shortcut cleaner
|
|
if re.search(r'^((JRT|RKill).*|sc-cleaner)', entry.name, re.IGNORECASE):
|
|
_name = '{ClientDir}\\Info\\{name}'.format(name=entry.name, **global_vars)
|
|
shutil.move(entry.path, non_clobber_rename(_name))
|
|
run_program('rmdir "{path}"'.format(path='{ClientDir}\\Info'.format(**global_vars)), check=False, shell=True)
|
|
|
|
def uninstall_eset():
|
|
if 'PROGRAMFILES(X86)' in global_vars['Env']:
|
|
_path = '{PROGRAMFILES(X86)}\\ESET'.format(**global_vars['Env'])
|
|
else:
|
|
_path = '{PROGRAMFILES}\\ESET'.format(**global_vars['Env'])
|
|
if os.path.exists('{path}\\ESET Online Scanner'.format(path=_path)):
|
|
run_program('"{path}\\ESET Online Scanner\\OnlineScannerUninstaller.exe" -s'.format(path=_path))
|
|
shutil.rmtree('{path}\\ESET Online Scanner'.format(path=_path))
|
|
run_program('rmdir "{path}"'.format(path=_path), check=False)
|
|
|
|
def uninstall_mbam():
|
|
# if 'PROGRAMFILES(X86)' in global_vars['Env']:
|
|
# _path = '{PROGRAMFILES(X86)}\\Malwarebytes Anti-Malware'.format(**global_vars['Env'])
|
|
# else:
|
|
# _path = '{PROGRAMFILES}\\Malwarebytes Anti-Malware'.format(**global_vars['Env'])
|
|
# if os.path.exists('{path}'.format(path=_path)):
|
|
# print_warning('* Malwarebytes Anti-Malware installed.')
|
|
# if ask(' Uninstall?'):
|
|
# try:
|
|
# run_program('"{path}\\unins000.exe" /SILENT'.format(path=_path))
|
|
# run_program('rmdir "{path}"'.format(path=_path), check=False)
|
|
# except:
|
|
# print_error('ERROR: Failed to uninstall Malwarebytes Anti-Malware.')
|
|
pass
|
|
|
|
def uninstall_sas():
|
|
# It is always in programfiles (not x86) ??
|
|
_path = '{PROGRAMFILES}\\SUPERAntiSpyware'.format(**global_vars['Env'])
|
|
if os.path.exists(_path):
|
|
run_program('{path}\\Uninstall.exe'.format(path=_path))
|
|
run_program('rmdir "{path}"'.format(path=_path), check=False)
|
|
|
|
# Config
|
|
def config_classicstart():
|
|
# User level, not system level
|
|
_classicstart = '{PROGRAMFILES}\\Classic Shell\\ClassicStartMenu.exe'.format(**global_vars['Env'])
|
|
_skin = '{PROGRAMFILES}\\Classic Shell\\Skins\\Metro-Win10-Black.skin7'.format(**global_vars['Env'])
|
|
extract_item('ClassicStartSkin', silent=True)
|
|
|
|
# Stop Classic Start
|
|
run_program([_classicstart, '-exit'], check=False)
|
|
|
|
# Configure
|
|
winreg.CreateKey(winreg.HKEY_CURRENT_USER, r'Software\IvoSoft\ClassicShell\Settings')
|
|
winreg.CreateKey(winreg.HKEY_CURRENT_USER, r'Software\IvoSoft\ClassicStartMenu\MRU')
|
|
winreg.CreateKey(winreg.HKEY_CURRENT_USER, r'Software\IvoSoft\ClassicStartMenu\Settings')
|
|
with winreg.OpenKey(winreg.HKEY_CURRENT_USER, r'Software\IvoSoft\ClassicStartMenu', access=winreg.KEY_WRITE) as _key:
|
|
winreg.SetValueEx(_key, 'ShowedStyle2', 0, winreg.REG_DWORD, 1)
|
|
with winreg.OpenKey(winreg.HKEY_CURRENT_USER, r'Software\IvoSoft\ClassicStartMenu\Settings', access=winreg.KEY_WRITE) as _key:
|
|
winreg.SetValueEx(_key, 'MenuStyle', 0, winreg.REG_SZ, 'Win7')
|
|
winreg.SetValueEx(_key, 'RecentPrograms', 0, winreg.REG_SZ, 'Recent')
|
|
winreg.SetValueEx(_key, 'SkipMetro', 0, winreg.REG_DWORD, 1)
|
|
|
|
# Enable Win10 theme if on Win10
|
|
if global_vars['OS']['Version'] == '10' and os.path.exists(_skin):
|
|
winreg.SetValueEx(_key, 'SkinW7', 0, winreg.REG_SZ, 'Metro-Win10-Black')
|
|
winreg.SetValueEx(_key, 'SkinVariationW7', 0, winreg.REG_SZ, '')
|
|
|
|
# Pin Google Chrome to Start Menu (Classic)
|
|
_source = '{BinDir}\\ClassicStartSkin\\Google Chrome.lnk'.format(**global_vars)
|
|
_dest_path = '{APPDATA}\\ClassicShell\\Pinned'.format(**global_vars['Env'])
|
|
_dest = '{dest_path}\\Google Chrome.lnk'.format(dest_path=_dest_path)
|
|
try:
|
|
os.makedirs(_dest_path, exist_ok=True)
|
|
shutil.copy(_source, _dest)
|
|
except:
|
|
pass # Meh, it's fine without
|
|
|
|
# (Re)start Classic Start
|
|
run_program([_classicstart, '-exit'], check=False)
|
|
sleep(1)
|
|
kill_process('ClassicStartMenu.exe')
|
|
run_program(_classicstart, check=False)
|
|
|
|
def config_explorer_system():
|
|
# Disable Telemetry
|
|
winreg.CreateKeyEx(winreg.HKEY_LOCAL_MACHINE, r'SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\DataCollection', 0, winreg.KEY_WRITE)
|
|
winreg.CreateKeyEx(winreg.HKEY_LOCAL_MACHINE, r'SOFTWARE\Policies\Microsoft\Windows\DataCollection', 0, winreg.KEY_WRITE)
|
|
winreg.CreateKeyEx(winreg.HKEY_LOCAL_MACHINE, r'SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\DataCollection', 0, winreg.KEY_WRITE | winreg.KEY_WOW64_32KEY)
|
|
with winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, r'SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\DataCollection', access=winreg.KEY_WRITE) as _key:
|
|
winreg.SetValueEx(_key, 'AllowTelemetry', 0, winreg.REG_DWORD, 0)
|
|
with winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, r'SOFTWARE\Policies\Microsoft\Windows\DataCollection', access=winreg.KEY_WRITE) as _key:
|
|
winreg.SetValueEx(_key, 'AllowTelemetry', 0, winreg.REG_DWORD, 0)
|
|
with winreg.OpenKeyEx(winreg.HKEY_LOCAL_MACHINE, r'SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\DataCollection', 0, winreg.KEY_WRITE | winreg.KEY_WOW64_32KEY) as _key:
|
|
winreg.SetValueEx(_key, 'AllowTelemetry', 0, winreg.REG_DWORD, 0)
|
|
|
|
# Disable Wi-Fi Sense
|
|
winreg.CreateKeyEx(winreg.HKEY_LOCAL_MACHINE, r'Software\Microsoft\PolicyManager\default\WiFi\AllowWiFiHotSpotReporting', 0, winreg.KEY_WRITE)
|
|
winreg.CreateKeyEx(winreg.HKEY_LOCAL_MACHINE, r'Software\Microsoft\PolicyManager\default\WiFi\AllowAutoConnectToWiFiSenseHotspots', 0, winreg.KEY_WRITE)
|
|
with winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, r'Software\Microsoft\PolicyManager\default\WiFi\AllowWiFiHotSpotReporting', access=winreg.KEY_WRITE) as _key:
|
|
winreg.SetValueEx(_key, 'Value', 0, winreg.REG_DWORD, 0)
|
|
with winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, r'Software\Microsoft\PolicyManager\default\WiFi\AllowAutoConnectToWiFiSenseHotspots', access=winreg.KEY_WRITE) as _key:
|
|
winreg.SetValueEx(_key, 'Value', 0, winreg.REG_DWORD, 0)
|
|
|
|
# Disable Location Tracking
|
|
with winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, r'SOFTWARE\Microsoft\Windows NT\CurrentVersion\Sensor\Overrides\{BFA794E4-F964-4FDB-90F6-51056BFE4B44}', access=winreg.KEY_WRITE) as _key:
|
|
winreg.SetValueEx(_key, 'SensorPermissionState', 0, winreg.REG_DWORD, 0)
|
|
with winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, r'System\CurrentControlSet\Services\lfsvc\Service\Configuration', access=winreg.KEY_WRITE) as _key:
|
|
winreg.SetValueEx(_key, 'Status', 0, winreg.REG_DWORD, 0)
|
|
|
|
def config_explorer_user():
|
|
# Disable Cortana
|
|
winreg.CreateKeyEx(winreg.HKEY_CURRENT_USER, r'Software\Microsoft\Personalization\Settings', 0, winreg.KEY_WRITE)
|
|
winreg.CreateKeyEx(winreg.HKEY_CURRENT_USER, r'Software\Microsoft\InputPersonalization', 0, winreg.KEY_WRITE)
|
|
winreg.CreateKeyEx(winreg.HKEY_CURRENT_USER, r'Software\Microsoft\InputPersonalization\TrainedDataStore', 0, winreg.KEY_WRITE)
|
|
with winreg.OpenKey(winreg.HKEY_CURRENT_USER, r'Software\Microsoft\Personalization\Settings', access=winreg.KEY_WRITE) as _key:
|
|
winreg.SetValueEx(_key, 'AcceptedPrivacyPolicy', 0, winreg.REG_DWORD, 0)
|
|
with winreg.OpenKey(winreg.HKEY_CURRENT_USER, r'Software\Microsoft\InputPersonalization', access=winreg.KEY_WRITE) as _key:
|
|
winreg.SetValueEx(_key, 'RestrictImplicitTextCollection', 0, winreg.REG_DWORD, 1)
|
|
winreg.SetValueEx(_key, 'RestrictImplicitInkCollection', 0, winreg.REG_DWORD, 1)
|
|
with winreg.OpenKey(winreg.HKEY_CURRENT_USER, r'Software\Microsoft\InputPersonalization\TrainedDataStore', access=winreg.KEY_WRITE) as _key:
|
|
winreg.SetValueEx(_key, 'HarvestContacts', 0, winreg.REG_DWORD, 1)
|
|
|
|
# Hide Search button / box
|
|
with winreg.OpenKey(winreg.HKEY_CURRENT_USER, r'Software\Microsoft\Windows\CurrentVersion\Search', access=winreg.KEY_WRITE) as _key:
|
|
winreg.SetValueEx(_key, 'SearchboxTaskbarMode', 0, winreg.REG_DWORD, 0)
|
|
|
|
# Change default Explorer view to "Computer"
|
|
with winreg.OpenKey(winreg.HKEY_CURRENT_USER, r'Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced', access=winreg.KEY_WRITE) as _key:
|
|
winreg.SetValueEx(_key, 'LaunchTo', 0, winreg.REG_DWORD, 1)
|
|
|
|
def update_clock():
|
|
# Set Timezone and sync clock
|
|
run_program('tzutil /s "Pacific Standard Time"', check=False)
|
|
run_program('net stop w32ime', check=False)
|
|
run_program('w32tm /config /syncfromflags:manual /manualpeerlist:"us.pool.ntp.org time.nist.gov time.windows.com"', check=False)
|
|
run_program('net start w32ime', check=False)
|
|
run_program('w32tm /resync /nowait', check=False)
|
|
|
|
# Disk Management and Data Transfers
|
|
def cleanup_transfer():
|
|
"""Fix permissions and walk through transfer folder (from the bottom) and remove extraneous items."""
|
|
cmd = ['attrib', '-a', '-h', '-r', '-s', global_vars['Data']['Destination']]
|
|
run_program(cmd, check=False)
|
|
try:
|
|
os.rmdir(global_vars['Data']['Destination'])
|
|
except:
|
|
pass # Should only remove when empty
|
|
if os.path.exists(global_vars['Data']['Destination']):
|
|
for root, dirs, files in os.walk(global_vars['Data']['Destination'], topdown=False):
|
|
for name in dirs:
|
|
# Remove empty directories and junction points
|
|
try:
|
|
os.rmdir(os.path.join(root, name))
|
|
except OSError:
|
|
pass
|
|
for name in files:
|
|
# Remove files based on exclusion regex
|
|
if REGEX_EXCL_ITEMS.search(name):
|
|
try:
|
|
os.remove(os.path.join(root, name))
|
|
except OSError:
|
|
pass
|
|
|
|
def extract_keys():
|
|
"""Extract keys from provided hives and return a dict."""
|
|
keys = {}
|
|
|
|
# Extract keys
|
|
extract_item('ProduKey', silent=True)
|
|
for hive in find_software_hives():
|
|
_cmd = [
|
|
global_vars['Tools']['ProduKey'],
|
|
'/IEKeys', '0',
|
|
'/WindowsKeys', '1',
|
|
'/OfficeKeys', '1',
|
|
'/ExtractEdition', '1',
|
|
'/nosavereg',
|
|
'/regfile', hive,
|
|
'/scomma', '']
|
|
_out = run_program(_cmd)
|
|
|
|
for line in _out.stdout.decode().splitlines():
|
|
# Add key to keys under product only if unique
|
|
_tmp = line.split(',')
|
|
_product = _tmp[0]
|
|
_key = _tmp[2]
|
|
if _product not in keys:
|
|
keys[_product] = []
|
|
if _key not in keys[_product]:
|
|
keys[_product].append(_key)
|
|
|
|
global_vars['Keys'] = keys
|
|
|
|
def is_valid_wim_image(item):
|
|
_valid = bool(item.is_file() and REGEX_WIM_FILE.search(item.name))
|
|
if _valid:
|
|
extract_item('wimlib', silent=True)
|
|
try:
|
|
_cmd = [global_vars['Tools']['wimlib-imagex'], 'info', item.path]
|
|
run_program(_cmd)
|
|
except subprocess.CalledProcessError:
|
|
_valid = False
|
|
print_log('WARNING: Image "{image}" damaged.'.format(image=item.name))
|
|
return _valid
|
|
|
|
def mount_backup_shares():
|
|
"""Mount the backup shares unless labeled as already mounted."""
|
|
for server in BACKUP_SERVERS:
|
|
# Blindly skip if we mounted earlier
|
|
if server['Mounted']:
|
|
continue
|
|
else:
|
|
try:
|
|
# Test connection
|
|
ping_test(server['IP'])
|
|
|
|
# Mount
|
|
run_program('net use \\\\{IP}\\{Share} /user:{User} {Pass}'.format(**server))
|
|
print_info('Mounted {Name}'.format(**server))
|
|
server['Mounted'] = True
|
|
except subprocess.CalledProcessError:
|
|
print_error('Failed to mount \\\\{Name}\\{Share}, {IP} unreachable.'.format(**server))
|
|
sleep(1)
|
|
except:
|
|
print_warning('Failed to mount \\\\{Name}\\{Share} ({IP})'.format(**server))
|
|
sleep(1)
|
|
|
|
def run_fast_copy(items=None, dest=None):
|
|
if items is None or dest is None:
|
|
raise Exception
|
|
elif len(items) == 0:
|
|
raise Exception
|
|
|
|
cmd = [global_vars['Tools']['FastCopy'], *FAST_COPY_ARGS]
|
|
if 'LogFile' in global_vars:
|
|
cmd.append('/logfile={LogFile}'.format(**global_vars))
|
|
cmd.extend(items)
|
|
cmd.append('/to={dest}\\'.format(dest=dest))
|
|
run_program(cmd)
|
|
|
|
def run_wimextract(source=None, items=None, dest=None):
|
|
if source is None or items is None or dest is None:
|
|
raise Exception
|
|
elif len(items) == 0:
|
|
raise Exception
|
|
extract_item('wimlib', silent=True)
|
|
|
|
# Write files.txt
|
|
with open('{TmpDir}\\wim_files.txt'.format(**global_vars), 'w') as f:
|
|
# Defaults
|
|
for item in items:
|
|
f.write('{item}\n'.format(item=item))
|
|
sleep(1) # For safety?
|
|
|
|
# Extract files
|
|
cmd = [
|
|
global_vars['Tools']['wimlib-imagex'],
|
|
'extract',
|
|
source, '1',
|
|
'@{TmpDir}\\wim_files.txt'.format(**global_vars),
|
|
'--dest-dir={dest}\\'.format(dest=dest),
|
|
'--no-acls',
|
|
'--nullglob']
|
|
run_program(cmd)
|
|
|
|
def save_keys():
|
|
key_list = []
|
|
if global_vars['Keys']:
|
|
for product in sorted(global_vars['Keys']):
|
|
key_list.append(product)
|
|
for key in sorted(global_vars['Keys'][product]):
|
|
key_list.append(' {key}'.format(key=key))
|
|
else:
|
|
key_list.append('No keys found.')
|
|
|
|
return key_list
|
|
|
|
def scan_backup():
|
|
if 'Source' not in global_vars['Data']:
|
|
raise Exception
|
|
backup = global_vars['Data']['Source']
|
|
global_vars['Data']['Selected Items'] = []
|
|
|
|
if backup.is_dir():
|
|
# File-Based
|
|
print_standard('Scanning File-Based backup: {}'.format(backup.path))
|
|
scan_backup_folder(backup)
|
|
else:
|
|
# Image-Based
|
|
if REGEX_WIM_FILE.search(backup.name):
|
|
print_standard('Scanning Image-Based backup: {}'.format(backup.path))
|
|
selected_items = scan_backup_wim(backup)
|
|
else:
|
|
print_error('ERROR: Unsupported image: {}'.format(backup.path))
|
|
raise GenericError
|
|
|
|
def scan_backup_folder(backup_folder=None, rel_path=None, interactive=True):
|
|
if backup_folder is None:
|
|
raise Exception
|
|
win_olds = []
|
|
dest = '{dest}{rel_path}'.format(
|
|
dest = global_vars['Data']['Destination'],
|
|
rel_path = '' if rel_path is None else '\\'+rel_path)
|
|
|
|
# Root items
|
|
_items = []
|
|
for item in os.scandir(backup_folder.path):
|
|
if REGEX_INCL_ROOT_ITEMS.search(item.name):
|
|
_items.append(item.path)
|
|
elif not REGEX_EXCL_ROOT_ITEMS.search(item.name):
|
|
if (not interactive
|
|
or ask('Copy: "{rel_path}{name}" ?'.format(name=item.name, rel_path='' if rel_path is None else rel_path+'\\'))):
|
|
_items.append(item.path)
|
|
if REGEX_WINDOWS_OLD.search(item.name):
|
|
win_olds.append(item)
|
|
if len(_items) > 0:
|
|
global_vars['Data']['Selected Items'].append({
|
|
'Message': '{}Root Items...'.format('' if rel_path is None else rel_path+'\\'),
|
|
'Items': _items.copy(),
|
|
'Destination': dest})
|
|
|
|
# Fonts
|
|
if os.path.exists('{}\\Windows\\Fonts'.format(backup_folder.path)):
|
|
global_vars['Data']['Selected Items'].append({
|
|
'Message': '{}Fonts...'.format('' if rel_path is None else rel_path+'\\'),
|
|
'Items': ['{}\\Windows\\Fonts'.format(backup_folder.path)],
|
|
'Destination': '{}\\{}'.format(dest, 'Windows')})
|
|
_items.append('{source}\\Windows\\Fonts'.format(source=backup_folder.path))
|
|
|
|
# Registry
|
|
_items = []
|
|
if os.path.exists('{}\\Windows\\System32\\config'.format(backup_folder.path)):
|
|
_items.append('{}\\Windows\\System32\\config'.format(backup_folder.path))
|
|
if os.path.exists('{}\\Windows\\System32\\OEM'.format(backup_folder.path)):
|
|
_items.append('{}\\Windows\\System32\\OEM'.format(backup_folder.path))
|
|
if len(_items) > 0:
|
|
global_vars['Data']['Selected Items'].append({
|
|
'Message': '{}Registry...'.format('' if rel_path is None else rel_path+'\\'),
|
|
'Items': _items.copy(),
|
|
'Destination': '{}\\{}'.format(dest, 'Windows\\System32')})
|
|
|
|
# Windows.old(s)
|
|
for old in win_olds:
|
|
scan_backup_folder(old.path, rel_path=old.name, interactive=False)
|
|
|
|
def scan_backup_wim(backup_file=None, rel_path=None, interactive=True):
|
|
if backup_file is None:
|
|
raise Exception
|
|
if rel_path is None:
|
|
rel_path = ''
|
|
else:
|
|
rel_path = rel_path + '\\'
|
|
win_olds = []
|
|
|
|
# Scan source
|
|
extract_item('wimlib', silent=True)
|
|
_cmd = [
|
|
global_vars['Tools']['wimlib-imagex'], 'dir',
|
|
backup_file.path, '1']
|
|
try:
|
|
_list = run_program(_cmd)
|
|
except subprocess.CalledProcessError as err:
|
|
print_error('ERROR: Failed to get file list.')
|
|
raise
|
|
|
|
# Root Items
|
|
_items = []
|
|
root_items = [i.strip() for i in _list.stdout.decode('utf-8', 'ignore').splitlines() if i.count('\\') == 1 and i.strip() != '\\']
|
|
if rel_path:
|
|
root_items = [i.replace(rel_path, '') for i in root_items if rel_path in i]
|
|
for item in root_items:
|
|
if REGEX_INCL_ROOT_ITEMS.search(item):
|
|
_items.append(item)
|
|
elif not REGEX_EXCL_ROOT_ITEMS.search(item):
|
|
if (not interactive
|
|
or ask('Extract: "{rel_path}{name}" ?'.format(name=item, rel_path=rel_path))):
|
|
_items.append('{}{}'.format(rel_path, item))
|
|
if REGEX_WINDOWS_OLD.search(item):
|
|
win_olds.append(item)
|
|
if len(_items) > 0:
|
|
global_vars['Data']['Selected Items'].append({
|
|
'Message': '{}Root Items...'.format(rel_path),
|
|
'Items': _items.copy(),
|
|
'Destination': global_vars['Data']['Destination']})
|
|
|
|
# Fonts
|
|
if wim_contains(backup_file.path, '{}Windows\\Fonts'.format(rel_path)):
|
|
global_vars['Data']['Selected Items'].append({
|
|
'Message': '{}Fonts...'.format(rel_path),
|
|
'Items': ['{}\\Windows\\Fonts'.format(rel_path)],
|
|
'Destination': global_vars['Data']['Destination']})
|
|
|
|
# Registry
|
|
_items = []
|
|
if wim_contains(backup_file.path, '{}Windows\\System32\\config'.format(rel_path)):
|
|
_items.append('{}Windows\\System32\\config'.format(rel_path))
|
|
if wim_contains(backup_file.path, '{}Windows\\System32\\OEM'.format(rel_path)):
|
|
_items.append('{}Windows\\System32\\OEM'.format(rel_path))
|
|
if len(_items) > 0:
|
|
global_vars['Data']['Selected Items'].append({
|
|
'Message': '{}Registry...'.format(rel_path),
|
|
'Items': _items.copy(),
|
|
'Destination': global_vars['Data']['Destination']})
|
|
|
|
# Windows.old(s)
|
|
for old in win_olds:
|
|
scan_backup_wim(backup_file, rel_path=old, interactive=False)
|
|
|
|
def select_backup():
|
|
"""Select backup from those found on the BACKUP_SERVERS for the ticket."""
|
|
sources = []
|
|
mount_backup_shares()
|
|
|
|
# Check for ticket folders on servers
|
|
for server in BACKUP_SERVERS:
|
|
if server['Mounted']:
|
|
print_standard('Scanning {server}...'.format(server=server['Name']))
|
|
for d in os.scandir('\\\\{IP}\\{Share}'.format(**server)):
|
|
if d.is_dir() and re.match('^{}'.format(global_vars['TicketNumber']), d.name):
|
|
# Add folder to sources
|
|
sources.append({
|
|
'Name': '{server:9}| File-Based: [DIR] {ticket}'.format(server=server['Name'], ticket=d.name),
|
|
'Server': server,
|
|
'Source': d})
|
|
|
|
# Check for images and subfolders
|
|
for ticket_folder in sources.copy():
|
|
for item in os.scandir(ticket_folder['Source'].path):
|
|
if item.is_dir():
|
|
# Add folder to sources
|
|
sources.append({
|
|
'Name': '{server:9}| File-Based: [DIR] {ticket}\\{folder}'.format(
|
|
folder = item.name,
|
|
server = ticket_folder['Server']['Name'],
|
|
ticket = ticket_folder['Source'].name),
|
|
'Server': ticket_folder['Server'],
|
|
'Source': item})
|
|
|
|
# Check for images in folder
|
|
for subitem in os.scandir(item.path):
|
|
if REGEX_WIM_FILE.search(item.name):
|
|
# Add image to sources
|
|
try:
|
|
size = human_readable_size(item.stat().st_size)
|
|
except:
|
|
size = ' ? ?' # unknown
|
|
sources.append({
|
|
'Disabled': bool(not is_valid_wim_image(subitem)),
|
|
'Name': '{server:9}| Image-Based: {size:>7} {ticket}\\{folder}\\{image}'.format(
|
|
folder = item.name,
|
|
image = subitem.name,
|
|
server = ticket_folder['Server']['Name'],
|
|
size = size,
|
|
ticket = ticket_folder['Source'].name),
|
|
'Server': ticket_folder['Server'],
|
|
'Source': subitem})
|
|
elif REGEX_WIM_FILE.search(item.name):
|
|
# Add image to sources
|
|
try:
|
|
size = human_readable_size(item.stat().st_size)
|
|
except:
|
|
size = ' ? ?' # unknown
|
|
sources.append({
|
|
'Disabled': bool(not is_valid_wim_image(item)),
|
|
'Name': '{server:9}| Image-Based: {size:>7} {ticket}\\{image}'.format(
|
|
image = item.name,
|
|
server = ticket_folder['Server']['Name'],
|
|
size = size,
|
|
ticket = ticket_folder['Source'].name),
|
|
'Server': ticket_folder['Server'],
|
|
'Source': item})
|
|
|
|
# Build Menu
|
|
sources.sort(key=itemgetter('Name'))
|
|
actions = [{'Name': 'Quit', 'Letter': 'Q'}]
|
|
|
|
# Select backup from sources
|
|
if len(sources) > 0:
|
|
selection = menu_select('Which backup are we using?', sources, actions, disabled_label='DAMAGED')
|
|
if selection == 'Q':
|
|
umount_backup_shares()
|
|
exit_script()
|
|
else:
|
|
global_vars['Data']['Source'] = sources[int(selection)-1]['Source']
|
|
else:
|
|
print_error('ERROR: No backups found for ticket: {TicketNumber}.'.format(**global_vars))
|
|
umount_backup_shares()
|
|
pause("Press Enter to exit...")
|
|
exit_script()
|
|
|
|
def select_destination():
|
|
"""Select destination for data 1 transfer."""
|
|
disk = select_disk()
|
|
path = '{disk}{folder_path}_{Date}'.format(
|
|
disk = disk['Disk'].mountpoint,
|
|
folder_path = 'WK\\Transfer' if 'fixed' in disk['Disk'].opts else 'WK-Transfer',
|
|
**global_vars)
|
|
|
|
# Avoid merging with existing transfer
|
|
path = non_clobber_rename(path)
|
|
os.makedirs(path, exist_ok=True)
|
|
|
|
global_vars['Data']['Destination'] = path
|
|
|
|
def select_disk():
|
|
"""Select disk from attached disks. returns dict."""
|
|
actions = [{'Name': 'Quit', 'Letter': 'Q'}]
|
|
disks = []
|
|
for d in psutil.disk_partitions():
|
|
info = {
|
|
'Disk': d,
|
|
'Name': d.mountpoint}
|
|
try:
|
|
usage = psutil.disk_usage(d.device)
|
|
free = '{free} / {total} available'.format(
|
|
free = human_readable_size(usage.free, 2),
|
|
total = human_readable_size(usage.total, 2))
|
|
except:
|
|
# Meh, leaving unsupported destinations out
|
|
pass
|
|
# free = 'Unknown'
|
|
# info['Disabled'] = True
|
|
else:
|
|
info['Display Name'] = '{disk} ({free})'.format(disk=info['Name'], free=free)
|
|
disks.append(info)
|
|
|
|
selection = menu_select('Which disk are we transferring to?', disks, actions)
|
|
if selection == 'Q':
|
|
exit_script()
|
|
else:
|
|
return disks[int(selection)-1]
|
|
|
|
def transfer_backup():
|
|
if 'Source' not in global_vars['Data']:
|
|
raise Exception
|
|
backup = global_vars['Data']['Source']
|
|
|
|
if backup.is_dir():
|
|
# File-Based
|
|
transfer_backup_file_based()
|
|
else:
|
|
# Image-Based
|
|
if REGEX_WIM_FILE.search(backup.name):
|
|
transfer_backup_image_based()
|
|
else:
|
|
print_error('ERROR: Unsupported image: {}'.format(backup.path))
|
|
raise GenericError
|
|
|
|
def transfer_backup_file_based():
|
|
if 'Source' not in global_vars['Data'] or 'Selected Items' not in global_vars['Data']:
|
|
raise Exception
|
|
backup = global_vars['Data']['Source']
|
|
selected_items = global_vars['Data']['Selected Items']
|
|
|
|
# Run FastCopy for each selection "group"
|
|
for group in selected_items:
|
|
try_and_print(message=group['Message'], function=run_fast_copy, cs='Done', items=group['Items'], dest=group['Destination'])
|
|
|
|
def transfer_backup_image_based():
|
|
if 'Source' not in global_vars['Data'] or 'Selected Items' not in global_vars['Data']:
|
|
raise Exception
|
|
backup = global_vars['Data']['Source']
|
|
selected_items = global_vars['Data']['Selected Items']
|
|
|
|
# Run wimlib-imagex for each selection "group"
|
|
for group in selected_items:
|
|
try_and_print(message=group['Message'], function=run_wimextract, cs='Done', source=global_vars['Data']['Source'].path, items=group['Items'], dest=group['Destination'])
|
|
|
|
def umount_backup_shares():
|
|
"""Unnount the backup shares regardless of current status."""
|
|
for server in BACKUP_SERVERS:
|
|
try:
|
|
# Umount
|
|
run_program('net use \\\\{IP}\\{Share} /delete'.format(**server))
|
|
print_info('Umounted {Name}'.format(**server))
|
|
server['Mounted'] = False
|
|
except:
|
|
print_error('Failed to umount \\\\{Name}\\{Share}.'.format(**server))
|
|
sleep(1)
|
|
|
|
def wim_contains(source_path=None, file_path=None):
|
|
if file_path is None or source_path is None:
|
|
raise Exception
|
|
|
|
_cmd = [
|
|
global_vars['Tools']['wimlib-imagex'], 'dir',
|
|
'{source}'.format(source=source_path), '1',
|
|
'--path={}'.format(file_path),
|
|
'--one-file-only']
|
|
try:
|
|
run_program(_cmd)
|
|
except subprocess.CalledProcessError:
|
|
return False
|
|
else:
|
|
return True
|
|
|
|
# Kit Updates
|
|
def download_file(out_dir, out_name, source_url):
|
|
"""Downloads a file using curl."""
|
|
extract_item('curl', silent=True)
|
|
_cmd = [
|
|
global_vars['Tools']['curl'],
|
|
# '-#LSfo', # ProgressBar
|
|
'-Lfso',
|
|
'{out_dir}/{out_name}'.format(out_dir=out_dir, out_name=out_name),
|
|
source_url]
|
|
os.makedirs(out_dir, exist_ok=True)
|
|
run_program(_cmd, pipe=False)
|
|
|
|
def resolve_dynamic_url(source_url, regex):
|
|
"""Download the "download page" and scan for a url using the regex provided; returns str."""
|
|
# Download the "download page"
|
|
extract_item('curl', silent=True)
|
|
_tmp_file = '{TmpDir}/webpage.tmp'.format(**global_vars)
|
|
_cmd = [
|
|
global_vars['Tools']['curl'],
|
|
'-#LSfo',
|
|
_tmp_file,
|
|
source_url]
|
|
try:
|
|
run_program(_cmd)
|
|
except:
|
|
# "Fail silently as the download_file() function will catch it
|
|
return None
|
|
|
|
# Scan the file for the regex
|
|
with open(_tmp_file, 'r') as file:
|
|
for line in file:
|
|
if re.search(regex, line):
|
|
_url = line.strip()
|
|
_url = re.sub(r'.*(a |)href="([^"]+)".*', r'\2', _url)
|
|
_url = re.sub(r".*(a |)href='([^']+)'.*", r'\2', _url)
|
|
break
|
|
|
|
# Cleanup and return
|
|
os.remove(_tmp_file)
|
|
return _url
|
|
|
|
def update_adwcleaner():
|
|
_path = global_vars['BinDir']
|
|
_name = 'AdwCleaner.exe'
|
|
_dl_page = 'http://www.bleepingcomputer.com/download/adwcleaner/dl/125/'
|
|
_regex = r'href=.*http(s|)://download\.bleepingcomputer\.com/dl/[a-zA-Z0-9]+/[a-zA-Z0-9]+/windows/security/security-utilities/a/adwcleaner/AdwCleaner\.exe'
|
|
_url = resolve_dynamic_url(_dl_page, _regex)
|
|
download_file(_path, _name, _url)
|
|
|
|
def update_eset():
|
|
_path = global_vars['BinDir']
|
|
_name = 'ESET.exe'
|
|
_url = 'http://download.eset.com/special/eos/esetsmartinstaller_enu.exe'
|
|
download_file(_path, _name, _url)
|
|
|
|
def update_jrt():
|
|
_path = global_vars['BinDir']
|
|
_name = 'JRT.exe'
|
|
_url = 'http://downloads.malwarebytes.org/file/jrt'
|
|
download_file(_path, _name, _url)
|
|
|
|
def update_kvrt():
|
|
_path = global_vars['BinDir']
|
|
_name = 'KVRT.exe'
|
|
_url = 'http://devbuilds.kaspersky-labs.com/devbuilds/KVRT/latest/full/KVRT.exe'
|
|
download_file(_path, _name, _url)
|
|
|
|
def update_hitmanpro():
|
|
_path = '{BinDir}/HitmanPro'.format(**global_vars)
|
|
_name = 'HitmanPro.exe'
|
|
_url = 'http://dl.surfright.nl/HitmanPro.exe'
|
|
download_file(_path, _name, _url)
|
|
|
|
_name = 'HitmanPro64.exe'
|
|
_url = 'http://dl.surfright.nl/HitmanPro_x64.exe'
|
|
download_file(_path, _name, _url)
|
|
|
|
def update_intel_driver_utility():
|
|
_path = '{BinDir}/_Drivers'.format(**global_vars)
|
|
_name = 'Intel Driver Update Utility.exe'
|
|
_dl_page = 'http://www.intel.com/content/www/us/en/support/detect.html'
|
|
_regex = r'a href.*http(s|)://downloadmirror\.intel\.com/[a-zA-Z0-9]+/[a-zA-Z0-9]+/Intel%20Driver%20Update%20Utility%20Installer.exe'
|
|
_url = resolve_dynamic_url(_dl_page, _regex)
|
|
_url = resolve_dynamic_url(_dl_page, _regex)
|
|
download_file(_path, _name, _url)
|
|
|
|
def update_intel_ssd_toolbox():
|
|
_path = '{BinDir}/_Drivers'.format(**global_vars)
|
|
_name = 'Intel SSD Toolbox.exe'
|
|
_dl_page = 'https://downloadcenter.intel.com/download/26085/Intel-Solid-State-Drive-Toolbox'
|
|
_regex = r'href=./downloads/eula/[0-9]+/Intel-Solid-State-Drive-Toolbox.httpDown=https\%3A\%2F\%2Fdownloadmirror\.intel\.com\%2F[0-9]+\%2Feng\%2FIntel\%20SSD\%20Toolbox\%20-\%20v[0-9\.]+.exe'
|
|
_url = resolve_dynamic_url(_dl_page, _regex)
|
|
_url = re.sub(r'.*httpDown=(.*)', r'\1', _url, flags=re.IGNORECASE)
|
|
_url = _url.replace('%3A', ':')
|
|
_url = _url.replace('%2F', '/')
|
|
download_file(_path, _name, _url)
|
|
|
|
def update_rkill():
|
|
_path = '{BinDir}/RKill'.format(**global_vars)
|
|
_name = 'RKill.exe'
|
|
_dl_page = 'http://www.bleepingcomputer.com/download/rkill/dl/10/'
|
|
_regex = r'href=.*http(s|)://download\.bleepingcomputer\.com/dl/[a-zA-Z0-9]+/[a-zA-Z0-9]+/windows/security/security-utilities/r/rkill/rkill\.exe'
|
|
_url = resolve_dynamic_url(_dl_page, _regex)
|
|
download_file(_path, _name, _url)
|
|
|
|
def update_samsung_magician():
|
|
print_warning('Disabled.')
|
|
#~Broken~# _path = '{BinDir}/_Drivers'.format(**global_vars)
|
|
#~Broken~# _name = 'Samsung Magician.zip'
|
|
#~Broken~# _dl_page = 'http://www.samsung.com/semiconductor/minisite/ssd/download/tools.html'
|
|
#~Broken~# _regex = r'href=./semiconductor/minisite/ssd/downloads/software/Samsung_Magician_Setup_v[0-9]+.zip'
|
|
#~Broken~# _url = resolve_dynamic_url(_dl_page, _regex)
|
|
#~Broken~# # Convert relative url to absolute
|
|
#~Broken~# _url = 'http://www.samsung.com' + _url
|
|
#~Broken~# download_file(_path, _name, _url)
|
|
#~Broken~# # Extract and replace old copy
|
|
#~Broken~# _args = [
|
|
#~Broken~# 'e', '"{BinDir}/_Drivers/Samsung Magician.zip"'.format(**global_vars),
|
|
#~Broken~# '-aoa', '-bso0', '-bsp0',
|
|
#~Broken~# '-o"{BinDir}/_Drivers"'.format(**global_vars)
|
|
#~Broken~# ]
|
|
#~Broken~# run_program(seven_zip, _args)
|
|
#~Broken~# try:
|
|
#~Broken~# os.remove('{BinDir}/_Drivers/Samsung Magician.zip'.format(**global_vars))
|
|
#~Broken~# #~PoSH~# Move-Item "$bin\_Drivers\Samsung*exe" "$bin\_Drivers\Samsung Magician.exe" $path 2>&1 | Out-Null
|
|
#~Broken~# except:
|
|
#~Broken~# pass
|
|
pass
|
|
|
|
def update_sysinternalssuite():
|
|
_path = '{BinDir}/tmp'.format(**global_vars)
|
|
_name = 'SysinternalsSuite.zip'
|
|
_url = 'https://download.sysinternals.com/files/SysinternalsSuite.zip'
|
|
download_file(_path, _name, _url)
|
|
# Extract
|
|
_args = [
|
|
'e', '"{BinDir}/tmp/SysinternalsSuite.zip"'.format(**global_vars),
|
|
'-aoa', '-bso0', '-bsp0',
|
|
'-o"{BinDir}/SysinternalsSuite"'.format(**global_vars)]
|
|
run_program(seven_zip, _args)
|
|
try:
|
|
os.remove('{BinDir}/tmp/SysinternalsSuite.zip'.format(**global_vars))
|
|
except:
|
|
pass
|
|
|
|
def update_tdsskiller():
|
|
_path = global_vars['BinDir']
|
|
_name = 'TDSSKiller.exe'
|
|
_url = 'http://media.kaspersky.com/utilities/VirusUtilities/EN/tdsskiller.exe'
|
|
download_file(_path, _name, _url)
|
|
|
|
# Installations
|
|
def install_adobe_reader():
|
|
cmd = [
|
|
'{BaseDir}/Installers/Extras/Office/Adobe Reader DC.exe'.format(**global_vars),
|
|
'/sAll',
|
|
'/msi', '/norestart', '/quiet',
|
|
'ALLUSERS=1',
|
|
'EULA_ACCEPT=YES']
|
|
try_and_print(message='Adobe Reader DC...', function=run_program, cmd=cmd)
|
|
|
|
def install_chrome_extensions():
|
|
winreg.CreateKeyEx(winreg.HKEY_LOCAL_MACHINE, r'Software\Google\Chrome\Extensions', 0, winreg.KEY_WRITE | winreg.KEY_WOW64_32KEY)
|
|
winreg.CreateKeyEx(winreg.HKEY_LOCAL_MACHINE, r'Software\Google\Chrome\Extensions\cjpalhdlnbpafiamejdnhcphjbkeiagm', 0, winreg.KEY_WRITE | winreg.KEY_WOW64_32KEY)
|
|
with winreg.OpenKeyEx(winreg.HKEY_LOCAL_MACHINE, r'Software\Google\Chrome\Extensions\cjpalhdlnbpafiamejdnhcphjbkeiagm', 0, winreg.KEY_WRITE | winreg.KEY_WOW64_32KEY) as _key:
|
|
winreg.SetValueEx(_key, 'update_url', 0, winreg.REG_SZ, 'https://clients2.google.com/service/update2/crx')
|
|
winreg.CreateKeyEx(winreg.HKEY_LOCAL_MACHINE, r'Software\Google\Chrome\Extensions\pgdnlhfefecpicbbihgmbmffkjpaplco', 0, winreg.KEY_WRITE | winreg.KEY_WOW64_32KEY)
|
|
with winreg.OpenKeyEx(winreg.HKEY_LOCAL_MACHINE, r'Software\Google\Chrome\Extensions\pgdnlhfefecpicbbihgmbmffkjpaplco', 0, winreg.KEY_WRITE | winreg.KEY_WOW64_32KEY) as _key:
|
|
winreg.SetValueEx(_key, 'update_url', 0, winreg.REG_SZ, 'https://clients2.google.com/service/update2/crx')
|
|
|
|
def install_classicstart_skin():
|
|
if global_vars['OS']['Version'] not in ['8', '10']:
|
|
raise UnsupportedOSError
|
|
extract_item('ClassicStartSkin', silent=True)
|
|
_source = '{BinDir}\\ClassicStartSkin\\Metro-Win10-Black.skin7'.format(**global_vars)
|
|
_dest_path = '{PROGRAMFILES}\\Classic Shell\\Skins'.format(**global_vars['Env'])
|
|
_dest = '{dest_path}\\Metro-Win10-Black.skin7'.format(dest_path=_dest_path)
|
|
os.makedirs(_dest_path, exist_ok=True)
|
|
shutil.copy(_source, _dest)
|
|
|
|
def install_firefox_extensions():
|
|
extract_item('FirefoxExtensions', silent=True)
|
|
extensions = ['uBlock0@raymondhill.net']
|
|
dests = ['{PROGRAMFILES}\\Mozilla Firefox\\distribution\\extensions'.format(**global_vars['Env'])]
|
|
if 'PROGRAMFILES(X86)' in global_vars['Env']:
|
|
dests.append('{PROGRAMFILES(X86)}\\Mozilla Firefox\\distribution\\extensions'.format(**global_vars['Env']))
|
|
for extension in extensions:
|
|
_source = '{BinDir}\\FirefoxExtensions\\{extension}'.format(extension=extension, **global_vars)
|
|
for dest in dests:
|
|
_dest = '{}\\{}'.format(dest, extension)
|
|
if not os.path.exists(dest):
|
|
shutil.copytree(_source, _dest)
|
|
|
|
def install_ninite_bundle(mse=False):
|
|
if global_vars['OS']['Version'] in ['8', '10']:
|
|
# Modern selection
|
|
popen_program('{BaseDir}/Installers/Extras/Bundles/Modern.exe'.format(**global_vars))
|
|
else:
|
|
# Legacy selection
|
|
if mse:
|
|
popen_program('{BaseDir}/Installers/Extras/Security/Microsoft Security Essentials.exe'.format(**global_vars))
|
|
popen_program('{BaseDir}/Installers/Extras/Bundles/Legacy.exe'.format(**global_vars))
|
|
|
|
def install_vcredists():
|
|
extract_item('_vcredists', silent=True)
|
|
prev_dir = os.getcwd()
|
|
os.chdir('{BinDir}/_vcredists'.format(**global_vars))
|
|
for vcr in VCR_REDISTS:
|
|
try_and_print(message=vcr['Name'], function=run_program, cmd=vcr['Cmd'])
|
|
|
|
os.chdir(prev_dir)
|
|
|
|
# Network
|
|
def check_connection():
|
|
while True:
|
|
result = try_and_print(message='Ping test...', function=ping_test, cs='OK')
|
|
if result['CS']:
|
|
break
|
|
else:
|
|
if not ask('ERROR: System appears offline, try again?'):
|
|
abort()
|
|
|
|
def ping_test(addr='google.com'):
|
|
"""Attempt to ping addr and if unsuccessful either retry or abort."""
|
|
_cmd = ['ping', '-n', '2', addr]
|
|
run_program(_cmd)
|
|
|
|
# OSR / VR
|
|
def run_autoruns():
|
|
"""Run AutoRuns in the background with VirusTotal checks enabled."""
|
|
extract_item('SysinternalsSuite', filter='autoruns*', silent=True)
|
|
winreg.CreateKey(winreg.HKEY_CURRENT_USER, r'Software\Sysinternals\AutoRuns')
|
|
with winreg.OpenKey(winreg.HKEY_CURRENT_USER, r'Software\Sysinternals\AutoRuns', access=winreg.KEY_WRITE) as _key:
|
|
winreg.SetValueEx(_key, 'checkvirustotal', 0, winreg.REG_DWORD, 1)
|
|
winreg.SetValueEx(_key, 'EulaAccepted', 0, winreg.REG_DWORD, 1)
|
|
winreg.SetValueEx(_key, 'shownomicrosoft', 0, winreg.REG_DWORD, 1)
|
|
winreg.SetValueEx(_key, 'shownowindows', 0, winreg.REG_DWORD, 1)
|
|
winreg.SetValueEx(_key, 'showonlyvirustotal', 0, winreg.REG_DWORD, 1)
|
|
winreg.SetValueEx(_key, 'submitvirustotal', 0, winreg.REG_DWORD, 0)
|
|
winreg.SetValueEx(_key, 'verifysignatures', 0, winreg.REG_DWORD, 1)
|
|
winreg.CreateKey(winreg.HKEY_CURRENT_USER, r'Software\Sysinternals\AutoRuns\SigCheck')
|
|
with winreg.OpenKey(winreg.HKEY_CURRENT_USER, r'Software\Sysinternals\AutoRuns\SigCheck', access=winreg.KEY_WRITE) as _key:
|
|
winreg.SetValueEx(_key, 'EulaAccepted', 0, winreg.REG_DWORD, 1)
|
|
winreg.CreateKey(winreg.HKEY_CURRENT_USER, r'Software\Sysinternals\AutoRuns\Streams')
|
|
with winreg.OpenKey(winreg.HKEY_CURRENT_USER, r'Software\Sysinternals\AutoRuns\Streams', access=winreg.KEY_WRITE) as _key:
|
|
winreg.SetValueEx(_key, 'EulaAccepted', 0, winreg.REG_DWORD, 1)
|
|
winreg.CreateKey(winreg.HKEY_CURRENT_USER, r'Software\Sysinternals\AutoRuns\VirusTotal')
|
|
with winreg.OpenKey(winreg.HKEY_CURRENT_USER, r'Software\Sysinternals\AutoRuns\VirusTotal', access=winreg.KEY_WRITE) as _key:
|
|
winreg.SetValueEx(_key, 'VirusTotalTermsAccepted', 0, winreg.REG_DWORD, 1)
|
|
popen_program(global_vars['Tools']['AutoRuns'], minimized=True)
|
|
|
|
def run_chkdsk():
|
|
"""Run CHKDSK in a "split window" and report errors."""
|
|
if global_vars['OS']['Version'] in ['8', '10']:
|
|
_cmd = [
|
|
'chkdsk',
|
|
'{SYSTEMDRIVE}'.format(**global_vars['Env']),
|
|
'/scan', '/perf']
|
|
else:
|
|
_cmd = [
|
|
'chkdsk',
|
|
'{SYSTEMDRIVE}'.format(**global_vars['Env'])]
|
|
_out = run_program(_cmd, check=False)
|
|
# retcode == 0: no issues
|
|
# retcode == 1: fixed issues (also happens when chkdsk.exe is killed?)
|
|
# retcode == 2: issues
|
|
if int(_out.returncode) > 0:
|
|
# print_error(' ERROR: CHKDSK encountered errors')
|
|
raise GenericError
|
|
|
|
# Save stderr
|
|
with open('{LogDir}\\CHKDSK.err'.format(**global_vars), 'a') as f:
|
|
for line in _out.stderr.decode().splitlines():
|
|
f.write(line.strip() + '\n')
|
|
# Save stdout
|
|
with open('{LogDir}\\CHKDSK.log'.format(**global_vars), 'a') as f:
|
|
for line in _out.stdout.decode().splitlines():
|
|
f.write(line.strip() + '\n')
|
|
|
|
def run_chkdsk_offline():
|
|
"""Set filesystem 'dirty bit' to force a chkdsk during next boot."""
|
|
_cmd = [
|
|
'fsutil', 'dirty', 'set',
|
|
'{SYSTEMDRIVE}'.format(**global_vars['Env'])]
|
|
_out = run_program(_cmd, check=False)
|
|
if int(_out.returncode) > 0:
|
|
raise GenericError
|
|
|
|
def run_chkdsk_spotfix():
|
|
"""Run CHKDSK in a "split window" and report errors."""
|
|
if global_vars['OS']['Version'] in ['8', '10']:
|
|
_cmd = [
|
|
'chkdsk',
|
|
'{SYSTEMDRIVE}'.format(**global_vars['Env']),
|
|
'/scan', '/perf']
|
|
else:
|
|
raise UnsupportedOSError
|
|
_out = run_program(_cmd, check=False)
|
|
# retcode == 0: no issues
|
|
# retcode == 1: fixed issues (also happens when chkdsk.exe is killed?)
|
|
# retcode == 2: issues
|
|
if int(_out.returncode) > 0:
|
|
# print_error(' ERROR: CHKDSK encountered errors')
|
|
raise GenericError
|
|
|
|
# Save stderr
|
|
with open('{LogDir}\\CHKDSK_Spotfix.err'.format(**global_vars), 'a') as f:
|
|
for line in _out.stderr.decode().splitlines():
|
|
f.write(line.strip() + '\n')
|
|
# Save stdout
|
|
with open('{LogDir}\\CHKDSK_Spotfix.log'.format(**global_vars), 'a') as f:
|
|
for line in _out.stdout.decode().splitlines():
|
|
f.write(line.strip() + '\n')
|
|
|
|
def run_dism_restore_health():
|
|
"""Run DISM /ScanHealth, then /CheckHealth, and then report errors."""
|
|
if global_vars['OS']['Version'] in ['8', '10']:
|
|
# Scan Health
|
|
_cmd = [
|
|
'DISM', '/Online', '/Cleanup-Image', '/RestoreHealth',
|
|
'/LogPath:"{LogDir}\\DISM_RestoreHealth.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',
|
|
'/LogPath:"{LogDir}\\DISM_CheckHealth.log"'.format(**global_vars)]
|
|
_result = run_program(_cmd, shell=True).stdout.decode()
|
|
# Check result
|
|
if re.search(r'No component store corruption detected', _result, re.IGNORECASE):
|
|
pass
|
|
else:
|
|
raise GenericError
|
|
else:
|
|
raise UnsupportedOSError
|
|
|
|
def run_dism_scan_health():
|
|
"""Run DISM /ScanHealth, then /CheckHealth, and then report errors."""
|
|
if global_vars['OS']['Version'] in ['8', '10']:
|
|
# Scan Health
|
|
_cmd = [
|
|
'DISM', '/Online', '/Cleanup-Image', '/ScanHealth',
|
|
'/LogPath:"{LogDir}\\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',
|
|
'/LogPath:"{LogDir}\\DISM_CheckHealth.log"'.format(**global_vars)]
|
|
_result = run_program(_cmd, shell=True).stdout.decode()
|
|
# Check result
|
|
if re.search(r'No component store corruption detected', _result, re.IGNORECASE):
|
|
pass
|
|
else:
|
|
raise GenericError
|
|
else:
|
|
raise UnsupportedOSError
|
|
|
|
def run_hitmanpro():
|
|
"""Run HitmanPro in the background."""
|
|
extract_item('HitmanPro', silent=True)
|
|
_cmd = [
|
|
global_vars['Tools']['HitmanPro'],
|
|
'/quiet', '/noinstall', '/noupload',
|
|
'/log={LogDir}\\hitman.xml'.format(**global_vars)]
|
|
popen_program(_cmd)
|
|
|
|
def run_kvrt():
|
|
"""Run KVRT."""
|
|
extract_item('KVRT', silent=True)
|
|
os.makedirs(global_vars['QuarantineDir'], exist_ok=True)
|
|
_cmd = [
|
|
global_vars['Tools']['KVRT'],
|
|
'-accepteula', '-dontcryptsupportinfo', '-fixednames',
|
|
'-d', global_vars['QuarantineDir'],
|
|
'-processlevel', '3']
|
|
popen_program(_cmd, pipe=False)
|
|
|
|
def run_process_killer():
|
|
"""Kill most running processes skipping those in the whitelist.txt."""
|
|
# borrowed from TronScript (reddit.com/r/TronScript) and credit to /u/cuddlychops06
|
|
_prev_dir = os.getcwd()
|
|
extract_item('ProcessKiller', silent=True)
|
|
os.chdir('{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'],
|
|
'-l', '{LogDir}\\RKill.log'.format(**global_vars),
|
|
'-new_console:n', '-new_console:s33V']
|
|
run_program(_cmd, check=False)
|
|
wait_for_process('RKill')
|
|
kill_process('notepad.exe')
|
|
|
|
# RKill cleanup
|
|
if os.path.exists('{USERPROFILE}\\Desktop'.format(**global_vars['Env'])):
|
|
for item in os.scandir('{USERPROFILE}\\Desktop'.format(**global_vars['Env'])):
|
|
if re.search(r'^RKill', item.name, re.IGNORECASE):
|
|
_name = re.sub(r'^(.*)\.', '\1_{Date-Time}'.format(**global_vars), item.name, re.IGNORECASE)
|
|
_name = '{ClientDir}\\Info\\{name}'.format(name=_name, **global_vars)
|
|
shutil.move(item.path, non_clobber_rename(_name))
|
|
|
|
def run_sfc_scan():
|
|
"""Run SFC in a "split window" and report errors."""
|
|
_cmd = [
|
|
'{SYSTEMROOT}\\System32\\sfc.exe'.format(**global_vars['Env']),
|
|
'/scannow']
|
|
_out = run_program(_cmd, check=False)
|
|
# Save stderr
|
|
with open('{LogDir}\\SFC.err'.format(**global_vars), 'a') as f:
|
|
for line in _out.stderr.decode('utf-8', 'ignore').splitlines():
|
|
f.write(line.strip() + '\n')
|
|
# Save stdout
|
|
with open('{LogDir}\\SFC.log'.format(**global_vars), 'a') as f:
|
|
for line in _out.stdout.decode('utf-8', 'ignore').splitlines():
|
|
f.write(line.strip() + '\n')
|
|
# Check result
|
|
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):
|
|
pass
|
|
elif re.findall(r'successfully\s+repaired\s+them', log_text):
|
|
raise GenericRepair
|
|
else:
|
|
raise GenericError
|
|
|
|
def run_tdsskiller():
|
|
"""Run TDSSKiller."""
|
|
extract_item('TDSSKiller', silent=True)
|
|
os.makedirs('{QuarantineDir}\\TDSSKiller'.format(**global_vars), exist_ok=True)
|
|
_cmd = [
|
|
global_vars['Tools']['TDSSKiller'],
|
|
'-l', '{LogDir}\\TDSSKiller.log'.format(**global_vars),
|
|
'-qpath', '{QuarantineDir}\\TDSSKiller'.format(**global_vars),
|
|
'-accepteula', '-accepteulaksn',
|
|
'-dcexact', '-tdlfs']
|
|
run_program(_cmd, pipe=False)
|
|
|
|
# Windows Activation
|
|
def activate_windows_with_bios():
|
|
"""Attempt to activate Windows with a key stored in the BIOS."""
|
|
# Code borrowed from https://github.com/aeruder/get_win8key
|
|
#####################################################
|
|
#script to query windows 8.x OEM key from PC firmware
|
|
#ACPI -> table MSDM -> raw content -> byte offset 56 to end
|
|
#ck, 03-Jan-2014 (christian@korneck.de)
|
|
#####################################################
|
|
bios_key = None
|
|
table = b"MSDM"
|
|
if acpi.FindAcpiTable(table) is True:
|
|
rawtable = acpi.GetAcpiTable(table)
|
|
#http://msdn.microsoft.com/library/windows/hardware/hh673514
|
|
#byte offset 36 from beginning = Microsoft 'software licensing data structure' / 36 + 20 bytes offset from beginning = Win Key
|
|
bios_key = rawtable[56:len(rawtable)].decode("utf-8")
|
|
else:
|
|
raise Exception('ACPI table {} not found.'.format(str(table)))
|
|
if bios_key is None:
|
|
raise BIOSKeyNotFoundError
|
|
|
|
# Install Key
|
|
run_program('cscript {SYSTEMROOT}\\System32\\slmgr.vbs /ipk {pkey} //nologo'.format(**global_vars['Env'], pkey=bios_key), check=False)
|
|
sleep(5)
|
|
|
|
# Attempt activation
|
|
run_program('cscript {SYSTEMROOT}\\System32\\slmgr.vbs /ato //nologo'.format(**global_vars['Env']), check=False)
|
|
sleep(5)
|
|
|
|
# Check status
|
|
if not windows_is_activated():
|
|
raise Exception('Activation Failed')
|
|
|
|
def update_windows_activation_status():
|
|
if not re.search(r'(permanent|safe mode)', global_vars['OS']['Activation'], re.IGNORECASE):
|
|
_out = run_program('cscript /nologo {SYSTEMROOT}\\System32\\slmgr.vbs /xpr'.format(**global_vars['Env']))
|
|
_out = _out.stdout.decode().splitlines()
|
|
_out = [l for l in _out if re.match(r'^\s', l)]
|
|
if len(_out) > 0:
|
|
global_vars['OS']['Activation'] = re.sub(r'^\s+', '', _out[0])
|
|
else:
|
|
global_vars['OS']['Activation'] = 'Activation status unknown'
|
|
|
|
def windows_is_activated():
|
|
"""Updates activation status, checks if activated, and returns a bool."""
|
|
update_windows_activation_status()
|
|
return re.search(r'permanent', global_vars['OS']['Activation'], re.IGNORECASE)
|
|
|
|
# System Info
|
|
def backup_file_list():
|
|
"""Export current file listing for the system."""
|
|
extract_item('Everything', silent=True)
|
|
_cmd = [
|
|
global_vars['Tools']['Everything'],
|
|
'-nodb',
|
|
'-create-filelist',
|
|
'{LogDir}\\File List.txt'.format(**global_vars),
|
|
'{SYSTEMDRIVE}'.format(**global_vars['Env'])]
|
|
run_program(_cmd)
|
|
|
|
def backup_power_plans():
|
|
"""Export current power plans."""
|
|
os.makedirs('{BackupDir}\\Power Plans'.format(**global_vars), exist_ok=True)
|
|
_plans = run_program('powercfg /L')
|
|
_plans = _plans.stdout.decode().splitlines()
|
|
_plans = [p for p in _plans if re.search(r'^Power Scheme', p)]
|
|
for p in _plans:
|
|
_guid = re.sub(r'Power Scheme GUID:\s+([0-9a-f\-]+).*', r'\1', p)
|
|
_name = re.sub(r'Power Scheme GUID:\s+[0-9a-f\-]+\s+\(([^\)]+)\).*', r'\1', p)
|
|
# print(' {name} ({guid})'.format(guid=_guid, name=_name))
|
|
_out = '{BackupDir}\\Power Plans\\{name}.pow'.format(name=_name, **global_vars)
|
|
if not os.path.exists(_out):
|
|
_cmd = ['powercfg', '-export', _out, _guid]
|
|
run_program(_cmd, check=False)
|
|
|
|
def backup_registry():
|
|
extract_item('erunt', silent=True)
|
|
_args = [
|
|
'{LogDir}\\Registry'.format(**global_vars),
|
|
'sysreg',
|
|
'curuser',
|
|
'otherusers',
|
|
'/noprogresswindow']
|
|
run_program(global_vars['Tools']['ERUNT'], _args)
|
|
|
|
def compress_info():
|
|
path = '{ClientDir}'.format(**global_vars)
|
|
file = 'Info_{Date-Time}.7z'.format(**global_vars)
|
|
_cmd = [
|
|
global_vars['Tools']['SevenZip'],
|
|
'a', '-t7z', '-mx=9', '-bso0', '-bse0',
|
|
'{path}\\{file}'.format(path=path, file=file),
|
|
'{ClientDir}\\Info'.format(**global_vars)]
|
|
run_program(_cmd)
|
|
|
|
def find_software_hives():
|
|
"""Search for transferred SW hives and return a list."""
|
|
hives = []
|
|
search_paths = [global_vars['ClientDir']]
|
|
|
|
while len(search_paths) > 0:
|
|
for item in os.scandir(search_paths.pop(0)):
|
|
if item.is_dir() and REGEX_REGISTRY_DIRS.search(item.name):
|
|
search_paths.append(item.path)
|
|
if item.is_file() and REGEX_SOFTWARE_HIVE.search(item.name):
|
|
hives.append(item.path)
|
|
|
|
return hives
|
|
|
|
def get_installed_office():
|
|
programs = []
|
|
with open ('{LogDir}\\Installed Program List (AIDA64).txt'.format(**global_vars), 'r') as f:
|
|
for line in sorted(f.readlines()):
|
|
if REGEX_OFFICE.search(line):
|
|
programs.append(line[4:82].strip())
|
|
|
|
if len(programs) == 0:
|
|
programs = ['No programs found']
|
|
return programs
|
|
|
|
def get_product_keys():
|
|
keys = []
|
|
|
|
with open ('{LogDir}\\Product Keys (ProduKey).txt'.format(**global_vars), 'r') as f:
|
|
for line in f.readlines():
|
|
if re.search(r'^Product Name', line):
|
|
line = re.sub(r'^Product Name\s+:\s+(.*)', r'\1', line.strip())
|
|
keys.append(line)
|
|
|
|
if len(keys) == 0:
|
|
keys = ['No product keys found']
|
|
return keys
|
|
|
|
def get_user_data_size_info(all_users=True, indent=8, width=32):
|
|
"""Get size of user folders for all users and return a dict of dicts."""
|
|
users = {}
|
|
TMP_HIVE_PATH = 'HKU\\wk_tmp'
|
|
# Extract and configure du
|
|
extract_item('SysinternalsSuite', filter='du*', silent=True)
|
|
winreg.CreateKey(winreg.HKEY_CURRENT_USER, r'Software\Sysinternals\Du')
|
|
with winreg.OpenKey(winreg.HKEY_CURRENT_USER, r'Software\Sysinternals\Du', access=winreg.KEY_WRITE) as _key:
|
|
winreg.SetValueEx(_key, 'EulaAccepted', 0, winreg.REG_DWORD, 1)
|
|
|
|
try:
|
|
# Get SIDs
|
|
if all_users:
|
|
out = run_program('wmic useraccount get sid')
|
|
else:
|
|
out = run_program('wmic useraccount where name="{USERNAME}" get sid'.format(**global_vars['Env']))
|
|
sids = out.stdout.decode().splitlines()
|
|
sids = [s.strip() for s in sids if re.search(r'-1\d+$', s.strip())]
|
|
|
|
# Get Usernames and add to _users
|
|
for sid in sids:
|
|
try:
|
|
out = run_program('wmic useraccount where sid="{sid}" get name'.format(sid=sid))
|
|
name = out.stdout.decode().splitlines()[2].strip()
|
|
users[name] = {'Extra Folders': {}, 'Shell Folders': {}, 'SID': sid}
|
|
except:
|
|
# Just skip problem users
|
|
pass
|
|
except subprocess.CalledProcessError:
|
|
# This results in an empty dict being returned, leaving it to the calling section to handle that case
|
|
pass
|
|
|
|
# Use username/SID pairs to check profile folder sizes
|
|
for u in users.keys():
|
|
try:
|
|
# Main Profile path
|
|
key = r'SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList\{SID}'.format(**users[u])
|
|
with winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, key) as _key:
|
|
users[u]['ProfileImagePath'] = winreg.QueryValueEx(_key, 'ProfileImagePath')[0]
|
|
try:
|
|
out = run_program(global_vars['Tools']['Du'], ['-nobanner', '-q', users[u]['ProfileImagePath']])
|
|
size = out.stdout.decode().splitlines()[4]
|
|
size = re.sub(r'Size:\s+([\d,]+)\sbytes$', r'\1', size)
|
|
size = size.replace(',', '')
|
|
size = human_readable_size(size)
|
|
size_str = '{indent}{folder:<{width}}{size:>6} ({path})'.format(
|
|
indent = ' ' * indent,
|
|
width = width,
|
|
folder = 'Profile',
|
|
size = size,
|
|
path = users[u]['ProfileImagePath'])
|
|
users[u]['ProfileSize'] = size_str
|
|
except subprocess.CalledProcessError:
|
|
# Failed to get folder size
|
|
pass
|
|
|
|
# Check if user hive is already loaded
|
|
unload_hive = False
|
|
try:
|
|
# This tests if the user hive is already loaded and throws FileNotFoundError if not.
|
|
winreg.QueryValue(winreg.HKEY_USERS, users[u]['SID'])
|
|
except FileNotFoundError:
|
|
# User not logged-in. Loading hive and setting unload_hive so it will be unloaded before the script exits.
|
|
try:
|
|
_cmd = 'reg load {tmp_path} "{ProfileImagePath}\\NTUSER.DAT"'.format(tmp_path=TMP_HIVE_PATH, **users[u])
|
|
run_program(_cmd)
|
|
unload_hive = True
|
|
except subprocess.CalledProcessError:
|
|
# Failed to load user hive
|
|
pass
|
|
|
|
# Get Shell folder sizes
|
|
key = r'{SID}\Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders'.format(**users[u])
|
|
try:
|
|
with winreg.OpenKey(winreg.HKEY_USERS, key) as _key:
|
|
for folder in SHELL_FOLDERS.keys():
|
|
for value in SHELL_FOLDERS[folder]:
|
|
try:
|
|
# Query value and break out of for look if successful
|
|
folder_path = winreg.QueryValueEx(_key, value)[0]
|
|
try:
|
|
# Finally calculate folder size
|
|
out = run_program(global_vars['Tools']['Du'], ['-nobanner', '-q', folder_path])
|
|
size = out.stdout.decode().splitlines()[4]
|
|
size = re.sub(r'Size:\s+([\d,]+)\sbytes$', r'\1', size)
|
|
size = size.replace(',', '')
|
|
size = human_readable_size(size)
|
|
str = '{indent}{folder:<{width}}{size:>6} ({path})'.format(
|
|
indent = ' ' * indent,
|
|
width = width,
|
|
folder = folder,
|
|
size = size,
|
|
path = folder_path)
|
|
users[u]['Shell Folders'][folder] = str
|
|
except subprocess.CalledProcessError:
|
|
# Failed to get folder size
|
|
pass
|
|
break
|
|
except FileNotFoundError:
|
|
# Failed to query value above
|
|
pass
|
|
except FileNotFoundError:
|
|
# Can't read the user hive, skipping this user.
|
|
pass
|
|
|
|
# Extra shell folder check
|
|
for folder in SHELL_FOLDERS.keys():
|
|
if folder not in users[u]['Shell Folders']:
|
|
folder_path = '{ProfileImagePath}\\{folder}'.format(folder=folder, **users[u])
|
|
if os.path.exists(folder_path):
|
|
try:
|
|
out = run_program(global_vars['Tools']['Du'], ['-nobanner', '-q', folder_path])
|
|
size = out.stdout.decode().splitlines()[4]
|
|
size = re.sub(r'Size:\s+([\d,]+)\sbytes$', r'\1', size)
|
|
size = size.replace(',', '')
|
|
size = human_readable_size(size)
|
|
str = '{indent}{folder:<{width}}{size:>6} ({path})'.format(
|
|
indent = ' ' * indent,
|
|
width = width,
|
|
folder = folder,
|
|
size = size,
|
|
path = folder_path)
|
|
users[u]['Shell Folders'][folder] = str
|
|
except subprocess.CalledProcessError:
|
|
# Failed to get folder size
|
|
pass
|
|
|
|
# Extra folder sizes
|
|
for folder in EXTRA_FOLDERS:
|
|
folder_path = '{ProfileImagePath}\\{folder}'.format(folder=folder, **users[u])
|
|
if os.path.exists(folder_path):
|
|
try:
|
|
out = run_program(global_vars['Tools']['Du'], ['-nobanner', '-q', folder_path])
|
|
size = size.stdout.decode().splitlines()[4]
|
|
size = re.sub(r'Size:\s+([\d,]+)\sbytes$', r'\1', size)
|
|
size = size.replace(',', '')
|
|
size = human_readable_size(size)
|
|
str = '{indent}{folder:<{width}}{size:>6} ({path})'.format(
|
|
indent = ' ' * indent,
|
|
width = width,
|
|
folder = folder,
|
|
size = size,
|
|
path = folder_path)
|
|
users[u]['Extra Folders'][folder] = str
|
|
except subprocess.CalledProcessError:
|
|
# Failed to get folder size
|
|
pass
|
|
# Unload user hive (if necessary)
|
|
if unload_hive:
|
|
_cmd = 'reg unload {tmp_path}'.format(tmp_path=TMP_HIVE_PATH)
|
|
run_program(_cmd, check=False)
|
|
|
|
except FileNotFoundError:
|
|
# Can't find the ProfileImagePath, skipping this user.
|
|
pass
|
|
except:
|
|
# Unload the wk_tmp hive no matter what
|
|
_cmd = 'reg unload {tmp_path}'.format(tmp_path=TMP_HIVE_PATH)
|
|
run_program(_cmd, check=False)
|
|
# Done
|
|
return users
|
|
|
|
def run_aida64():
|
|
extract_item('AIDA64', silent=True)
|
|
# All system info
|
|
if not os.path.exists('{LogDir}\\System Information (AIDA64).html'.format(**global_vars)):
|
|
_cmd = [
|
|
global_vars['Tools']['AIDA64'],
|
|
'/R', '{LogDir}\\System Information (AIDA64).html'.format(**global_vars),
|
|
'/CUSTOM', '{BinDir}\\AIDA64\\full.rpf'.format(**global_vars),
|
|
'/HTML', '/SILENT', '/SAFEST']
|
|
run_program(_cmd, check=False)
|
|
|
|
# Installed Programs
|
|
if not os.path.exists('{LogDir}\\Installed Program List (AIDA64).txt'.format(**global_vars)):
|
|
_cmd = [
|
|
global_vars['Tools']['AIDA64'],
|
|
'/R', '{LogDir}\\Installed Program List (AIDA64).txt'.format(**global_vars),
|
|
'/CUSTOM', '{BinDir}\\AIDA64\\installed_programs.rpf'.format(**global_vars),
|
|
'/TEXT', '/SILENT', '/SAFEST']
|
|
run_program(_cmd, check=False)
|
|
|
|
# Product Keys
|
|
if not os.path.exists('{LogDir}\\Product Keys (AIDA64).txt'.format(**global_vars)):
|
|
_cmd = [
|
|
global_vars['Tools']['AIDA64'],
|
|
'/R', '{LogDir}\\Product Keys (AIDA64).txt'.format(**global_vars),
|
|
'/CUSTOM', '{BinDir}\\AIDA64\\licenses.rpf'.format(**global_vars),
|
|
'/TEXT', '/SILENT', '/SAFEST']
|
|
run_program(_cmd, check=False)
|
|
|
|
def run_bleachbit():
|
|
if not os.path.exists('{LogDir}\\BleachBit.log'.format(**global_vars)):
|
|
extract_item('BleachBit', silent=True)
|
|
_cmd = [global_vars['Tools']['BleachBit'], '--preview', '--preset']
|
|
_out = run_program(_cmd, check=False)
|
|
# Save stderr
|
|
if len(_out.stderr.decode().splitlines()) > 0:
|
|
with open('{LogDir}\\BleachBit.err'.format(**global_vars), 'a') as f:
|
|
for line in _out.stderr.decode().splitlines():
|
|
f.write(line.strip() + '\n')
|
|
# Save stdout
|
|
with open('{LogDir}\\BleachBit.log'.format(**global_vars), 'a') as f:
|
|
for line in _out.stdout.decode().splitlines():
|
|
f.write(line.strip() + '\n')
|
|
|
|
def run_hwinfo_sensors():
|
|
_path = '{BinDir}\\HWiNFO'.format(**global_vars)
|
|
for bit in [32, 64]:
|
|
# Configure
|
|
_source = '{path}\\general.ini'.format(path=_path)
|
|
_dest = '{path}\\HWiNFO{bit}.ini'.format(bit=bit, path=_path)
|
|
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_produkey():
|
|
extract_item('ProduKey', silent=True)
|
|
if not os.path.exists('{LogDir}\\Product Keys (ProduKey).txt'.format(**global_vars)):
|
|
# Clear current configuration
|
|
for config in ['ProduKey.cfg', 'ProduKey64.cfg']:
|
|
try:
|
|
if os.path.exists('{BinDir}\\ProduKey\\{config}'.format(config=config, **global_vars)):
|
|
os.remove('{BinDir}\\ProduKey\\{config}'.format(config=config, **global_vars))
|
|
except:
|
|
pass
|
|
_cmd = [
|
|
global_vars['Tools']['ProduKey'], '/nosavereg',
|
|
'/stext', '{LogDir}\\Product Keys (ProduKey).txt'.format(**global_vars)]
|
|
run_program(_cmd, check=False)
|
|
|
|
def run_xmplay():
|
|
extract_item('XMPlay', silent=True)
|
|
popen_program([global_vars['Tools']['XMPlay'], '{BinDir}\\XMPlay\\music.7z'.format(**global_vars)])
|
|
|
|
def show_disk_usage(disk=None):
|
|
if disk is None:
|
|
raise Exception
|
|
print_standard(disk.device.replace('\\', ' '), end='', flush=True, timestamp=False)
|
|
try:
|
|
usage = psutil.disk_usage(disk.device)
|
|
display_string = '{percent:>5.2f}% Free ({free} / {total})'.format(
|
|
percent = 100 - usage.percent,
|
|
free = human_readable_size(usage.free, 2),
|
|
total = human_readable_size(usage.total, 2))
|
|
if usage.percent > 85:
|
|
print_error(display_string, timestamp=False)
|
|
elif usage.percent > 75:
|
|
print_warning(display_string, timestamp=False)
|
|
else:
|
|
print_standard(display_string, timestamp=False)
|
|
except:
|
|
print_warning('Unknown', timestamp=False)
|
|
|
|
def show_free_space():
|
|
"""Show free space info for all fixed disks."""
|
|
message = 'Free Space:'
|
|
for disk in psutil.disk_partitions():
|
|
try:
|
|
if 'fixed' in disk.opts:
|
|
try_and_print(disk=disk, message=message, function=show_disk_usage, ns='Unknown', silent_function=False)
|
|
message = ''
|
|
except:
|
|
pass
|
|
|
|
def show_installed_ram():
|
|
mem = psutil.virtual_memory()
|
|
if mem.total > 5905580032:
|
|
# > 5.5 Gb so 6Gb or greater
|
|
print_standard(human_readable_size(mem.total).strip())
|
|
elif mem.total > 3758096384:
|
|
# > 3.5 Gb so 4Gb or greater
|
|
print_warning(human_readable_size(mem.total).strip())
|
|
else:
|
|
print_error(human_readable_size(mem.total).strip())
|
|
|
|
def show_os_activation():
|
|
act_str = global_vars['OS']['Activation']
|
|
if re.search(r'permanent', act_str, re.IGNORECASE):
|
|
print_standard(act_str, timestamp=False)
|
|
elif re.search(r'unavailable', act_str, re.IGNORECASE):
|
|
print_warning(act_str, timestamp=False)
|
|
else:
|
|
print_error(act_str, timestamp=False)
|
|
|
|
def show_os_name():
|
|
os_name = global_vars['OS']['DisplayName']
|
|
if global_vars['OS']['Arch'] == 32:
|
|
# Show all 32-bit installs as an error message
|
|
print_error(os_name, timestamp=False)
|
|
else:
|
|
if re.search(r'(unrecognized|very outdated)', 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:
|
|
print_standard(os_name, timestamp=False)
|
|
|
|
def show_temp_files_size():
|
|
# Temp file size
|
|
size = None
|
|
with open('{LogDir}\\BleachBit.log'.format(**global_vars), 'r') as f:
|
|
for line in f.readlines():
|
|
if re.search(r'^disk space to be recovered:', line, re.IGNORECASE):
|
|
size = re.sub(r'.*: ', '', line.strip())
|
|
size = re.sub(r'(\w)iB$', r' \1b', size)
|
|
if size is None:
|
|
print_warning(size, timestamp=False)
|
|
else:
|
|
print_standard(size, timestamp=False)
|
|
|
|
def show_user_data_summary(all_users=True, indent=8, width=32):
|
|
users = get_user_data_size_info(all_users)
|
|
for user in sorted(users.keys()):
|
|
print_success(' User: {user}'.format(user=user))
|
|
print_standard(users[user].get('ProfileSize', 'Unknown'))
|
|
print_standard('{}{}'.format(' '*indent, '-'*(width+6)))
|
|
for folder in sorted(users[user]['Shell Folders']):
|
|
print_standard(users[user]['Shell Folders'][folder])
|
|
for folder in sorted(users[user]['Extra Folders']):
|
|
print_standard(users[user]['Shell Folders'][folder])
|
|
|
|
def upload_info():
|
|
path = '{ClientDir}'.format(**global_vars)
|
|
file = 'Info_{Date-Time}.7z'.format(**global_vars)
|
|
upload_data(path, file)
|
|
|
|
if __name__ == '__main__':
|
|
print("This file is not meant to be called directly.")
|