From 337b6d95e1b5b978ec71c8a177b38649c883051b Mon Sep 17 00:00:00 2001 From: 2Shirt <2xShirt@gmail.com> Date: Wed, 29 Sep 2021 00:59:06 -0600 Subject: [PATCH] Add activation and Secure Boot sections --- scripts/auto_setup.py | 4 +- scripts/wk/os/win.py | 128 ++++++++++++++++++++++++++++++++++------ scripts/wk/setup/win.py | 25 ++++++-- 3 files changed, 132 insertions(+), 25 deletions(-) diff --git a/scripts/auto_setup.py b/scripts/auto_setup.py index e30b39e7..5d614f33 100644 --- a/scripts/auto_setup.py +++ b/scripts/auto_setup.py @@ -138,8 +138,8 @@ BASE_MENUS = { ), 'System Summary': ( MenuEntry('Operating System', 'auto_show_os_name'), - MenuEntry('Windows Activation', no_op), - MenuEntry('Secure Boot', no_op), + MenuEntry('Windows Activation', 'auto_show_activation'), + MenuEntry('Secure Boot', 'auto_show_secure_boot_status'), MenuEntry('Installed RAM', no_op), MenuEntry('Storage Volumes', no_op), MenuEntry('Virus Protection', no_op), diff --git a/scripts/wk/os/win.py b/scripts/wk/os/win.py index 4fa96574..41b52a26 100644 --- a/scripts/wk/os/win.py +++ b/scripts/wk/os/win.py @@ -1,6 +1,7 @@ """WizardKit: Windows Functions""" # vim: sts=2 sw=2 ts=2 +import ctypes import logging import os import pathlib @@ -16,6 +17,7 @@ except ImportError as err: raise err from wk.borrowed import acpi +from wk.cfg.main import KIT_NAME_FULL from wk.cfg.windows_builds import ( OLDEST_SUPPORTED_BUILD, OUTDATED_BUILD_NUMBERS, @@ -126,9 +128,40 @@ def is_activated(): return act_str and 'permanent' in act_str -# System Info Functions -def show_os_name(check=True): - """Build OS display name and print it to screen. +# Date / Time functions +def get_timezone(): + """Get current timezone using tzutil, returns str.""" + cmd = ['tzutil', '/g'] + proc = run_program(cmd, check=False) + return proc.stdout + + +def set_timezone(zone): + """Set current timezone using tzutil.""" + cmd = ['tzutil', '/s', zone] + run_program(cmd, check=False) + + +# Info Functions +def get_os_activation(as_list=False, check=True): + """Get OS activation status, returns str. + + NOTE: If check=True then raise an exception if OS isn't activated. + """ + act_str = get_activation_string() + + if check and not is_activated(): + if 'unavailable' in act_str.lower(): + raise GenericWarning(act_str) + # Else + raise GenericError(act_str) + + # Done + return [act_str] if as_list else act_str + + +def get_os_name(as_list=False, check=True): + """Build OS display name, returns str. NOTE: If check=True then an exception is raised if the OS version is outdated or unsupported. @@ -150,7 +183,14 @@ def show_os_name(check=True): raise GenericError(f'{display_name} (unsupported)') # Done - print(display_name) + return [display_name] if as_list else display_name + + +def show_alert_box(message, title=None): + """Show Windows alert box with message.""" + title = title if title else f'{KIT_NAME_FULL} Warning' + message_box = ctypes.windll.user32.MessageBoxW + message_box(None, message, title, 0x00001030) # Registry Functions @@ -381,6 +421,72 @@ def enable_safemode_msi(): run_program(cmd) +# Secure Boot Functions +def is_booted_uefi(): + """Check if booted UEFI or legacy, returns bool.""" + kernel = ctypes.windll.kernel32 + firmware_type = ctypes.c_uint() + + # Get value from kernel32 API (firmware_type is updated by the call) + try: + kernel.GetFirmwareType(ctypes.byref(firmware_type)) + except Exception: # pylint: disable=broad-except + # Ignore and set firmware_type back to zero + firmware_type = ctypes.c_uint(0) + + # Check result + return firmware_type.value == 2 + + +def is_secure_boot_enabled(raise_exceptions=False, show_alert=False): + """Check if Secure Boot is enabled, returns bool. + + If raise_exceptions is True then an exception is raised with details. + If show_alert is True a popup alert box is shown if it's not enabled. + """ + booted_uefi = is_booted_uefi() + cmd = ['PowerShell', '-Command', 'Confirm-SecureBootUEFI'] + enabled = False + msg_error = None + msg_warning = None + + # Bail early + if OS_VERSION < 8: + if raise_exceptions: + raise GenericWarning(f'Secure Boot not available for {OS_VERSION}') + return False + + # Check results + proc = run_program(cmd, check=False) + if proc.returncode: + # Something went wrong + if booted_uefi: + msg_warning = 'UNKNOWN' + else: + msg_warning = 'DISABLED\n\nOS installed LEGACY' + else: + # Command completed + enabled = 'True' in proc.stdout + if 'False' in proc.stdout: + msg_error = 'ERROR' + else: + msg_warning = 'UNKNOWN' + + # Show popup and/or raise exceptions as necessary + for msg, exc in ((msg_error, GenericError), (msg_warning, GenericWarning)): + if not msg: + continue + msg = f'Secure Boot {msg}' + if show_alert: + show_alert_box(msg) + if raise_exceptions: + raise exc(msg) + break + + # Done + return enabled + + # Service Functions def disable_service(service_name): """Set service startup to disabled.""" @@ -451,19 +557,5 @@ def stop_service(service_name): raise GenericError(f'Failed to stop service {service_name}') -# Date / Time functions -def get_timezone(): - """Get current timezone using tzutil, returns str.""" - cmd = ['tzutil', '/g'] - proc = run_program(cmd, check=False) - return proc.stdout - - -def set_timezone(zone): - """Set current timezone using tzutil.""" - cmd = ['tzutil', '/s', zone] - run_program(cmd, check=False) - - if __name__ == '__main__': print("This file is not meant to be called directly.") diff --git a/scripts/wk/setup/win.py b/scripts/wk/setup/win.py index c5621a3c..c0d9f6b2 100644 --- a/scripts/wk/setup/win.py +++ b/scripts/wk/setup/win.py @@ -44,10 +44,12 @@ if platform.system() == 'Windows': from wk.os.win import ( OS_VERSION, activate_with_bios, + get_os_activation, + get_os_name, + is_secure_boot_enabled, reg_read_value, reg_set_value, reg_write_settings, - show_os_name, ) from wk.repairs.win import ( backup_all_browser_profiles, @@ -66,10 +68,12 @@ else: """No-op function.""" # wk.os.win activate_with_bios = no_op + get_os_activation = no_op + get_os_name = no_op + is_secure_boot_enabled = no_op reg_read_value = no_op reg_set_value = no_op reg_write_settings = no_op - show_os_name = no_op # wk.repairs.win backup_all_browser_profiles = no_op backup_registry = no_op @@ -559,9 +563,22 @@ def auto_restore_default_uac(): TRY_PRINT.run('User Account Control...', restore_default_uac) +def auto_show_os_activation(): + """Display OS Name.""" + TRY_PRINT.run('Activation...', get_os_activation, as_list=True) + + def auto_show_os_name(): """Display OS Name.""" - TRY_PRINT.run('Operating System...', show_os_name) + TRY_PRINT.run('Operating System...', get_os_name, as_list=True) + + +def auto_show_secure_boot_status(): + """Display Secure Boot status.""" + TRY_PRINT.run( + 'Secure Boot...', is_secure_boot_enabled, + raise_exceptions=True, show_alert=True, + ) def auto_windows_temp_fix(): @@ -569,8 +586,6 @@ def auto_windows_temp_fix(): TRY_PRINT.run(r'Windows\Temp fix...', fix_windows_temp) - - # Configure Functions def config_explorer(): """Configure Windows Explorer and restart the process."""