Updated info.py

This commit is contained in:
2Shirt 2018-12-27 19:57:39 -07:00
parent 166a293864
commit 097fae866a
Signed by: 2Shirt
GPG key ID: 152FAC923B0E132C

View file

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