# Migration to Python started #
* PoSH has an extreme slowdown for some systems while it runs an optimization
** pass for .NET on the first PoSH script execution.
** This is reason enough to move to an alternative.
* New additions:
* User Data Transfer script
* Will extract from a WIM or copy from a folder
* Uses wimlib-imagex for images and FastCopy for folders
* Removes undesired items after transfer/extraction
* HWiNFO
* Missing ODD repair registry patch
* Q-Dir
* SW Bundle install script
* ConEmu
* Moving back to ConEmu for better performance.
* Copy-WizardKit
* Now uses FastCopy
* functions.py
* Ported init.ps1 to Python using functions.py (from WinPE) as a base
* Launch.cmd
* Elevating programs/scripts now done using a temp VBScript file
* Can run Python scripts (using either the 32 or 64 bit runtime)
* transferred_keys.cmd
* Expanded searched paths
* Misc
* Lots of variables and files renamed
* Lots of hard-coded paths are now in variables
* Should only be set in scripts in %bin%\Scripts
* Moved a subset of the Diagnostics launchers to a new 'Extras' folder
* The launchers moved are those that are less-often used
* Refactored FindBin code to be more concise
* Renamed "KitDir" "ClientDir" to indicate that it is on the client's system
* Removed GeForce Experience launcher as it now requires an account
* Added link to NVIDIA's driver webpage to download the correct driver
* Removed AMD's Gaming Evolved launcher
* This is usually bundled with the GPU driver anyway
* Switched back to ConEmu
* Variable and script names are now more descriptive
* i.e. checklist -> final_checklist, and HH -> %kit_dir%
* (not happy with %kit_dir%, will probably change again)
248 lines
No EOL
12 KiB
Python
248 lines
No EOL
12 KiB
Python
# Wizard Kit: Copy user data to the system over the network
|
|
|
|
import os
|
|
import re
|
|
from operator import itemgetter
|
|
|
|
# Init
|
|
os.chdir(os.path.dirname(os.path.realpath(__file__)))
|
|
os.system('title Wizard Kit: Data 1')
|
|
from functions import *
|
|
vars = init_vars()
|
|
vars_os = init_vars_os()
|
|
vars['LogFile'] = '{LogDir}\\Data 1.log'.format(**vars)
|
|
os.makedirs('{LogDir}'.format(**vars), exist_ok=True)
|
|
vars['TransferDir'] = '{ClientDir}\\Transfer\\'.format(**vars)
|
|
os.makedirs('{TransferDir}'.format(**vars), exist_ok=True)
|
|
vars['FastCopy'] = '{BinDir}\\FastCopy\\FastCopy.exe'.format(**vars)
|
|
vars['FastCopyArgs'] = [
|
|
'/cmd=noexist_only',
|
|
'/logfile={LogFile}'.format(**vars),
|
|
'/utf8',
|
|
'/skip_empty_dir',
|
|
'/linkdest',
|
|
'/no_ui',
|
|
'/auto_close',
|
|
'/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']
|
|
vars['Notepad2'] = '{BinDir}\\Notepad2\\Notepad2-Mod.exe'.format(**vars)
|
|
vars['wimlib-imagex'] = '{BinDir}\\wimlib\\x32\\wimlib-imagex.exe'.format(**vars)
|
|
if vars_os['Arch'] == 64:
|
|
vars['FastCopy'] = vars['FastCopy'].replace('FastCopy.exe', 'FastCopy64.exe')
|
|
vars['Notepad2'] = vars['Notepad2'].replace('Notepad2-Mod.exe', 'Notepad2-Mod64.exe')
|
|
vars['wimlib-imagex'] = vars['wimlib-imagex'].replace('x32', 'x64')
|
|
re_included_root_items = re.compile(r'(^\\((My\s*)|Downloads|Doc(uments?|s?)|WK(-Info|-Transfer|)|Media|Music|Pictures?|Videos?)$|^\\(ProgramData|Recovery|Temp.*|Users)$|(log|txt|rtf|qb\w*|avi|m4a|m4v|mp4|mkv|jpg|png|tiff?)$)', flags=re.IGNORECASE)
|
|
re_excluded_root_items = re.compile(r'(^\\boot(mgr|nxt)$|^\\(eula|globdata|install|vc_?red)|.*.sys$|^\\System Volume Information|RECYCLER|\$Recycle\.bin|^\\\$?Win(dows(.old|\.~BT|)$|RE_)|^\\PerfLogs|^\\Program Files|\.(esd|swm|wim|dd|map|dmg|image)$)', flags=re.IGNORECASE)
|
|
re_excluded_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)
|
|
|
|
def abort():
|
|
print_warning('Aborted.', log_file=vars['LogFile'])
|
|
exit_script()
|
|
|
|
def cleanup_transfer():
|
|
"""Walk through transfer folder (from the bottom) and remove extraneous items."""
|
|
if os.path.exists(vars['TransferDir']):
|
|
for root, dirs, files in os.walk(vars['TransferDir'], topdown=False):
|
|
for name in dirs:
|
|
try:
|
|
# Removes empty directories and junction points
|
|
os.rmdir(os.path.join(root, name))
|
|
except OSError:
|
|
pass
|
|
for name in files:
|
|
if re_excluded_items.search(name):
|
|
try:
|
|
# Removes files based on exclusion regex
|
|
os.remove(os.path.join(root, name))
|
|
except OSError:
|
|
pass
|
|
|
|
def exit_script():
|
|
umount_backup_shares()
|
|
pause("Press Enter to exit...")
|
|
subprocess.Popen('"{Notepad2}" "{LogFile}"'.format(**vars))
|
|
quit()
|
|
|
|
def is_valid_image(item):
|
|
_valid = item.is_file() and re.search(r'\.wim$', item.name, flags=re.IGNORECASE)
|
|
if _valid:
|
|
try:
|
|
_cmd = [vars['wimlib-imagex'], 'info', '{image}'.format(image=item.path)]
|
|
run_program(_cmd)
|
|
except subprocess.CalledProcessError:
|
|
_valid = False
|
|
print_warning('WARNING: Image damaged.', log_file=vars['LogFile'])
|
|
time.sleep(2)
|
|
return _valid
|
|
|
|
def transfer_file_based(restore_source):
|
|
# Registry
|
|
_args = vars['FastCopyArgs'].copy()
|
|
if os.path.exists('{source}\\Windows\\System32\\config'.format(source=restore_source.path)):
|
|
_args.append('{source}\\Windows\\System32\\config'.format(source=restore_source.path))
|
|
if os.path.exists('{source}\\Windows\\System32\\OEM'.format(source=restore_source.path)):
|
|
_args.append('{source}\\Windows\\System32\\OEM'.format(source=restore_source.path))
|
|
_args.append('/to={TransferDir}\\Windows\\System32\\'.format(**vars))
|
|
try:
|
|
print_standard('Copying Windows Registry...', log_file=vars['LogFile'])
|
|
run_program(vars['FastCopy'], _args, check=True)
|
|
except subprocess.CalledProcessError:
|
|
print_warning('WARNING: Errors encountered while copying registry', log_file=vars['LogFile'])
|
|
|
|
# Registry (Windows.old)
|
|
_args = vars['FastCopyArgs'].copy()
|
|
if os.path.exists('{source}\\Windows.old\\Windows\\System32\\config'.format(source=restore_source.path)):
|
|
_args.append('{source}\\Windows.old\\Windows\\System32\\config'.format(source=restore_source.path))
|
|
if os.path.exists('{source}\\Windows.old\\Windows\\System32\\OEM'.format(source=restore_source.path)):
|
|
_args.append('{source}\\Windows.old\\Windows\\System32\\OEM'.format(source=restore_source.path))
|
|
_args.append('/to={TransferDir}\\Windows.old\\Windows\\System32\\'.format(**vars))
|
|
try:
|
|
print_standard('Copying Windows Registry...', log_file=vars['LogFile'])
|
|
run_program(vars['FastCopy'], _args, check=True)
|
|
except subprocess.CalledProcessError:
|
|
print_warning('WARNING: Errors encountered while copying registry', log_file=vars['LogFile'])
|
|
|
|
# Main copy
|
|
selected_items = []
|
|
for item in os.scandir(restore_source.path):
|
|
if re_included_root_items.search(item.name):
|
|
selected_items.append(item.path)
|
|
elif not re_excluded_root_items.search(item.name):
|
|
if ask('Copy: "{name}" item?'.format(name=item.name)):
|
|
selected_items.append(item.path)
|
|
if len(selected_items) > 0:
|
|
_args = vars['FastCopyArgs'].copy()
|
|
_args += selected_items
|
|
_args.append('/to={TransferDir}\\'.format(**vars))
|
|
try:
|
|
print_standard('Copying main user data...', log_file=vars['LogFile'])
|
|
run_program(vars['FastCopy'], _args, check=True)
|
|
except subprocess.CalledProcessError:
|
|
print_warning('WARNING: Errors encountered while copying main user data', log_file=vars['LogFile'])
|
|
else:
|
|
print_error('ERROR: No files selected for transfer?', log_file=vars['LogFile'])
|
|
abort()
|
|
|
|
# Windows.old
|
|
selected_items = []
|
|
for item in ['Users', 'ProgramData']:
|
|
item = '{source}\\Windows.old\\{item}'.format(source=restore_source.path, item=item)
|
|
if os.path.exists(item):
|
|
selected_items.append(item)
|
|
if len(selected_items) > 0:
|
|
_args = vars['FastCopyArgs'].copy()
|
|
_args += selected_items
|
|
_args.append('/to={TransferDir}\\Windows.old\\'.format(**vars))
|
|
try:
|
|
print_standard('Copying user data (Windows.old)...', log_file=vars['LogFile'])
|
|
run_program(vars['FastCopy'], _args, check=True)
|
|
except subprocess.CalledProcessError:
|
|
print_warning('WARNING: Errors encountered while copying data from Windows.old', log_file=vars['LogFile'])
|
|
|
|
def transfer_image_based(restore_source):
|
|
print_standard('Assessing image...', log_file=vars['LogFile'])
|
|
|
|
# Scan source
|
|
_args = [
|
|
'dir',
|
|
'{source}'.format(source=restore_source.path), '1']
|
|
try:
|
|
_list = run_program(vars['wimlib-imagex'], _args, check=True)
|
|
except subprocess.CalledProcessError as err:
|
|
print_error('ERROR: Failed to get file list.')
|
|
print(err)
|
|
abort()
|
|
|
|
# Add items to list
|
|
selected_items = []
|
|
root_items = [i.strip() for i in _list.stdout.decode('utf-8', 'ignore').splitlines() if i.count('\\') == 1 and i.strip() != '\\']
|
|
for item in root_items:
|
|
if re_included_root_items.search(item):
|
|
selected_items.append(item)
|
|
elif not re_excluded_root_items.search(item):
|
|
if ask('Extract: "{name}" item?'.format(name=item)):
|
|
selected_items.append(item)
|
|
|
|
# Extract files
|
|
if len(selected_items) > 0:
|
|
# Write files.txt
|
|
with open('{TmpDir}\\wim_files.txt'.format(**vars), 'w') as f:
|
|
# Defaults
|
|
f.write('\\Windows.old\\WK*\n')
|
|
f.write('\\Windows.old\\ProgramData\n')
|
|
f.write('\\Windows.old\\Temp\n')
|
|
f.write('\\Windows.old\\Users\n')
|
|
f.write('\\Windows.old\\Windows\\System32\\config\n')
|
|
f.write('\\Windows.old\\Windows\\System32\\OEM\n')
|
|
f.write('\\Windows\\System32\\config\n')
|
|
f.write('\\Windows\\System32\\OEM\n')
|
|
f.write('AdwCleaner\\*log\n')
|
|
f.write('AdwCleaner\\*txt\n')
|
|
for item in selected_items:
|
|
f.write('{item}\n'.format(item=item))
|
|
try:
|
|
print_standard('Extracting user data...', log_file=vars['LogFile'])
|
|
_args = [
|
|
'extract',
|
|
'{source}'.format(source=restore_source.path), '1',
|
|
'@{TmpDir}\\wim_files.txt'.format(**vars),
|
|
'--dest-dir={TransferDir}\\'.format(**vars),
|
|
'--no-acls',
|
|
'--nullglob']
|
|
run_program(vars['wimlib-imagex'], _args, check=True)
|
|
except subprocess.CalledProcessError:
|
|
print_warning('WARNING: Errors encountered while extracting user data', log_file=vars['LogFile'])
|
|
else:
|
|
print_error('ERROR: No files selected for extraction?', log_file=vars['LogFile'])
|
|
abort()
|
|
|
|
if __name__ == '__main__':
|
|
# Set ticket number
|
|
ticket = None
|
|
while ticket is None:
|
|
tmp = input('Enter ticket number: ')
|
|
if re.match(r'^([0-9]+([-_]?\w+|))$', tmp):
|
|
ticket = tmp
|
|
|
|
# Get backup
|
|
backup_source = select_backup(ticket)
|
|
if backup_source is None:
|
|
abort()
|
|
|
|
# Determine restore method
|
|
restore_source = None
|
|
restore_options = []
|
|
_file_based = False
|
|
for item in os.scandir(backup_source.path):
|
|
if item.is_dir():
|
|
_file_based = True
|
|
restore_options.append({'Name': 'File-Based:\t{source}'.format(source=item.name), 'Source': item})
|
|
for _subitem in os.scandir(item.path):
|
|
if is_valid_image(_subitem):
|
|
restore_options.append({'Name': 'Image-Based: {dir}\\{source}'.format(dir=item.name, source=_subitem.name), 'Source': _subitem})
|
|
elif is_valid_image(item):
|
|
restore_options.append({'Name': 'Image-Based:\t{source}'.format(source=item.name), 'Source': item})
|
|
if _file_based:
|
|
restore_options.append({'Name': 'File-Based:\t.', 'Source': backup_source})
|
|
restore_options = sorted(restore_options, key=itemgetter('Name'))
|
|
actions = [{'Name': 'Quit', 'Letter': 'Q'}]
|
|
if len(restore_options) > 0:
|
|
selection = menu_select('Which backup are we using? (Path: {path})'.format(path=backup_source.path), restore_options, actions)
|
|
if selection == 'Q':
|
|
abort()
|
|
else:
|
|
restore_source = restore_options[int(selection)-1]['Source']
|
|
else:
|
|
print_error('ERROR: No restoration options detected.', log_file=vars['LogFile'])
|
|
abort()
|
|
|
|
# Start transfer
|
|
print_info('Using backup: {path}'.format(path=restore_source.path), log_file=vars['LogFile'])
|
|
if restore_source.is_dir():
|
|
transfer_file_based(restore_source)
|
|
if restore_source.is_file():
|
|
transfer_image_based(restore_source)
|
|
cleanup_transfer()
|
|
|
|
# Done
|
|
print_success('Done.', log_file=vars['LogFile'])
|
|
exit_script() |