diff --git a/.bin/ConEmu/ConEmu.xml b/.bin/ConEmu/ConEmu.xml
index 3a00062b..871995cc 100644
--- a/.bin/ConEmu/ConEmu.xml
+++ b/.bin/ConEmu/ConEmu.xml
@@ -139,7 +139,7 @@
-
+
diff --git a/.bin/Scripts/activate.py b/.bin/Scripts/activate.py
index f9a9c69d..fa54fa5d 100644
--- a/.bin/Scripts/activate.py
+++ b/.bin/Scripts/activate.py
@@ -55,8 +55,8 @@ if __name__ == '__main__':
print_success('\nDone.')
pause("Press Enter to exit...")
exit_script()
- except SystemExit:
- pass
+ except SystemExit as sys_exit:
+ exit_script(sys_exit.code)
except:
major_exception()
diff --git a/.bin/Scripts/add-known-networks b/.bin/Scripts/add-known-networks
new file mode 100755
index 00000000..bdfc7a1c
--- /dev/null
+++ b/.bin/Scripts/add-known-networks
@@ -0,0 +1,81 @@
+#!/bin/env python3
+#
+## Convert saved WiFi connections for NetworkManager
+
+import os
+import re
+import sys
+import uuid
+
+KNOWN_NETWORKS = '/root/known_networks'
+TEMPLATE = '''[connection]
+id={ssid}
+uuid={uuid}
+type=wifi
+permissions=user:{user}:;
+
+[wifi]
+mac-address-blacklist=
+mode=infrastructure
+ssid={ssid}
+
+[wifi-security]
+auth-alg=open
+key-mgmt=wpa-psk
+psk={password}
+
+[ipv4]
+dns-search=
+method=auto
+
+[ipv6]
+addr-gen-mode=stable-privacy
+dns-search=
+method=auto
+'''
+
+def get_user_name():
+ """Get user name, returns str."""
+ user = None
+
+ # Get running user
+ if 'SUDO_USER' in os.environ:
+ user = os.environ.get('SUDO_USER')
+ else:
+ user = os.environ.get('USER')
+
+ # Check if user manually specified
+ for a in sys.argv:
+ a = a.strip().lower()
+ if a.startswith('--user='):
+ user = a.replace('--user=', '')
+
+ return user
+
+if __name__ == '__main__':
+ known_networks = {}
+ #try:
+ with open('/root/known_networks', 'r') as f:
+ for line in f.readlines():
+ r = re.search(r"^'(.*)':\s+'(.*)'", line.strip())
+ if r:
+ known_networks[r.group(1)] = r.group(2)
+ for ssid, password in known_networks.items():
+ out_path = '{}/{}.nmconnection'.format(
+ '/etc/NetworkManager/system-connections',
+ ssid,
+ )
+ if not os.path.exists(out_path):
+ with open(out_path, 'w') as f:
+ f.write(TEMPLATE.format(
+ user=get_user_name(),
+ ssid=ssid,
+ password=password,
+ uuid=uuid.uuid4(),
+ ))
+ os.chmod(out_path, 0o600)
+ #except:
+ # # Meh
+ # pass
+
+# vim: sts=2 sw=2 ts=2
diff --git a/.bin/Scripts/build-ufd b/.bin/Scripts/build-ufd
index 5f272d7d..17e5972c 100755
--- a/.bin/Scripts/build-ufd
+++ b/.bin/Scripts/build-ufd
@@ -1,671 +1,149 @@
-#!/usr/bin/env bash
+#!/bin/env python3
#
-## Wizard Kit: UFD Build Tool
-#
-# Based on a template by BASH3 Boilerplate v2.3.0
-# http://bash3boilerplate.sh/#authors
-#
-# The MIT License (MIT)
-# Copyright (c) 2013 Kevin van Zonneveld and contributors
-# You are not obligated to bundle the LICENSE file with your b3bp projects as long
-# as you leave these references intact in the header comments of your source files.
-
-# Exit on error. Append "|| true" if you expect an error.
-set -o errexit
-# Exit on error inside any functions or subshells.
-set -o errtrace
-# Do not allow use of undefined vars. Use ${VAR:-} to use an undefined VAR
-set -o nounset
-# Catch the error in case mysqldump fails (but gzip succeeds) in `mysqldump |gzip`
-set -o pipefail
-# Turn on traces, useful while debugging but commented out by default
-# set -o xtrace
-
-if [[ "${BASH_SOURCE[0]}" != "${0}" ]]; then
- __i_am_main_script="0" # false
-
- if [[ "${__usage+x}" ]]; then
- if [[ "${BASH_SOURCE[1]}" = "${0}" ]]; then
- __i_am_main_script="1" # true
- fi
-
- __b3bp_external_usage="true"
- __b3bp_tmp_source_idx=1
- fi
-else
- __i_am_main_script="1" # true
- [[ "${__usage+x}" ]] && unset -v __usage
- [[ "${__helptext+x}" ]] && unset -v __helptext
-fi
-
-# Set magic variables for current file, directory, os, etc.
-__dir="$(cd "$(dirname "${BASH_SOURCE[${__b3bp_tmp_source_idx:-0}]}")" && pwd)"
-__file="${__dir}/$(basename "${BASH_SOURCE[${__b3bp_tmp_source_idx:-0}]}")"
-__base="$(basename "${__file}" .sh)"
-__wd="$(pwd)"
-__usage_example="Usage: sudo $(basename "${0}") --ufd-device [device] --linux-iso [path] --main-kit [path] --winpe-iso [path]"
-__all_args=""
-for a in "${@}"; do
- if [[ "${a:0:1}" == "-" ]]; then
- __all_args="${__all_args} ${a}"
- else
- __all_args="${__all_args} \"${a}\""
- fi
-done
-
-
-# Define the environment variables (and their defaults) that this script depends on
-LOG_LEVEL="${LOG_LEVEL:-6}" # 7 = debug -> 0 = emergency
-NO_COLOR="${NO_COLOR:-}" # true = disable color. otherwise autodetected
-
-
-### Functions
-##############################################################################
-
-function __b3bp_log () {
- local log_level="${1}"
- shift
-
- # shellcheck disable=SC2034
- local color_debug="\x1b[35m"
- # shellcheck disable=SC2034
- local color_info="\x1b[32m"
- # shellcheck disable=SC2034
- local color_notice="\x1b[34m"
- # shellcheck disable=SC2034
- local color_warning="\x1b[33m"
- # shellcheck disable=SC2034
- local color_error="\x1b[31m"
- # shellcheck disable=SC2034
- local color_critical="\x1b[1;31m"
- # shellcheck disable=SC2034
- local color_alert="\x1b[1;33;41m"
- # shellcheck disable=SC2034
- local color_emergency="\x1b[1;4;5;33;41m"
-
- local colorvar="color_${log_level}"
-
- local color="${!colorvar:-${color_error}}"
- local color_reset="\x1b[0m"
-
- if [[ "${NO_COLOR:-}" = "true" ]] || ( [[ "${TERM:-}" != *"256color"* ]] && [[ "${TERM:-}" != "xterm"* ]] && [[ "${TERM:-}" != "screen"* ]] ) || [[ ! -t 2 ]]; then
- if [[ "${NO_COLOR:-}" != "false" ]]; then
- # Don't use colors on pipes or non-recognized terminals
- color=""; color_reset=""
- fi
- fi
-
- # all remaining arguments are to be printed
- local log_line=""
-
- while IFS=$'\n' read -r log_line; do
- echo -e "$(date -u +"%Y-%m-%d %H:%M:%S UTC") ${color}$(printf "[%9s]" "${log_level}")${color_reset} ${log_line}" 1>&2
- done <<< "${@:-}"
-}
-
-function emergency () { __b3bp_log emergency "${@}"; exit 1; }
-function alert () { [[ "${LOG_LEVEL:-0}" -ge 1 ]] && __b3bp_log alert "${@}"; true; }
-function critical () { [[ "${LOG_LEVEL:-0}" -ge 2 ]] && __b3bp_log critical "${@}"; true; }
-function error () { [[ "${LOG_LEVEL:-0}" -ge 3 ]] && __b3bp_log error "${@}"; true; }
-function warning () { [[ "${LOG_LEVEL:-0}" -ge 4 ]] && __b3bp_log warning "${@}"; true; }
-function notice () { [[ "${LOG_LEVEL:-0}" -ge 5 ]] && __b3bp_log notice "${@}"; true; }
-function info () { [[ "${LOG_LEVEL:-0}" -ge 6 ]] && __b3bp_log info "${@}"; true; }
-function debug () { [[ "${LOG_LEVEL:-0}" -ge 7 ]] && __b3bp_log debug "${@}"; true; }
-
-function help () {
- echo "" 1>&2
- echo " ${*}" 1>&2
- echo "" 1>&2
- echo " ${__usage:-No usage available}" 1>&2
- echo "" 1>&2
-
- if [[ "${__helptext:-}" ]]; then
- echo " ${__helptext}" 1>&2
- echo "" 1>&2
- fi
-
- exit 1
-}
-
-
-### Parse commandline options
-##############################################################################
-
-# Commandline options. This defines the usage page, and is used to parse cli
-# opts & defaults from. The parsing is unforgiving so be precise in your syntax
-# - A short option must be preset for every long option; but every short option
-# need not have a long option
-# - `--` is respected as the separator between options and arguments
-# - We do not bash-expand defaults, so setting '~/app' as a default will not resolve to ${HOME}.
-# you can use bash variables to work around this (so use ${HOME} instead)
-
-# shellcheck disable=SC2015
-[[ "${__usage+x}" ]] || read -r -d '' __usage <<-'EOF' || true # exits non-zero when EOF encountered
- OPTIONS:
- -u --ufd-device [arg] Device to which the kit will be applied
- -l --linux-iso [arg] Path to the Linux ISO
-
- -e --extra-dir [arg] Path to the Extra folder (optional)
- -m --main-kit [arg] Path to the Main Kit (optional)
- -w --winpe-iso [arg] Path to the WinPE ISO (optional)
- -h --help This page
-
- ADVANCED:
- -d --debug Enable debug mode
- -v --verbose Enable verbose mode
- -M --use-mbr Use real MBR instead of GPT w/ Protective MBR
- -F --force Bypass all confirmation messages. USE WITH EXTREME CAUTION!
-EOF
-
-# shellcheck disable=SC2015
-[[ "${__helptext+x}" ]] || read -r -d '' __helptext <<-'EOF' || true # exits non-zero when EOF encountered
- Paths can be relative to the current working directory or absolute
-EOF
-
-# Translate usage string -> getopts arguments, and set $arg_ defaults
-while read -r __b3bp_tmp_line; do
- if [[ "${__b3bp_tmp_line}" =~ ^- ]]; then
- # fetch single character version of option string
- __b3bp_tmp_opt="${__b3bp_tmp_line%% *}"
- __b3bp_tmp_opt="${__b3bp_tmp_opt:1}"
-
- # fetch long version if present
- __b3bp_tmp_long_opt=""
-
- if [[ "${__b3bp_tmp_line}" = *"--"* ]]; then
- __b3bp_tmp_long_opt="${__b3bp_tmp_line#*--}"
- __b3bp_tmp_long_opt="${__b3bp_tmp_long_opt%% *}"
- fi
-
- # map opt long name to+from opt short name
- printf -v "__b3bp_tmp_opt_long2short_${__b3bp_tmp_long_opt//-/_}" '%s' "${__b3bp_tmp_opt}"
- printf -v "__b3bp_tmp_opt_short2long_${__b3bp_tmp_opt}" '%s' "${__b3bp_tmp_long_opt//-/_}"
-
- # check if option takes an argument
- if [[ "${__b3bp_tmp_line}" =~ \[.*\] ]]; then
- __b3bp_tmp_opt="${__b3bp_tmp_opt}:" # add : if opt has arg
- __b3bp_tmp_init="" # it has an arg. init with ""
- printf -v "__b3bp_tmp_has_arg_${__b3bp_tmp_opt:0:1}" '%s' "1"
- elif [[ "${__b3bp_tmp_line}" =~ \{.*\} ]]; then
- __b3bp_tmp_opt="${__b3bp_tmp_opt}:" # add : if opt has arg
- __b3bp_tmp_init="" # it has an arg. init with ""
- # remember that this option requires an argument
- printf -v "__b3bp_tmp_has_arg_${__b3bp_tmp_opt:0:1}" '%s' "2"
- else
- __b3bp_tmp_init="0" # it's a flag. init with 0
- printf -v "__b3bp_tmp_has_arg_${__b3bp_tmp_opt:0:1}" '%s' "0"
- fi
- __b3bp_tmp_opts="${__b3bp_tmp_opts:-}${__b3bp_tmp_opt}"
- fi
-
- [[ "${__b3bp_tmp_opt:-}" ]] || continue
-
- if [[ "${__b3bp_tmp_line}" =~ (^|\.\ *)Default= ]]; then
- # ignore default value if option does not have an argument
- __b3bp_tmp_varname="__b3bp_tmp_has_arg_${__b3bp_tmp_opt:0:1}"
-
- if [[ "${!__b3bp_tmp_varname}" != "0" ]]; then
- __b3bp_tmp_init="${__b3bp_tmp_line##*Default=}"
- __b3bp_tmp_re='^"(.*)"$'
- if [[ "${__b3bp_tmp_init}" =~ ${__b3bp_tmp_re} ]]; then
- __b3bp_tmp_init="${BASH_REMATCH[1]}"
- else
- __b3bp_tmp_re="^'(.*)'$"
- if [[ "${__b3bp_tmp_init}" =~ ${__b3bp_tmp_re} ]]; then
- __b3bp_tmp_init="${BASH_REMATCH[1]}"
- fi
- fi
- fi
- fi
-
- if [[ "${__b3bp_tmp_line}" =~ (^|\.\ *)Required\. ]]; then
- # remember that this option requires an argument
- printf -v "__b3bp_tmp_has_arg_${__b3bp_tmp_opt:0:1}" '%s' "2"
- fi
-
- printf -v "arg_${__b3bp_tmp_opt:0:1}" '%s' "${__b3bp_tmp_init}"
-done <<< "${__usage:-}"
-
-# run getopts only if options were specified in __usage
-if [[ "${__b3bp_tmp_opts:-}" ]]; then
- # Allow long options like --this
- __b3bp_tmp_opts="${__b3bp_tmp_opts}-:"
-
- # Reset in case getopts has been used previously in the shell.
- OPTIND=1
-
- # start parsing command line
- set +o nounset # unexpected arguments will cause unbound variables
- # to be dereferenced
- # Overwrite $arg_ defaults with the actual CLI options
- while getopts "${__b3bp_tmp_opts}" __b3bp_tmp_opt; do
- [[ "${__b3bp_tmp_opt}" = "?" ]] && help "Invalid use of script: ${*} "
-
- if [[ "${__b3bp_tmp_opt}" = "-" ]]; then
- # OPTARG is long-option-name or long-option=value
- if [[ "${OPTARG}" =~ .*=.* ]]; then
- # --key=value format
- __b3bp_tmp_long_opt=${OPTARG/=*/}
- # Set opt to the short option corresponding to the long option
- __b3bp_tmp_varname="__b3bp_tmp_opt_long2short_${__b3bp_tmp_long_opt//-/_}"
- printf -v "__b3bp_tmp_opt" '%s' "${!__b3bp_tmp_varname}"
- OPTARG=${OPTARG#*=}
- else
- # --key value format
- # Map long name to short version of option
- __b3bp_tmp_varname="__b3bp_tmp_opt_long2short_${OPTARG//-/_}"
- printf -v "__b3bp_tmp_opt" '%s' "${!__b3bp_tmp_varname}"
- # Only assign OPTARG if option takes an argument
- __b3bp_tmp_varname="__b3bp_tmp_has_arg_${__b3bp_tmp_opt}"
- printf -v "OPTARG" '%s' "${@:OPTIND:${!__b3bp_tmp_varname}}"
- # shift over the argument if argument is expected
- ((OPTIND+=__b3bp_tmp_has_arg_${__b3bp_tmp_opt}))
- fi
- # we have set opt/OPTARG to the short value and the argument as OPTARG if it exists
- fi
- __b3bp_tmp_varname="arg_${__b3bp_tmp_opt:0:1}"
- __b3bp_tmp_default="${!__b3bp_tmp_varname}"
-
- __b3bp_tmp_value="${OPTARG}"
- if [[ -z "${OPTARG}" ]] && [[ "${__b3bp_tmp_default}" = "0" ]]; then
- __b3bp_tmp_value="1"
- fi
-
- printf -v "${__b3bp_tmp_varname}" '%s' "${__b3bp_tmp_value}"
- debug "cli arg ${__b3bp_tmp_varname} = (${__b3bp_tmp_default}) -> ${!__b3bp_tmp_varname}"
- done
- set -o nounset # no more unbound variable references expected
-
- shift $((OPTIND-1))
-
- if [[ "${1:-}" = "--" ]] ; then
- shift
- fi
-fi
-
-
-### Automatic validation of required option arguments
-##############################################################################
-
-for __b3bp_tmp_varname in ${!__b3bp_tmp_has_arg_*}; do
- # validate only options which required an argument
- [[ "${!__b3bp_tmp_varname}" = "2" ]] || continue
-
- __b3bp_tmp_opt_short="${__b3bp_tmp_varname##*_}"
- __b3bp_tmp_varname="arg_${__b3bp_tmp_opt_short}"
- [[ "${!__b3bp_tmp_varname}" ]] && continue
-
- __b3bp_tmp_varname="__b3bp_tmp_opt_short2long_${__b3bp_tmp_opt_short}"
- printf -v "__b3bp_tmp_opt_long" '%s' "${!__b3bp_tmp_varname}"
- [[ "${__b3bp_tmp_opt_long:-}" ]] && __b3bp_tmp_opt_long=" (--${__b3bp_tmp_opt_long//_/-})"
-
- help "Option -${__b3bp_tmp_opt_short}${__b3bp_tmp_opt_long:-} requires an argument"
-done
-
-
-### Cleanup Environment variables
-##############################################################################
-
-for __tmp_varname in ${!__b3bp_tmp_*}; do
- unset -v "${__tmp_varname}"
-done
-
-unset -v __tmp_varname
-
-
-### Externally supplied __usage. Nothing else to do here
-##############################################################################
-
-if [[ "${__b3bp_external_usage:-}" = "true" ]]; then
- unset -v __b3bp_external_usage
- return
-fi
-
-
-### Signal trapping and backtracing
-##############################################################################
-
-function __b3bp_cleanup_before_exit () {
- if [[ "$EUID" -eq 0 ]]; then
- for d in Dest Linux WinPE; do
- if [[ -d "/mnt/${d}" ]]; then
- umount "/mnt/${d}" || true
- rmdir "/mnt/${d}" || true
- fi
- done
- fi
- if [[ "${?}" != "0" ]]; then
- info "Sources unmounted"
- fi
- if [[ ${arg_F:-} == 0 && "${SILENT:-False}" == "False" ]]; then
- read -r -p "Press Enter to exit... " ignored_var 2>&1
- fi
-}
-trap __b3bp_cleanup_before_exit EXIT
-
-# requires `set -o errtrace`
-__b3bp_err_report() {
- local error_code
- error_code=${?}
- error "Error in ${__file} in function ${1} on line ${2}"
- exit ${error_code}
-}
-# Uncomment the following line for always providing an error backtrace
-trap '__b3bp_err_report "${FUNCNAME:-.}" ${LINENO}' ERR
-
-
-### Command-line argument switches (like -d for debugmode, -h for showing helppage)
-##############################################################################
-
-# debug mode
-if [[ "${arg_d:?}" = "1" ]]; then
- set -o xtrace
- LOG_LEVEL="7"
- # Enable error backtracing
- trap '__b3bp_err_report "${FUNCNAME:-.}" ${LINENO}' ERR
-fi
-
-# verbose mode
-if [[ "${arg_v:?}" = "1" ]]; then
- set -o verbose
-fi
-
-
-### Validation. Error out if the things required for your script are not present
-##############################################################################
-
-if [[ "${arg_F:?}" == 1 ]]; then
- SILENT="True"
-else
- SILENT="False"
-fi
-if [[ "${arg_M:?}" == 1 ]]; then
- USE_MBR="True"
-else
- USE_MBR="False"
-fi
-
-if [[ "${arg_h:?}" == 1 ]]; then
- help "${__usage_example}"
-else
- # Print warning line
- [[ "${arg_u:-}" ]] || echo " -u or --ufd-device is required"
- [[ "${arg_l:-}" ]] || echo " -l or --linux-iso is required"
-
- # Bail if necessary
- [[ "${arg_u:-}" ]] || help "${__usage_example}"
- [[ "${arg_l:-}" ]] || help "${__usage_example}"
-fi
-[[ "${LOG_LEVEL:-}" ]] || emergency "Cannot continue without LOG_LEVEL. "
-
-
-### More functions
-##############################################################################
-
-function abort () {
- local abort_message="Aborted"
- [[ "${1:-}" ]] && abort_message="${1}" || true
- error "${abort_message}"
- #echo -e "${YELLOW}${abort_message}${CLEAR}"
- exit 1
-}
-
-function ask() {
- if [[ "${SILENT}" == "True" ]]; then
- echo -e "${1:-} Yes ${BLUE}(Silent)${CLEAR}"
- return 0
- fi
- while :; do
- read -p "${1:-} [Y/N] " -r answer
- if echo "$answer" | egrep -iq '^(y|yes|sure)$'; then
- return 0
- elif echo "$answer" | egrep -iq '^(n|no|nope)$'; then
- return 1
- fi
- done
-}
-
-
-### Runtime
-##############################################################################
-
-# VARIABLES
-DEST_DEV="${arg_u}"
-DEST_PAR="${DEST_DEV}1"
-LOG_FILE="$(getent passwd "$SUDO_USER" | cut -d: -f6)/Logs/build-ufd_${DEST_DEV##*/}_$(date +%Y-%m-%d_%H%M_%z).log"
-MAIN_PY="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/settings/main.py"
-RSYNC_ARGS="-hrtuvS --modify-window=1 --progress"
-MAIN_KIT="$(realpath "${arg_m:-}" 2>/dev/null || true)"
-LINUX_ISO="$(realpath "${arg_l:-}" 2>/dev/null || true)"
-WINPE_ISO="$(realpath "${arg_w:-}" 2>/dev/null || true)"
-EXTRA_DIR="$(realpath "${arg_e:-}" 2>/dev/null || true)"
-mkdir -p "$(dirname "$LOG_FILE")"
-chown "$SUDO_USER:$SUDO_USER" -R "$(dirname "$LOG_FILE")"
-
-# COLORS
-CLEAR="\e[0m"
-RED="\e[31m"
-GREEN="\e[32m"
-YELLOW="\e[33m"
-BLUE="\e[34m"
-
-# Load main.py settings
-if [ ! -f "${MAIN_PY}" ]; then
- echo -e "${RED}ERROR${CLEAR}: ${MAIN_PY} not found."
- abort
-fi
-while read line; do
- if echo "${line}" | egrep -q "^\w+='"; then
- line="$(echo "${line}" | sed -r 's/[\r\n]+//')"
- eval "${line}"
- fi
-done < "${MAIN_PY}"
-if [ -z ${KIT_NAME_FULL+x} ]; then
- # KIT_NAME_FULL is not set, assume main.py missing or malformatted
- echo -e "${RED}ERROR${CLEAR}: failed to load settings from ${MAIN_PY}"
- abort
-fi
-ISO_LABEL="${KIT_NAME_SHORT}_LINUX"
-UFD_LABEL="${KIT_NAME_SHORT}_UFD"
-
-# Check if root
-if [[ "$EUID" -ne 0 ]]; then
- echo -e "${RED}ERROR${CLEAR}: This script must be run as root."
- abort
-fi
-
-# Check if in tmux
-if ! tmux list-session 2>/dev/null | grep -q "build-ufd"; then
- # Reload in tmux
- eval tmux new-session -s "build-ufd" "${0:-}" ${__all_args}
- SILENT="True" # avoid two "Press Enter to exit..." prompts
- exit 0
-fi
-
-# Header
-echo -e "${GREEN}${KIT_NAME_FULL}${CLEAR}: UFD Build Tool"
-echo ""
-
-# Verify sources
-[[ -b "${DEST_DEV}" ]] || abort "${DEST_DEV} is not a valid device."
-[[ -e "${LINUX_ISO}" ]] || abort "Linux ISO not found."
-if [[ ! -z "${arg_m:-}" ]]; then
- [[ -d "${MAIN_KIT}/.bin" ]] || abort "Invalid Main Kit, ${MAIN_KIT}/.bin not found."
-fi
-if [[ ! -z "${arg_w:-}" ]]; then
- [[ -e "${WINPE_ISO}" ]] || abort "WinPE ISO not found."
-fi
-if [[ ! -z "${arg_e:-}" ]]; then
- [[ -d "${EXTRA_DIR}" ]] || abort "Extra Dir not found."
-fi
-
-# Print Info
-echo -e "${BLUE}Sources${CLEAR}" | tee -a "${LOG_FILE}"
-echo "Main Kit: ${MAIN_KIT}" | tee -a "${LOG_FILE}"
-echo "Linux ISO: ${LINUX_ISO}" | tee -a "${LOG_FILE}"
-echo "WinPE ISO: ${WINPE_ISO}" | tee -a "${LOG_FILE}"
-echo "Extra Dir: ${EXTRA_DIR:-(Not Specified)}" | tee -a "${LOG_FILE}"
-echo "" | tee -a "${LOG_FILE}"
-echo -e "${BLUE}Destination${CLEAR}" | tee -a "${LOG_FILE}"
-lsblk -n -o NAME,LABEL,SIZE,MODEL,SERIAL "${DEST_DEV}" | tee -a "${LOG_FILE}"
-if [[ "${USE_MBR}" == "True" ]]; then
- echo -e "${YELLOW}Formatting using legacy MBR${CLEAR}" | tee -a "${LOG_FILE}"
-fi
-echo "" | tee -a "${LOG_FILE}"
-
-# Ask before starting job
-echo ""
-if ask "Is the above information correct?"; then
- echo ""
- echo -e "${YELLOW}SAFETY CHECK${CLEAR}"
- echo "All data will be DELETED from the disk and partition(s) listed above."
- echo -e "This is irreversible and will lead to ${RED}DATA LOSS.${CLEAR}"
- if ! ask "Asking again to confirm, is this correct?"; then
- abort
- fi
-else
- abort
-fi
-
-# Start Build
-echo "" | tee -a "${LOG_FILE}"
-echo -e "${GREEN}Building Kit${CLEAR}" | tee -a "${LOG_FILE}"
-touch "${LOG_FILE}"
-tmux split-window -dl 10 tail -f "${LOG_FILE}"
-
-# Zero beginning of device
-dd bs=4M count=16 if=/dev/zero of="${DEST_DEV}" >> "${LOG_FILE}" 2>&1
-
-# Format
-echo "Formatting drive..." | tee -a "${LOG_FILE}"
-if [[ "${USE_MBR}" == "True" ]]; then
- parted "${DEST_DEV}" --script -- mklabel msdos mkpart primary fat32 4MiB -1s >> "${LOG_FILE}" 2>&1
- parted "${DEST_DEV}" set 1 boot on >> "${LOG_FILE}" 2>&1
-else
- parted "${DEST_DEV}" --script -- mklabel gpt mkpart primary fat32 4MiB -4MiB >> "${LOG_FILE}" 2>&1
- parted "${DEST_DEV}" set 1 legacy_boot on >> "${LOG_FILE}" 2>&1
- #parted "${DEST_DEV}" disk_set pmbr_boot on >> "${LOG_FILE}" 2>&1
- # pmbr_boot breaks detection on some UEFI MOBOs
-fi
-mkfs.vfat -F 32 -n "${UFD_LABEL}" "${DEST_PAR}" >> "${LOG_FILE}" 2>&1
-
-# Mount sources and dest
-echo "Mounting sources and destination..." | tee -a "${LOG_FILE}"
-mkdir /mnt/{Dest,Linux,WinPE} -p >> "${LOG_FILE}" 2>&1
-mount ${DEST_PAR} /mnt/Dest >> "${LOG_FILE}" 2>&1
-mount "${LINUX_ISO}" /mnt/Linux -r >> "${LOG_FILE}" 2>&1
-if [[ ! -z "${arg_w:-}" ]]; then
- mount "${WINPE_ISO}" /mnt/WinPE -r >> "${LOG_FILE}" 2>&1
-fi
-
-# Find WinPE source
-w_boot="$(find /mnt/WinPE -iwholename "/mnt/WinPE/Boot")"
-w_boot_bcd="$(find /mnt/WinPE -iwholename "/mnt/WinPE/Boot/BCD")"
-w_boot_sdi="$(find /mnt/WinPE -iwholename "/mnt/WinPE/Boot/boot.sdi")"
-w_bootmgr="$(find /mnt/WinPE -iwholename "/mnt/WinPE/bootmgr")"
-w_bootmgr_efi="$(find /mnt/WinPE -iwholename "/mnt/WinPE/bootmgr.efi")"
-w_efi_boot="$(find /mnt/WinPE -iwholename "/mnt/WinPE/EFI/Boot")"
-w_efi_microsoft="$(find /mnt/WinPE -iwholename "/mnt/WinPE/EFI/Microsoft")"
-w_en_us="$(find /mnt/WinPE -iwholename "/mnt/WinPE/en-us")"
-w_sources="$(find /mnt/WinPE -iwholename "/mnt/WinPE/sources")"
-
-# Copy files
-echo "Copying Linux files..." | tee -a "${LOG_FILE}"
-rsync ${RSYNC_ARGS} /mnt/Linux/* /mnt/Dest/ >> "${LOG_FILE}" 2>&1
-sed -i "s/${ISO_LABEL}/${UFD_LABEL}/" /mnt/Dest/EFI/boot/refind.conf
-sed -i "s/${ISO_LABEL}/${UFD_LABEL}/" /mnt/Dest/arch/boot/syslinux/*cfg
-
-echo "Copying WinPE files..." | tee -a "${LOG_FILE}"
-if [[ ! -z "${arg_w:-}" ]]; then
- if [[ ! -z "${w_bootmgr:-}" ]]; then
- rsync ${RSYNC_ARGS} "${w_bootmgr}" /mnt/Dest/ >> "${LOG_FILE}" 2>&1
- fi
- if [[ ! -z "${w_bootmgr_efi:-}" ]]; then
- rsync ${RSYNC_ARGS} "${w_bootmgr_efi}" /mnt/Dest/ >> "${LOG_FILE}" 2>&1
- fi
- if [[ ! -z "${w_en_us:-}" ]]; then
- rsync ${RSYNC_ARGS} "${w_en_us}" /mnt/Dest/ >> "${LOG_FILE}" 2>&1
- fi
- if [[ ! -z "${w_boot:-}" ]]; then
- rsync ${RSYNC_ARGS} "${w_boot}"/* /mnt/Dest/Boot/ >> "${LOG_FILE}" 2>&1
- fi
- if [[ ! -z "${w_efi_boot:-}" ]]; then
- rsync ${RSYNC_ARGS} "${w_efi_boot}"/* /mnt/Dest/EFI/Microsoft/ >> "${LOG_FILE}" 2>&1
- fi
- if [[ ! -z "${w_efi_microsoft:-}" ]]; then
- rsync ${RSYNC_ARGS} "${w_efi_microsoft}"/* /mnt/Dest/EFI/Microsoft/ >> "${LOG_FILE}" 2>&1
- fi
- if [[ ! -z "${w_boot_bcd:-}" ]]; then
- rsync ${RSYNC_ARGS} "${w_boot_bcd}" /mnt/Dest/sources/ >> "${LOG_FILE}" 2>&1
- fi
- if [[ ! -z "${w_boot_sdi:-}" ]]; then
- rsync ${RSYNC_ARGS} "${w_boot_sdi}" /mnt/Dest/sources/ >> "${LOG_FILE}" 2>&1
- fi
- if [[ ! -z "${w_bootmgr:-}" ]]; then
- rsync ${RSYNC_ARGS} "${w_bootmgr}" /mnt/Dest/sources/ >> "${LOG_FILE}" 2>&1
- fi
- if [[ ! -z "${w_sources:-}" ]]; then
- rsync ${RSYNC_ARGS} "${w_sources}"/* /mnt/Dest/sources/ >> "${LOG_FILE}" 2>&1
- fi
-
- # Uncomment boot entries
- sed -i "s/#UFD-WINPE#//" /mnt/Dest/EFI/boot/refind.conf
- sed -i "s/#UFD-WINPE#//" /mnt/Dest/arch/boot/syslinux/*cfg
-fi
-
-echo "Copying Main Kit..." | tee -a "${LOG_FILE}"
-if [[ ! -z "${arg_m:-}" ]]; then
- rsync ${RSYNC_ARGS} \
- "${MAIN_KIT}/" \
- "/mnt/Dest/${KIT_NAME_FULL}/" >> "${LOG_FILE}" 2>&1
-fi
-
-if [[ ! -z "${EXTRA_DIR:-}" ]]; then
- echo "Copying Extra files..." | tee -a "${LOG_FILE}"
- rsync ${RSYNC_ARGS} \
- "${EXTRA_DIR}"/ \
- /mnt/Dest/ >> "${LOG_FILE}" 2>&1
-fi
-
-# Install syslinux
-echo "Copying Syslinux files..." | tee -a "${LOG_FILE}"
-rsync ${RSYNC_ARGS} /usr/lib/syslinux/bios/*.c32 /mnt/Dest/arch/boot/syslinux/ >> "${LOG_FILE}" 2>&1
-syslinux --install -d /arch/boot/syslinux/ ${DEST_PAR} >> "${LOG_FILE}" 2>&1
-
-echo "Unmounting destination..." | tee -a "${LOG_FILE}"
-umount /mnt/Dest >> "${LOG_FILE}" 2>&1
-rmdir /mnt/Dest >> "${LOG_FILE}" 2>&1
-sync
-
-echo "Installing Syslinux MBR..." | tee -a "${LOG_FILE}"
-if [[ "${USE_MBR}" == "True" ]]; then
- dd bs=440 count=1 if=/usr/lib/syslinux/bios/mbr.bin of=${DEST_DEV} >> "${LOG_FILE}" 2>&1
-else
- dd bs=440 count=1 if=/usr/lib/syslinux/bios/gptmbr.bin of=${DEST_DEV} >> "${LOG_FILE}" 2>&1
-fi
-sync
-
-# Cleanup
-echo "Hiding boot files..." | tee -a "${LOG_FILE}"
-echo "drive s: file=\"${DEST_PAR}\"" > /root/.mtoolsrc
-echo 'mtools_skip_check=1' >> /root/.mtoolsrc
-for item in arch Boot bootmgr{,.efi} EFI en-us images isolinux sources "${KIT_NAME_FULL}"/{.bin,.cbin}; do
- yes | mattrib +h "S:/${item}" >> "${LOG_FILE}" 2>&1 || true
-done
-sync
-
-# Unmount Sources
-echo "Unmounting sources..." | tee -a "${LOG_FILE}"
-for d in Linux WinPE; do
- umount "/mnt/${d}" >> "${LOG_FILE}" 2>&1 || true
- rmdir "/mnt/${d}" >> "${LOG_FILE}" 2>&1 || true
-done
-
-# Close progress pane
-pkill -f "tail.*${LOG_FILE}"
-
-# Done
-echo "" | tee -a "${LOG_FILE}"
-echo "Done." | tee -a "${LOG_FILE}"
-echo ""
-exit 0
+# pylint: disable=no-name-in-module,wildcard-import,wrong-import-position
+# vim: sts=2 sw=2 ts=2
+"""Wizard Kit: UFD build tool"""
+
+import os
+import sys
+
+# Init
+sys.path.append(os.path.dirname(os.path.realpath(__file__)))
+from docopt import docopt
+from functions.common import *
+from functions.ufd import *
+from settings.ufd import *
+init_global_vars(silent=True)
+
+# Main section
+if __name__ == '__main__':
+ # pylint: disable=invalid-name
+ # Set log
+ try:
+ global_vars['LogDir'] = '{}/Logs'.format(
+ get_user_home(get_user_name()))
+ set_log_file('Build UFD ({Date-Time}).log'.format(**global_vars))
+ except: # pylint: disable=bare-except
+ major_exception()
+
+ # Header
+ print_success(KIT_NAME_FULL)
+ print_standard('UFD Build Tool')
+ print_standard(' ')
+
+ # Check if running as root
+ if not running_as_root():
+ print_error('ERROR: This script is meant to be run as root.')
+ abort(False)
+
+ # Docopt
+ try:
+ args = docopt(DOCSTRING)
+ except SystemExit as sys_exit:
+ # Catch docopt exits
+ exit_script(sys_exit.code)
+ except: # pylint: disable=bare-except
+ major_exception()
+
+ try:
+ # Verify selections
+ ufd_dev = verify_ufd(args['--ufd-device'])
+ sources = verify_sources(args, UFD_SOURCES)
+ show_selections(args, sources, ufd_dev, UFD_SOURCES)
+ if not args['--force']:
+ confirm_selections(args)
+
+ # Prep UFD
+ print_info('Prep UFD')
+ if not args['--update']:
+ prep_device(ufd_dev, UFD_LABEL, use_mbr=args['--use-mbr'])
+
+ # Mount UFD
+ try_and_print(
+ indent=2,
+ message='Mounting UFD...',
+ function=mount,
+ mount_source=find_first_partition(ufd_dev),
+ mount_point='/mnt/UFD',
+ read_write=True,
+ )
+
+ # Remove Arch folder
+ if args['--update']:
+ try_and_print(
+ indent=2,
+ message='Removing Linux...',
+ function=remove_arch,
+ )
+
+ # Copy sources
+ print_standard(' ')
+ print_info('Copy Sources')
+ for s_label, s_path in sources.items():
+ try_and_print(
+ indent=2,
+ message='Copying {}...'.format(s_label),
+ function=copy_source,
+ source=s_path,
+ items=ITEMS[s_label],
+ overwrite=True,
+ )
+
+ # Update boot entries
+ print_standard(' ')
+ print_info('Boot Setup')
+ try_and_print(
+ indent=2,
+ message='Updating boot entries...',
+ function=update_boot_entries,
+ boot_entries=BOOT_ENTRIES,
+ boot_files=BOOT_FILES,
+ iso_label=ISO_LABEL,
+ ufd_label=UFD_LABEL,
+ )
+
+ # Install syslinux (to partition)
+ try_and_print(
+ indent=2,
+ message='Syslinux (partition)...',
+ function=install_syslinux_to_partition,
+ partition=find_first_partition(ufd_dev),
+ )
+
+ # Unmount UFD
+ try_and_print(
+ indent=2,
+ message='Unmounting UFD...',
+ function=unmount,
+ mount_point='/mnt/UFD',
+ )
+
+ # Install syslinux (to device)
+ try_and_print(
+ indent=2,
+ message='Syslinux (device)...',
+ function=install_syslinux_to_dev,
+ ufd_dev=ufd_dev,
+ use_mbr=args['--use-mbr'],
+ )
+
+ # Hide items
+ print_standard(' ')
+ print_info('Final Touches')
+ try_and_print(
+ indent=2,
+ message='Hiding items...',
+ function=hide_items,
+ ufd_dev=ufd_dev,
+ items=ITEMS_HIDDEN,
+ )
+
+ # Done
+ if not args['--force']:
+ print_standard('\nDone.')
+ pause('Press Enter to exit...')
+ exit_script()
+ except SystemExit as sys_exit:
+ exit_script(sys_exit.code)
+ except: # pylint: disable=bare-except
+ major_exception()
diff --git a/.bin/Scripts/cbs_fix.py b/.bin/Scripts/cbs_fix.py
index 36a7906f..167f95aa 100644
--- a/.bin/Scripts/cbs_fix.py
+++ b/.bin/Scripts/cbs_fix.py
@@ -35,8 +35,8 @@ if __name__ == '__main__':
print_standard('\nDone.')
pause("Press Enter to exit...")
exit_script()
- except SystemExit:
- pass
+ except SystemExit as sys_exit:
+ exit_script(sys_exit.code)
except:
major_exception()
diff --git a/.bin/Scripts/check_disk.py b/.bin/Scripts/check_disk.py
index baee7460..fe18650b 100644
--- a/.bin/Scripts/check_disk.py
+++ b/.bin/Scripts/check_disk.py
@@ -49,8 +49,8 @@ if __name__ == '__main__':
print_success('Done.')
pause("Press Enter to exit...")
exit_script()
- except SystemExit:
- pass
+ except SystemExit as sys_exit:
+ exit_script(sys_exit.code)
except:
major_exception()
diff --git a/.bin/Scripts/connect-to-network b/.bin/Scripts/connect-to-network
deleted file mode 100755
index 02500b37..00000000
--- a/.bin/Scripts/connect-to-network
+++ /dev/null
@@ -1,30 +0,0 @@
-#!/bin/python3
-#
-## Wizard Kit: Network connection tool
-
-import os
-import sys
-
-# Init
-sys.path.append(os.path.dirname(os.path.realpath(__file__)))
-from functions.network import *
-init_global_vars()
-
-if __name__ == '__main__':
- try:
- # Prep
- clear_screen()
-
- # Connect
- connect_to_network()
-
- # Done
- print_standard('\nDone.')
- #pause("Press Enter to exit...")
- exit_script()
- except SystemExit:
- pass
- except:
- major_exception()
-
-# vim: sts=2 sw=2 ts=2
diff --git a/.bin/Scripts/ddrescue-tui-menu b/.bin/Scripts/ddrescue-tui-menu
index a6014d76..f65e24e1 100755
--- a/.bin/Scripts/ddrescue-tui-menu
+++ b/.bin/Scripts/ddrescue-tui-menu
@@ -54,8 +54,8 @@ if __name__ == '__main__':
msg = str(ge)
print_error(msg)
abort()
- except SystemExit:
- pass
+ except SystemExit as sys_exit:
+ exit_script(sys_exit.code)
except:
major_exception()
diff --git a/.bin/Scripts/debug/hw_diags.py b/.bin/Scripts/debug/hw_diags.py
index 87a35990..44517fb4 100644
--- a/.bin/Scripts/debug/hw_diags.py
+++ b/.bin/Scripts/debug/hw_diags.py
@@ -149,11 +149,14 @@ def save_debug_reports(state, global_vars):
f.write('{}\n'.format(line))
-def upload_logdir(global_vars):
+def upload_logdir(global_vars, reason='Crash'):
"""Upload compressed LogDir to CRASH_SERVER."""
source = global_vars['LogDir']
source = source[source.rfind('/')+1:]
- dest = '{}.txz'.format(source)
+ dest = 'HW-Diags_{reason}_{Date-Time}.txz'.format(
+ reason=reason,
+ **global_vars,
+ )
data = None
# Compress LogDir
@@ -166,7 +169,7 @@ def upload_logdir(global_vars):
data = f.read()
# Upload data
- url = '{}/Crash_{}.txz'.format(CRASH_SERVER['Url'], source)
+ url = '{}/{}'.format(CRASH_SERVER['Url'], dest)
r = requests.put(
url,
data=data,
diff --git a/.bin/Scripts/dism.py b/.bin/Scripts/dism.py
index 2ef3ff25..4de5b788 100644
--- a/.bin/Scripts/dism.py
+++ b/.bin/Scripts/dism.py
@@ -50,8 +50,8 @@ if __name__ == '__main__':
print_success('Done.')
pause("Press Enter to exit...")
exit_script()
- except SystemExit:
- pass
+ except SystemExit as sys_exit:
+ exit_script(sys_exit.code)
except:
major_exception()
diff --git a/.bin/Scripts/find_user_wallpapers.py b/.bin/Scripts/find_user_wallpapers.py
index 3ea182f5..e1e77060 100644
--- a/.bin/Scripts/find_user_wallpapers.py
+++ b/.bin/Scripts/find_user_wallpapers.py
@@ -73,8 +73,8 @@ if __name__ == '__main__':
# Done
exit_script()
- except SystemExit:
- pass
+ except SystemExit as sys_exit:
+ exit_script(sys_exit.code)
except:
major_exception()
diff --git a/.bin/Scripts/functions/browsers.py b/.bin/Scripts/functions/browsers.py
index 9f51b1e6..e599bbd3 100644
--- a/.bin/Scripts/functions/browsers.py
+++ b/.bin/Scripts/functions/browsers.py
@@ -9,11 +9,11 @@ from settings.browsers import *
browser_data = {}
other_results = {
'Error': {
- 'MultipleInstallationsError': 'Multiple installations detected',
+ 'MultipleInstallationsError': 'MULTIPLE INSTALLATIONS DETECTED',
},
'Warning': {
- 'NotInstalledError': 'Not installed',
- 'NoProfilesError': 'No profiles found',
+ 'NotInstalledError': 'NOT INSTALLED',
+ 'NoProfilesError': 'NO PROFILES FOUND',
}
}
@@ -32,8 +32,8 @@ def archive_all_users():
user_path = os.path.join(users_root, user_name)
appdata_local = os.path.join(user_path, r'AppData\Local')
appdata_roaming = os.path.join(user_path, r'AppData\Roaming')
- valid_user &= os.path.exists(appdata_local)
- valid_user &= os.path.exists(appdata_roaming)
+ valid_user = valid_user and os.path.exists(appdata_local)
+ valid_user = valid_user and os.path.exists(appdata_roaming)
if valid_user:
user_envs.append({
'USERNAME': user_name,
@@ -319,13 +319,15 @@ def get_mozilla_profiles(search_path, dev=False):
return profiles
-def install_adblock(indent=8, width=32, just_firefox=False):
+def install_adblock(
+ indent=8, width=32, just_firefox=False, skip_firefox=False):
"""Install adblock for all supported browsers."""
for browser in sorted(browser_data):
if just_firefox and browser_data[browser]['base'] != 'mozilla':
continue
+ if skip_firefox and browser_data[browser]['base'] == 'mozilla':
+ continue
exe_path = browser_data[browser].get('exe_path', None)
- function=run_program
if not exe_path:
if browser_data[browser]['profiles']:
print_standard(
@@ -375,7 +377,6 @@ def install_adblock(indent=8, width=32, just_firefox=False):
elif browser_data[browser]['base'] == 'ie':
urls.append(IE_GALLERY)
- function=popen_program
# By using check=False we're skipping any return codes so
# it should only fail if the program can't be run
@@ -384,7 +385,7 @@ def install_adblock(indent=8, width=32, just_firefox=False):
# installation status.
try_and_print(message='{}...'.format(browser),
indent=indent, width=width,
- cs='Done', function=function,
+ cs='STARTED', function=popen_program,
cmd=[exe_path, *urls], check=False)
@@ -425,6 +426,12 @@ def list_homepages(indent=8, width=32):
indent=' '*indent, width=width, name=name, page=page))
+def profile_present(browser_name):
+ """Checks if a profile was detected for browser, returns bool."""
+ browser_name = browser_name.replace(' Chromium', '')
+ return bool(browser_data.get(browser_name, {}).get('profiles', False))
+
+
def reset_browsers(indent=8, width=32):
"""Reset all detected browsers to safe defaults."""
browser_list = [k for k, v in sorted(browser_data.items()) if v['profiles']]
@@ -458,7 +465,7 @@ def scan_for_browsers(just_firefox=False, silent=False, skip_ie=False):
pass
else:
try_and_print(message='{}...'.format(name),
- function=get_browser_details, cs='Detected',
+ function=get_browser_details, cs='DETECTED',
other_results=other_results, name=name)
diff --git a/.bin/Scripts/functions/cleanup.py b/.bin/Scripts/functions/cleanup.py
index 7caf19dc..2723994b 100644
--- a/.bin/Scripts/functions/cleanup.py
+++ b/.bin/Scripts/functions/cleanup.py
@@ -1,49 +1,7 @@
# Wizard Kit: Functions - Cleanup
from functions.setup import *
-
-# STATIC VARIABLES
-D7_HKCR_CLEANUP = {
- r'batfile\shell\!!RunWithParms': {'Recurse': True},
- r'batfile\shell\{0001B4FD-9EA3-4D90-A79E-FD14BA3AB01D}': {'Recurse': True},
- r'cmdfile\shell\!!RunWithParms': {'Recurse': True},
- r'cmdfile\shell\{0001B4FD-9EA3-4D90-A79E-FD14BA3AB01D}': {'Recurse': True},
- r'exefile\shell\!!RunWithParms': {'Recurse': True},
- r'exefile\shell\ResourceHacker': {'Recurse': True},
- r'regfile\shell\!!RunWithParms': {'Recurse': True},
- r'regfile\shell\{0001B4FD-9EA3-4D90-A79E-FD14BA3AB01D}': {'Recurse': True},
- }
-D7_HKCU_CLEANUP = {
- r'Software\Malwarebytes': {'Recurse': False},
- }
-D7_HKLM_CLEANUP = {
- r'Software\Emsisoft': {'Recurse': False},
- }
-HKU = winreg.HKEY_USERS
-HKCR = winreg.HKEY_CLASSES_ROOT
-HKCU = winreg.HKEY_CURRENT_USER
-HKLM = winreg.HKEY_LOCAL_MACHINE
-UAC_DEFAULTS_WIN7 = {
- r'Software\Microsoft\Windows\CurrentVersion\Policies\System': {
- 'DWORD Items': {
- 'ConsentPromptBehaviorAdmin': 5,
- 'EnableLUA': 1,
- 'PromptOnSecureDesktop': 1,
- },
- },
- }
-UAC_DEFAULTS_WIN10 = {
- r'Software\Microsoft\Windows\CurrentVersion\Policies\System': {
- 'DWORD Items': {
- 'ConsentPromptBehaviorAdmin': 5,
- 'ConsentPromptBehaviorUser': 3,
- 'EnableInstallerDetection': 1,
- 'EnableLUA': 1,
- 'EnableVirtualization': 1,
- 'PromptOnSecureDesktop': 1,
- },
- },
- }
+from settings.cleanup import *
def cleanup_adwcleaner():
@@ -195,8 +153,7 @@ def cleanup_desktop():
desktop_path = r'{USERPROFILE}\Desktop'.format(**global_vars['Env'])
for entry in os.scandir(desktop_path):
- # JRT, RKill, Shortcut cleaner
- if re.search(r'^(JRT|RKill|sc-cleaner)', entry.name, re.IGNORECASE):
+ if DESKTOP_ITEMS.search(entry.name):
dest_name = r'{}\{}'.format(dest_folder, entry.name)
dest_name = non_clobber_rename(dest_name)
shutil.move(entry.path, dest_name)
diff --git a/.bin/Scripts/functions/common.py b/.bin/Scripts/functions/common.py
index 20f0f9f8..bc5ed3f3 100644
--- a/.bin/Scripts/functions/common.py
+++ b/.bin/Scripts/functions/common.py
@@ -64,10 +64,13 @@ class GenericRepair(Exception):
class MultipleInstallationsError(Exception):
pass
-class NotInstalledError(Exception):
+class NoProfilesError(Exception):
pass
-class NoProfilesError(Exception):
+class Not4KAlignedError(Exception):
+ pass
+
+class NotInstalledError(Exception):
pass
class OSInstalledLegacyError(Exception):
@@ -88,14 +91,21 @@ class SecureBootNotAvailError(Exception):
class SecureBootUnknownError(Exception):
pass
+class WindowsOutdatedError(Exception):
+ pass
+
+class WindowsUnsupportedError(Exception):
+ pass
+
# General functions
-def abort():
+def abort(show_prompt=True):
"""Abort script."""
print_warning('Aborted.')
- sleep(1)
- pause(prompt='Press Enter to exit... ')
- exit_script()
+ if show_prompt:
+ sleep(1)
+ pause(prompt='Press Enter to exit... ')
+ exit_script(1)
def ask(prompt='Kotaero!'):
@@ -163,18 +173,22 @@ def clear_screen():
def convert_to_bytes(size):
"""Convert human-readable size str to bytes and return an int."""
size = str(size)
- tmp = re.search(r'(\d+\.?\d*)\s+([KMGT]B)', size.upper())
+ tmp = re.search(r'(\d+\.?\d*)\s+([PTGMKB])B?', size.upper())
if tmp:
size = float(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
+ if units == 'P':
+ size *= 1024 ** 5
+ if units == 'T':
+ size *= 1024 ** 4
+ elif units == 'G':
+ size *= 1024 ** 3
+ elif units == 'M':
+ size *= 1024 ** 2
+ elif units == 'K':
+ size *= 1024 ** 1
+ elif units == 'B':
+ size *= 1024 ** 0
size = int(size)
else:
return -1
@@ -293,20 +307,24 @@ def human_readable_size(size, decimals=0):
return '{size:>{width}} b'.format(size='???', width=width)
# Convert to sensible units
- if size >= 1099511627776:
- size /= 1099511627776
- units = 'Tb'
- elif size >= 1073741824:
- size /= 1073741824
- units = 'Gb'
- elif size >= 1048576:
- size /= 1048576
- units = 'Mb'
- elif size >= 1024:
- size /= 1024
- units = 'Kb'
+ if size >= 1024 ** 5:
+ size /= 1024 ** 5
+ units = 'PB'
+ elif size >= 1024 ** 4:
+ size /= 1024 ** 4
+ units = 'TB'
+ elif size >= 1024 ** 3:
+ size /= 1024 ** 3
+ units = 'GB'
+ elif size >= 1024 ** 2:
+ size /= 1024 ** 2
+ units = 'MB'
+ elif size >= 1024 ** 1:
+ size /= 1024 ** 1
+ units = 'KB'
else:
- units = ' b'
+ size /= 1024 ** 0
+ units = ' B'
# Return
return '{size:>{width}.{decimals}f} {units}'.format(
@@ -421,6 +439,8 @@ def non_clobber_rename(full_path):
def pause(prompt='Press Enter to continue... '):
"""Simple pause implementation."""
+ if prompt[-1] != ' ':
+ prompt += ' '
input(prompt)
@@ -885,25 +905,19 @@ def make_tmp_dirs():
def set_common_vars():
"""Set common variables."""
- 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['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'] = r'{BaseDir}\.bin'.format(
- **global_vars)
- global_vars['CBinDir'] = r'{BaseDir}\.cbin'.format(
- **global_vars)
- global_vars['ClientDir'] = r'{SYSTEMDRIVE}\{prefix}'.format(
- prefix=KIT_NAME_SHORT, **global_vars['Env'])
- global_vars['BackupDir'] = r'{ClientDir}\Backups'.format(
- **global_vars)
- global_vars['LogDir'] = r'{ClientDir}\Logs\{Date}'.format(
- **global_vars)
- global_vars['QuarantineDir'] = r'{ClientDir}\Quarantine'.format(
- **global_vars)
- global_vars['TmpDir'] = r'{BinDir}\tmp'.format(
- **global_vars)
+ global_vars['BinDir'] = r'{BaseDir}\.bin'.format(**global_vars)
+ global_vars['CBinDir'] = r'{BaseDir}\.cbin'.format(**global_vars)
+ global_vars['ClientDir'] = r'{SYSTEMDRIVE}\{prefix}'.format(
+ prefix=KIT_NAME_SHORT, **global_vars['Env'])
+ global_vars['BackupDir'] = r'{ClientDir}\Backups'.format(**global_vars)
+ global_vars['LogDir'] = r'{ClientDir}\Logs\{Date}'.format(**global_vars)
+ global_vars['QuarantineDir'] = r'{ClientDir}\Quarantine'.format(**global_vars)
+ global_vars['TmpDir'] = r'{BinDir}\tmp'.format(**global_vars)
def set_linux_vars():
@@ -911,12 +925,12 @@ def set_linux_vars():
These assume we're running under a WK-Linux build."""
result = run_program(['mktemp', '-d'])
- global_vars['TmpDir'] = result.stdout.decode().strip()
- 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['BinDir'] = '/usr/local/bin'
- global_vars['LogDir'] = global_vars['TmpDir']
+ global_vars['TmpDir'] = result.stdout.decode().strip()
+ 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['BinDir'] = '/usr/local/bin'
+ global_vars['LogDir'] = '{}/Logs'.format(global_vars['Env']['HOME'])
global_vars['Tools'] = {
'wimlib-imagex': 'wimlib-imagex',
'SevenZip': '7z',
@@ -925,10 +939,13 @@ def set_linux_vars():
def set_log_file(log_name):
"""Sets global var LogFile and creates path as needed."""
- folder_path = '{}{}{}'.format(
- global_vars['LogDir'],
- os.sep,
- KIT_NAME_FULL)
+ if psutil.LINUX:
+ folder_path = global_vars['LogDir']
+ else:
+ folder_path = '{}{}{}'.format(
+ global_vars['LogDir'],
+ os.sep,
+ KIT_NAME_FULL)
log_file = '{}{}{}'.format(
folder_path,
os.sep,
diff --git a/.bin/Scripts/functions/data.py b/.bin/Scripts/functions/data.py
index a2e5662c..c359ab6c 100644
--- a/.bin/Scripts/functions/data.py
+++ b/.bin/Scripts/functions/data.py
@@ -111,7 +111,7 @@ def find_core_storage_volumes(device_path=None):
# Check log for found volumes
cs_vols = {}
- with open(log_path, 'r') as f:
+ with open(log_path, 'r', encoding='utf-8', errors='ignore') as f:
for line in f.readlines():
r = re.match(
r'^.*echo "([^"]+)" . dmsetup create test(\d)$',
@@ -151,12 +151,16 @@ def is_valid_wim_file(item):
def get_mounted_volumes():
"""Get mounted volumes, returns dict."""
cmd = [
- 'findmnt', '-J', '-b', '-i',
- '-t', (
+ 'findmnt',
+ '--list',
+ '--json',
+ '--bytes',
+ '--invert',
+ '--types', (
'autofs,binfmt_misc,bpf,cgroup,cgroup2,configfs,debugfs,devpts,'
'devtmpfs,hugetlbfs,mqueue,proc,pstore,securityfs,sysfs,tmpfs'
),
- '-o', 'SOURCE,TARGET,FSTYPE,LABEL,SIZE,AVAIL,USED']
+ '--output', 'SOURCE,TARGET,FSTYPE,LABEL,SIZE,AVAIL,USED']
json_data = get_json_from_command(cmd)
mounted_volumes = []
for item in json_data.get('filesystems', []):
@@ -195,6 +199,8 @@ def mount_volumes(
volumes.update({child['name']: child})
for grandchild in child.get('children', []):
volumes.update({grandchild['name']: grandchild})
+ for great_grandchild in grandchild.get('children', []):
+ volumes.update({great_grandchild['name']: great_grandchild})
# Get list of mounted volumes
mounted_volumes = get_mounted_volumes()
@@ -239,9 +245,13 @@ def mount_volumes(
else:
fstype = vol_data.get('fstype', 'UNKNOWN FS')
size_used = human_readable_size(
- mounted_volumes[vol_path]['used'])
+ mounted_volumes[vol_path]['used'],
+ decimals=1,
+ )
size_avail = human_readable_size(
- mounted_volumes[vol_path]['avail'])
+ mounted_volumes[vol_path]['avail'],
+ decimals=1,
+ )
vol_data['size_avail'] = size_avail
vol_data['size_used'] = size_used
vol_data['mount_point'] = mounted_volumes[vol_path]['target']
@@ -283,6 +293,14 @@ def mount_backup_shares(read_write=False):
def mount_network_share(server, read_write=False):
"""Mount a network share defined by server."""
+ uid = '1000'
+
+ # Get UID
+ cmd = ['id', '--user', 'tech']
+ result = run_program(cmd, check=False, encoding='utf-8', errors='ignore')
+ if result.stdout.strip().isnumeric():
+ uid = result.stdout.strip()
+
if read_write:
username = server['RW-User']
password = server['RW-Pass']
@@ -298,18 +316,35 @@ def mount_network_share(server, read_write=False):
error = r'Failed to mount \\{Name}\{Share} ({IP})'.format(**server)
success = 'Mounted {Name}'.format(**server)
elif psutil.LINUX:
+ # Make mountpoint
cmd = [
'sudo', 'mkdir', '-p',
'/Backups/{Name}'.format(**server)]
run_program(cmd)
+
+ # Set mount options
+ cmd_options = [
+ # Assuming GID matches UID
+ 'gid={}'.format(uid),
+ 'uid={}'.format(uid),
+ ]
+ cmd_options.append('rw' if read_write else 'ro')
+ cmd_options.append('username={}'.format(username))
+ if password:
+ cmd_options.append('password={}'.format(password))
+ else:
+ # Skip password check
+ cmd_options.append('guest')
+
+ # Set mount command
cmd = [
'sudo', 'mount',
- '//{IP}/{Share}'.format(**server),
+ '//{IP}/{Share}'.format(**server).replace('\\', '/'),
'/Backups/{Name}'.format(**server),
- '-o', '{}username={},password={}'.format(
- '' if read_write else 'ro,',
- username,
- password)]
+ '-o', ','.join(cmd_options),
+ ]
+
+ # Set result messages
warning = 'Failed to mount /Backups/{Name}, {IP} unreachable.'.format(
**server)
error = 'Failed to mount /Backups/{Name}'.format(**server)
diff --git a/.bin/Scripts/functions/ddrescue.py b/.bin/Scripts/functions/ddrescue.py
index 545d08e0..b276d52b 100644
--- a/.bin/Scripts/functions/ddrescue.py
+++ b/.bin/Scripts/functions/ddrescue.py
@@ -1,25 +1,25 @@
-# Wizard Kit: Functions - ddrescue-tui
+# pylint: disable=no-name-in-module,too-many-lines,wildcard-import
+# vim: sts=2 sw=2 ts=2
+'''Wizard Kit: Functions - ddrescue-tui'''
import datetime
import pathlib
-import psutil
-import pytz
import re
-import signal
import stat
import time
+from operator import itemgetter
-from collections import OrderedDict
+import pytz
from functions.data import *
from functions.hw_diags import *
from functions.json import *
from functions.tmux import *
-from operator import itemgetter
from settings.ddrescue import *
# Clases
class BaseObj():
+ # pylint: disable=missing-docstring
"""Base object used by DevObj, DirObj, and ImageObj."""
def __init__(self, path):
self.type = 'base'
@@ -44,6 +44,7 @@ class BaseObj():
class BlockPair():
+ # pylint: disable=too-many-instance-attributes
"""Object to track data and methods together for source and dest."""
def __init__(self, mode, source, dest):
self.mode = mode
@@ -60,9 +61,10 @@ class BlockPair():
if self.mode == 'clone':
# Cloning
self.dest_path = dest.path
- self.map_path = '{pwd}/Clone_{prefix}.map'.format(
- pwd=os.path.realpath(global_vars['Env']['PWD']),
- prefix=source.prefix)
+ self.map_path = '{cwd}/Clone_{prefix}.map'.format(
+ cwd=os.path.realpath(os.getcwd()),
+ prefix=source.prefix,
+ )
else:
# Imaging
self.dest_path = '{path}/{prefix}.dd'.format(
@@ -105,19 +107,19 @@ class BlockPair():
def load_map_data(self):
"""Load data from map file and set progress."""
map_data = read_map_file(self.map_path)
- self.rescued_percent = map_data['rescued']
- self.rescued = (self.rescued_percent * self.size) / 100
+ self.rescued = map_data.get('rescued', 0)
+ self.rescued_percent = (self.rescued / self.size) * 100
if map_data['full recovery']:
self.pass_done = [True, True, True]
self.rescued = self.size
self.status = ['Skipped', 'Skipped', 'Skipped']
- elif map_data['non-tried'] > 0:
+ elif map_data.get('non-tried', 0) > 0:
# Initial pass incomplete
pass
- elif map_data['non-trimmed'] > 0:
+ elif map_data.get('non-trimmed', 0) > 0:
self.pass_done = [True, False, False]
self.status = ['Skipped', 'Pending', 'Pending']
- elif map_data['non-scraped'] > 0:
+ elif map_data.get('non-scraped', 0) > 0:
self.pass_done = [True, True, False]
self.status = ['Skipped', 'Skipped', 'Pending']
else:
@@ -145,14 +147,15 @@ class BlockPair():
"""Update progress using map file."""
if os.path.exists(self.map_path):
map_data = read_map_file(self.map_path)
- self.rescued_percent = map_data.get('rescued', 0)
- self.rescued = (self.rescued_percent * self.size) / 100
+ self.rescued = map_data.get('rescued', 0)
+ self.rescued_percent = (self.rescued / self.size) * 100
self.status[pass_num] = get_formatted_status(
label='Pass {}'.format(pass_num+1),
data=(self.rescued/self.size)*100)
class DevObj(BaseObj):
+ # pylint: disable=too-many-instance-attributes
"""Block device object."""
def self_check(self):
"""Verify that self.path points to a block device."""
@@ -186,6 +189,7 @@ class DevObj(BaseObj):
self.update_filename_prefix()
def update_filename_prefix(self):
+ # pylint: disable=attribute-defined-outside-init
"""Set filename prefix based on details."""
self.prefix = '{m_size}_{model}'.format(
m_size=self.model_size,
@@ -205,6 +209,7 @@ class DevObj(BaseObj):
class DirObj(BaseObj):
+ """Directory object."""
def self_check(self):
"""Verify that self.path points to a directory."""
if not pathlib.Path(self.path).is_dir():
@@ -222,6 +227,7 @@ class DirObj(BaseObj):
class ImageObj(BaseObj):
+ """Image file object."""
def self_check(self):
"""Verify that self.path points to a file."""
if not pathlib.Path(self.path).is_file():
@@ -243,10 +249,11 @@ class ImageObj(BaseObj):
self.report = get_device_report(self.loop_dev)
self.report = self.report.replace(
self.loop_dev[self.loop_dev.rfind('/')+1:], '(Img)')
- run_program(['losetup', '--detach', self.loop_dev], check=False)
+ run_program(['sudo', 'losetup', '--detach', self.loop_dev], check=False)
class RecoveryState():
+ # pylint: disable=too-many-instance-attributes
"""Object to track BlockPair objects and overall state."""
def __init__(self, mode, source, dest):
self.mode = mode.lower()
@@ -259,17 +266,21 @@ class RecoveryState():
self.etoc = ''
self.settings = DDRESCUE_SETTINGS.copy()
self.finished = False
+ self.ost = osTicket([], [])
self.panes = {}
self.progress_out = '{}/progress.out'.format(global_vars['LogDir'])
self.rescued = 0
self.resumed = False
self.started = False
self.status = 'Inactive'
+ self.ticket_id = None
+ self.ticket_name = None
self.timezone = pytz.timezone(LINUX_TIME_ZONE)
self.total_size = 0
if mode not in ('clone', 'image'):
raise GenericError('Unsupported mode')
self.get_smart_source()
+ self.set_working_dir()
def add_block_pair(self, source, dest):
"""Run safety checks and append new BlockPair to internal list."""
@@ -314,20 +325,180 @@ class RecoveryState():
# Safety checks passed
self.block_pairs.append(BlockPair(self.mode, source, dest))
+ def build_outer_panes(self):
+ """Build top and side panes."""
+ clear_screen()
+
+ # Top
+ self.panes['Source'] = tmux_split_window(
+ behind=True, vertical=True, lines=2,
+ text='{BLUE}Source{CLEAR}'.format(**COLORS))
+
+ # Started
+ self.panes['Started'] = tmux_split_window(
+ lines=SIDE_PANE_WIDTH, target_pane=self.panes['Source'],
+ text='{BLUE}Started{CLEAR}\n{s}'.format(
+ s=time.strftime("%Y-%m-%d %H:%M %Z"),
+ **COLORS))
+
+ # Destination
+ self.panes['Destination'] = tmux_split_window(
+ percent=50, target_pane=self.panes['Source'],
+ text='{BLUE}Destination{CLEAR}'.format(**COLORS))
+
+ # Progress
+ update_sidepane(self)
+ self.panes['Progress'] = tmux_split_window(
+ lines=SIDE_PANE_WIDTH, watch=self.progress_out)
+
def current_pass_done(self):
"""Checks if pass is done for all block-pairs, returns bool."""
done = True
- for bp in self.block_pairs:
- done &= bp.pass_done[self.current_pass]
+ for b_pair in self.block_pairs:
+ done = done and b_pair.pass_done[self.current_pass]
return done
def current_pass_min(self):
"""Gets minimum pass rescued percentage, returns float."""
min_percent = 100
- for bp in self.block_pairs:
- min_percent = min(min_percent, bp.rescued_percent)
+ for b_pair in self.block_pairs:
+ min_percent = min(min_percent, b_pair.rescued_percent)
return min_percent
+ def fix_tmux_panes(self, forced=False):
+ # pylint: disable=too-many-branches,too-many-locals
+ """Fix pane sizes if the winodw has been resized."""
+ needs_fixed = False
+
+ # Check layout
+ for pane, pane_data in TMUX_LAYOUT.items():
+ if not pane_data.get('Check'):
+ # Not concerned with the size of this pane
+ continue
+ # Get target
+ target = None
+ if pane != 'Current':
+ if pane not in self.panes:
+ # Skip missing panes
+ continue
+ else:
+ target = self.panes[pane]
+
+ # Check pane size
+ size_x, size_y = tmux_get_pane_size(pane_id=target)
+ if pane_data.get('x', False) and pane_data['x'] != size_x:
+ needs_fixed = True
+ if pane_data.get('y', False) and pane_data['y'] != size_y:
+ needs_fixed = True
+
+ # Bail?
+ if not needs_fixed and not forced:
+ return
+
+ # Remove Destination pane (temporarily)
+ tmux_kill_pane(self.panes['Destination'])
+
+ # Update layout
+ for pane, pane_data in TMUX_LAYOUT.items():
+ # Get target
+ target = None
+ if pane != 'Current':
+ if pane not in self.panes:
+ # Skip missing panes
+ continue
+ else:
+ target = self.panes[pane]
+
+ # Resize pane
+ tmux_resize_pane(pane_id=target, **pane_data)
+
+ # Calc Source/Destination pane sizes
+ width, height = tmux_get_pane_size()
+ width = int(width / 2) - 1
+
+ # Update Source string
+ source_str = self.source.name
+ if len(source_str) > width:
+ source_str = '{}...'.format(source_str[:width-3])
+
+ # Update Destination string
+ dest_str = self.dest.name
+ if len(dest_str) > width:
+ if self.mode == 'clone':
+ dest_str = '{}...'.format(dest_str[:width-3])
+ else:
+ dest_str = '...{}'.format(dest_str[-width+3:])
+
+ # Rebuild Source/Destination panes
+ tmux_update_pane(
+ pane_id=self.panes['Source'],
+ text='{BLUE}Source{CLEAR}\n{s}'.format(
+ s=source_str, **COLORS))
+ self.panes['Destination'] = tmux_split_window(
+ percent=50, target_pane=self.panes['Source'],
+ text='{BLUE}Destination{CLEAR}\n{s}'.format(
+ s=dest_str, **COLORS))
+
+ if 'SMART' in self.panes:
+ # Calc SMART/ddrescue/Journal panes sizes
+ ratio = [12, 22, 4]
+ width, height = tmux_get_pane_size(pane_id=self.panes['Progress'])
+ height -= 2
+ total = sum(ratio)
+ p_ratio = [int((x/total) * height) for x in ratio]
+ p_ratio[1] = height - p_ratio[0] - p_ratio[2]
+
+ # Resize SMART/Journal panes
+ tmux_resize_pane(self.panes['SMART'], y=ratio[0])
+ tmux_resize_pane(y=ratio[1])
+ tmux_resize_pane(self.panes['Journal'], y=ratio[2])
+
+ def generate_report(self):
+ """Generate report for osTicket post, returns list."""
+ report = ['']
+ test_station = TEST_STATIONS.get(get_hostname().lower(), '')
+
+ # Header
+ if test_station:
+ report[0] += '[Test-Station: {}] '.format(test_station)
+ report[0] += '[Report for ticket #{} {}]'.format(
+ self.ticket_id, self.ticket_name)
+ report.append('ddrescue-tui {} results'.format(self.mode))
+
+ # Source/Dest
+ report.append(' ')
+ report.append('Source: {}'.format(self.source.name))
+ report.append('Destination: {}'.format(self.dest.name))
+
+ # Overall
+ try:
+ percent = (self.rescued / self.total_size) * 100
+ except ZeroDivisionError:
+ percent = 0
+ report.append(' ')
+ report.append('Overall rescued: {:0.2f}% error size: {}'.format(
+ percent,
+ human_readable_size(self.total_size-self.rescued, decimals=2),
+ ))
+
+ # Block-Pairs
+ if len(self.block_pairs) > 1:
+ report.append(' ')
+ for b_pair in self.block_pairs:
+ try:
+ percent = (b_pair.rescued / b_pair.size) * 100
+ except ZeroDivisionError:
+ percent = 0
+ report.append('{} ({}) rescued: {:0.2f}% error size: {}'.format(
+ b_pair.source.path,
+ human_readable_size(b_pair.source.size, decimals=1),
+ percent,
+ human_readable_size(b_pair.size-b_pair.rescued, decimals=2),
+ ))
+
+ # Done
+ return report
+
def get_smart_source(self):
"""Get source for SMART dispay."""
disk_path = self.source.path
@@ -339,18 +510,15 @@ class RecoveryState():
def retry_all_passes(self):
"""Mark all passes as pending for all block-pairs."""
self.finished = False
- for bp in self.block_pairs:
- bp.pass_done = [False, False, False]
- bp.status = ['Pending', 'Pending', 'Pending']
- bp.fix_status_strings()
+ for b_pair in self.block_pairs:
+ b_pair.pass_done = [False, False, False]
+ b_pair.status = ['Pending', 'Pending', 'Pending']
+ b_pair.fix_status_strings()
self.set_pass_num()
def self_checks(self):
"""Run self-checks and update state values."""
cmd = ['findmnt', '--json', '--target', os.getcwd()]
- map_allowed_fstypes = RECOMMENDED_FSTYPES.copy()
- map_allowed_fstypes.extend(['cifs', 'ext2', 'vfat'])
- map_allowed_fstypes.sort()
json_data = get_json_from_command(cmd)
# Abort if json_data is empty
@@ -361,23 +529,24 @@ class RecoveryState():
# Avoid saving map to non-persistent filesystem
fstype = json_data.get(
'filesystems', [{}])[0].get(
- 'fstype', 'unknown')
- if fstype not in map_allowed_fstypes:
+ 'fstype', 'unknown')
+ if fstype not in RECOMMENDED_MAP_FSTYPES:
print_error(
"Map isn't being saved to a recommended filesystem ({})".format(
fstype.upper()))
print_info('Recommended types are: {}'.format(
- ' / '.join(map_allowed_fstypes).upper()))
+ ' / '.join(RECOMMENDED_MAP_FSTYPES).upper()))
print_standard(' ')
if not ask('Proceed anyways? (Strongly discouraged)'):
raise GenericAbort()
# Run BlockPair self checks and get total size
self.total_size = 0
- for bp in self.block_pairs:
- bp.self_check()
- self.resumed |= bp.resumed
- self.total_size += bp.size
+ for b_pair in self.block_pairs:
+ b_pair.self_check()
+ if b_pair.resumed:
+ self.resumed = True
+ self.total_size += b_pair.size
def set_pass_num(self):
"""Set current pass based on all block-pair's progress."""
@@ -385,8 +554,8 @@ class RecoveryState():
for pass_num in (2, 1, 0):
# Iterate backwards through passes
pass_done = True
- for bp in self.block_pairs:
- pass_done &= bp.pass_done[pass_num]
+ for b_pair in self.block_pairs:
+ pass_done = pass_done and b_pair.pass_done[pass_num]
if pass_done:
# All block-pairs reported being done
# Set to next pass, unless we're on the last pass (2)
@@ -404,6 +573,47 @@ class RecoveryState():
elif self.current_pass == 2:
self.current_pass_str = '3 "Scraping bad areas"'
+ def set_working_dir(self):
+ """Set working dir to MAP_DIR if possible.
+
+ NOTE: This is to help ensure the map file
+ is saved to non-volatile storage."""
+ map_dir = '{}/{}'.format(MAP_DIR, global_vars['Date-Time'])
+
+ # Get Ticket ID
+ if not self.ost.disabled:
+ try:
+ self.ticket_id, self.ticket_name = self.ost.get_ticket_details()
+ except TypeError:
+ # Happens if connection fails and retry is not attempted
+ pass
+ if self.ticket_id and self.ticket_name:
+ map_dir = '{}/{}_{}'.format(
+ MAP_DIR,
+ self.ticket_id,
+ self.ticket_name.replace(' ', '-'),
+ )
+
+ # Mount backup shares
+ mount_backup_shares(read_write=True)
+
+ # Get MAP_DIR filesystem type
+ # NOTE: If the backup share fails to mount then this will
+ # likely be the type of /
+ cmd = [
+ 'findmnt',
+ '--noheadings',
+ '--target', MAP_DIR,
+ '--output', 'FSTYPE',
+ ]
+ result = run_program(cmd, check=False, encoding='utf-8', errors='ingnore')
+ map_dir_type = result.stdout.strip().lower()
+
+ # Change working dir if map_dir_type is acceptable
+ if map_dir_type in RECOMMENDED_MAP_FSTYPES:
+ os.makedirs(map_dir, exist_ok=True)
+ os.chdir(map_dir)
+
def update_etoc(self):
"""Search ddrescue output for the current EToC, returns str."""
now = datetime.datetime.now(tz=self.timezone)
@@ -413,7 +623,7 @@ class RecoveryState():
# Just set to N/A (NOTE: this overrules the refresh rate below)
self.etoc = 'N/A'
return
- elif 'In Progress' not in self.status:
+ if 'In Progress' not in self.status:
# Don't update when EToC is hidden
return
if now.second % ETOC_REFRESH_RATE != 0:
@@ -427,13 +637,14 @@ class RecoveryState():
# Capture main tmux pane
try:
text = tmux_capture_pane()
- except Exception:
+ except Exception: # pylint: disable=broad-except
# Ignore
pass
# Search for EToC delta
matches = re.findall(r'remaining time:.*$', text, re.MULTILINE)
if matches:
+ # pylint: disable=invalid-name
r = REGEX_REMAINING_TIME.search(matches[-1])
if r.group('na'):
self.etoc = 'N/A'
@@ -450,7 +661,7 @@ class RecoveryState():
minutes=int(minutes),
seconds=int(seconds),
)
- except Exception:
+ except Exception: # pylint: disable=broad-except
# Ignore and leave as raw string
pass
@@ -460,15 +671,16 @@ class RecoveryState():
now = datetime.datetime.now(tz=self.timezone)
_etoc = now + etoc_delta
self.etoc = _etoc.strftime('%Y-%m-%d %H:%M %Z')
- except Exception:
+ except Exception: # pylint: disable=broad-except
# Ignore and leave as current string
pass
def update_progress(self):
+ # pylint: disable=attribute-defined-outside-init
"""Update overall progress using block_pairs."""
self.rescued = 0
- for bp in self.block_pairs:
- self.rescued += bp.rescued
+ for b_pair in self.block_pairs:
+ self.rescued += b_pair.rescued
self.rescued_percent = (self.rescued / self.total_size) * 100
self.status_percent = get_formatted_status(
label='Recovered:', data=self.rescued_percent)
@@ -477,26 +689,6 @@ class RecoveryState():
# Functions
-def build_outer_panes(state):
- """Build top and side panes."""
- state.panes['Source'] = tmux_split_window(
- behind=True, vertical=True, lines=2,
- text='{BLUE}Source{CLEAR}'.format(**COLORS))
- state.panes['Started'] = tmux_split_window(
- lines=SIDE_PANE_WIDTH, target_pane=state.panes['Source'],
- text='{BLUE}Started{CLEAR}\n{s}'.format(
- s=time.strftime("%Y-%m-%d %H:%M %Z"),
- **COLORS))
- state.panes['Destination'] = tmux_split_window(
- percent=50, target_pane=state.panes['Source'],
- text='{BLUE}Destination{CLEAR}'.format(**COLORS))
-
- # Side pane
- update_sidepane(state)
- state.panes['Progress'] = tmux_split_window(
- lines=SIDE_PANE_WIDTH, watch=state.progress_out)
-
-
def create_path_obj(path):
"""Create Dev, Dir, or Image obj based on path given."""
obj = None
@@ -514,101 +706,16 @@ def create_path_obj(path):
def double_confirm_clone():
"""Display warning and get 2nd confirmation, returns bool."""
print_standard('\nSAFETY CHECK')
- print_warning('All data will be DELETED from the '
- 'destination device and partition(s) listed above.')
- print_warning('This is irreversible and will lead '
- 'to {CLEAR}{RED}DATA LOSS.'.format(**COLORS))
+ print_warning(
+ 'All data will be DELETED from the '
+ 'destination device and partition(s) listed above.'
+ )
+ print_warning(
+ 'This is irreversible and will lead to {CLEAR}{RED}DATA LOSS.'.format(
+ **COLORS))
return ask('Asking again to confirm, is this correct?')
-def fix_tmux_panes(state, forced=False):
- """Fix pane sizes if the winodw has been resized."""
- needs_fixed = False
-
- # Check layout
- for k, v in TMUX_LAYOUT.items():
- if not v.get('Check'):
- # Not concerned with the size of this pane
- continue
- # Get target
- target = None
- if k != 'Current':
- if k not in state.panes:
- # Skip missing panes
- continue
- else:
- target = state.panes[k]
-
- # Check pane size
- x, y = tmux_get_pane_size(pane_id=target)
- if v.get('x', False) and v['x'] != x:
- needs_fixed = True
- if v.get('y', False) and v['y'] != y:
- needs_fixed = True
-
- # Bail?
- if not needs_fixed and not forced:
- return
-
- # Remove Destination pane (temporarily)
- tmux_kill_pane(state.panes['Destination'])
-
- # Update layout
- for k, v in TMUX_LAYOUT.items():
- # Get target
- target = None
- if k != 'Current':
- if k not in state.panes:
- # Skip missing panes
- continue
- else:
- target = state.panes[k]
-
- # Resize pane
- tmux_resize_pane(pane_id=target, **v)
-
- # Calc Source/Destination pane sizes
- width, height = tmux_get_pane_size()
- width = int(width / 2) - 1
-
- # Update Source string
- source_str = state.source.name
- if len(source_str) > width:
- source_str = '{}...'.format(source_str[:width-3])
-
- # Update Destination string
- dest_str = state.dest.name
- if len(dest_str) > width:
- if state.mode == 'clone':
- dest_str = '{}...'.format(dest_str[:width-3])
- else:
- dest_str = '...{}'.format(dest_str[-width+3:])
-
- # Rebuild Source/Destination panes
- tmux_update_pane(
- pane_id=state.panes['Source'],
- text='{BLUE}Source{CLEAR}\n{s}'.format(
- s=source_str, **COLORS))
- state.panes['Destination'] = tmux_split_window(
- percent=50, target_pane=state.panes['Source'],
- text='{BLUE}Destination{CLEAR}\n{s}'.format(
- s=dest_str, **COLORS))
-
- if 'SMART' in state.panes:
- # Calc SMART/ddrescue/Journal panes sizes
- ratio = [12, 22, 4]
- width, height = tmux_get_pane_size(pane_id=state.panes['Progress'])
- height -= 2
- total = sum(ratio)
- p_ratio = [int((x/total) * height) for x in ratio]
- p_ratio[1] = height - p_ratio[0] - p_ratio[2]
-
- # Resize SMART/Journal panes
- tmux_resize_pane(state.panes['SMART'], y=ratio[0])
- tmux_resize_pane(y=ratio[1])
- tmux_resize_pane(state.panes['Journal'], y=ratio[2])
-
-
def get_device_details(dev_path):
"""Get device details via lsblk, returns JSON dict."""
cmd = ['lsblk', '--json', '--output-all', '--paths', dev_path]
@@ -677,22 +784,22 @@ def get_dir_report(dir_path):
output.append('{BLUE}{label:<{width}}{line}{CLEAR}'.format(
label='PATH',
width=width,
- line=line.replace('\n',''),
+ line=line.replace('\n', ''),
**COLORS))
else:
output.append('{path:<{width}}{line}'.format(
path=dir_path,
width=width,
- line=line.replace('\n','')))
+ line=line.replace('\n', '')))
# Done
return '\n'.join(output)
-def get_size_in_bytes(s):
+def get_size_in_bytes(size):
"""Convert size string from lsblk string to bytes, returns int."""
- s = re.sub(r'(\d+\.?\d*)\s*([KMGTB])B?', r'\1 \2B', s, re.IGNORECASE)
- return convert_to_bytes(s)
+ size = re.sub(r'(\d+\.?\d*)\s*([KMGTB])B?', r'\1 \2B', size, re.IGNORECASE)
+ return convert_to_bytes(size)
def get_formatted_status(label, data):
@@ -700,13 +807,15 @@ def get_formatted_status(label, data):
data_width = SIDE_PANE_WIDTH - len(label)
try:
data_str = '{data:>{data_width}.2f} %'.format(
- data=data,
- data_width=data_width-2)
+ data=data,
+ data_width=data_width-2,
+ )
except ValueError:
# Assuming non-numeric data
data_str = '{data:>{data_width}}'.format(
- data=data,
- data_width=data_width)
+ data=data,
+ data_width=data_width,
+ )
status = '{label}{s_color}{data_str}{CLEAR}'.format(
label=label,
s_color=get_status_color(data),
@@ -715,19 +824,19 @@ def get_formatted_status(label, data):
return status
-def get_status_color(s, t_success=99, t_warn=90):
+def get_status_color(status, t_success=99, t_warn=90):
"""Get color based on status, returns str."""
color = COLORS['CLEAR']
p_recovered = -1
try:
- p_recovered = float(s)
+ p_recovered = float(status)
except ValueError:
# Status is either in lists below or will default to red
pass
- if s in ('Pending',) or str(s)[-2:] in (' b', 'Kb', 'Mb', 'Gb', 'Tb'):
+ if status == 'Pending' or str(status)[-2:] in (' b', 'Kb', 'Mb', 'Gb', 'Tb'):
color = COLORS['CLEAR']
- elif s in ('Skipped', 'Unknown'):
+ elif status in ('Skipped', 'Unknown'):
color = COLORS['YELLOW']
elif p_recovered >= t_success:
color = COLORS['GREEN']
@@ -742,9 +851,9 @@ def is_writable_dir(dir_obj):
"""Check if we have read-write-execute permissions, returns bool."""
is_ok = True
path_st_mode = os.stat(dir_obj.path).st_mode
- is_ok == is_ok and path_st_mode & stat.S_IRUSR
- is_ok == is_ok and path_st_mode & stat.S_IWUSR
- is_ok == is_ok and path_st_mode & stat.S_IXUSR
+ is_ok = is_ok and path_st_mode & stat.S_IRUSR
+ is_ok = is_ok and path_st_mode & stat.S_IWUSR
+ is_ok = is_ok and path_st_mode & stat.S_IXUSR
return is_ok
@@ -754,6 +863,7 @@ def is_writable_filesystem(dir_obj):
def menu_ddrescue(source_path, dest_path, run_mode):
+ # pylint: disable=too-many-branches
"""ddrescue menu."""
source = None
dest = None
@@ -797,17 +907,35 @@ def menu_ddrescue(source_path, dest_path, run_mode):
raise GenericAbort()
# Main menu
- clear_screen()
- build_outer_panes(state)
- fix_tmux_panes(state, forced=True)
+ state.build_outer_panes()
+ state.fix_tmux_panes(forced=True)
menu_main(state)
+ # Post results
+ if ask('Post results to osTicket?'):
+ if not state.ticket_id:
+ # (Re)enable osTicket
+ state.ost.disabled = False
+ try:
+ state.ticket_id, state.ticket_name = state.ost.get_ticket_details()
+ except TypeError:
+ # Happens if connection fails and retry is not attempted
+ pass
+
+ # Post
+ if state.ticket_id:
+ state.ost.post_response(state.generate_report(), state.ticket_id)
+ print_standard('Done')
+ print_standard(' ')
+ pause('Press Enter to exit... ')
+
# Done
run_program(['tmux', 'kill-window'])
exit_script()
def menu_main(state):
+ # pylint: disable=too-many-branches,too-many-statements
"""Main menu is used to set ddrescue settings."""
checkmark = '*'
if 'DISPLAY' in global_vars['Env']:
@@ -818,16 +946,15 @@ def menu_main(state):
# Build menu
main_options = [
{'Base Name': 'Auto continue (if recovery % over threshold)',
- 'Enabled': True},
+ 'Enabled': True},
{'Base Name': 'Retry (mark non-rescued sectors "non-tried")',
- 'Enabled': False},
+ 'Enabled': False},
{'Base Name': 'Reverse direction', 'Enabled': False},
]
actions = [
{'Name': 'Start', 'Letter': 'S'},
- {'Name': 'Change settings {YELLOW}(experts only){CLEAR}'.format(
- **COLORS),
- 'Letter': 'C'},
+ {'Name': 'Change settings {YELLOW}(experts only){CLEAR}'.format(**COLORS),
+ 'Letter': 'C'},
{'Name': 'Quit', 'Letter': 'Q', 'CRLF': True},
]
@@ -858,13 +985,13 @@ def menu_main(state):
elif selection == 'S':
# Set settings for pass
pass_settings = []
- for k, v in state.settings.items():
- if not v['Enabled']:
+ for option, option_data in state.settings.items():
+ if not option_data['Enabled']:
continue
- if 'Value' in v:
- pass_settings.append('{}={}'.format(k, v['Value']))
+ if 'Value' in option_data:
+ pass_settings.append('{}={}'.format(option, option_data['Value']))
else:
- pass_settings.append(k)
+ pass_settings.append(option)
for opt in main_options:
if 'Auto' in opt['Base Name']:
auto_run = opt['Enabled']
@@ -887,7 +1014,7 @@ def menu_main(state):
state.current_pass_min() < AUTO_PASS_1_THRESHOLD):
auto_run = False
elif (state.current_pass == 1 and
- state.current_pass_min() < AUTO_PASS_2_THRESHOLD):
+ state.current_pass_min() < AUTO_PASS_2_THRESHOLD):
auto_run = False
else:
auto_run = False
@@ -916,13 +1043,15 @@ def menu_settings(state):
# Build menu
settings = []
- for k, v in sorted(state.settings.items()):
- if not v.get('Hidden', False):
- settings.append({'Base Name': k, 'Flag': k})
+ for option, option_data in sorted(state.settings.items()):
+ if not option_data.get('Hidden', False):
+ settings.append({'Base Name': option, 'Flag': option})
actions = [{'Name': 'Main Menu', 'Letter': 'M'}]
# Show menu
while True:
+ # pylint: disable=invalid-name
+ # TODO: Clean up and/or replace with new menu-select function
for s in settings:
s['Name'] = '{}{}{}'.format(
s['Base Name'],
@@ -959,25 +1088,27 @@ def menu_settings(state):
def read_map_file(map_path):
"""Read map file with ddrescuelog and return data as dict."""
- map_data = {'full recovery': False}
+ cmd = [
+ 'ddrescuelog',
+ '--binary-prefixes',
+ '--show-status',
+ map_path,
+ ]
+ map_data = {'full recovery': False, 'pass completed': False}
try:
- result = run_program(['ddrescuelog', '-t', map_path])
+ result = run_program(cmd, encoding='utf-8', errors='ignore')
except CalledProcessError:
# (Grossly) assuming map_data hasn't been saved yet, return empty dict
return map_data
# Parse output
- for line in result.stdout.decode().splitlines():
- m = re.match(
- r'^\s*(?P\S+):.*\(\s*(?P\d+\.?\d*)%.*', line.strip())
- if m:
- try:
- map_data[m.group('key')] = float(m.group('value'))
- except ValueError:
- raise GenericError('Failed to read map data')
- m = re.match(r'.*current status:\s+(?P.*)', line.strip())
- if m:
- map_data['pass completed'] = bool(m.group('status') == 'finished')
+ for line in result.stdout.splitlines():
+ line = line.strip()
+ _r = REGEX_DDRESCUE_LOG.search(line)
+ if _r:
+ map_data[_r.group('key')] = convert_to_bytes('{size} {unit}B'.format(
+ **_r.groupdict()))
+ map_data['pass completed'] = 'current status: finished' in line
# Check if 100% done
try:
@@ -991,6 +1122,7 @@ def read_map_file(map_path):
def run_ddrescue(state, pass_settings):
+ # pylint: disable=too-many-branches,too-many-statements
"""Run ddrescue pass."""
return_code = -1
aborted = False
@@ -1005,8 +1137,8 @@ def run_ddrescue(state, pass_settings):
# Create SMART monitor pane
state.smart_out = '{}/smart_{}.out'.format(
global_vars['TmpDir'], state.smart_source.name)
- with open(state.smart_out, 'w') as f:
- f.write('Initializing...')
+ with open(state.smart_out, 'w') as _f:
+ _f.write('Initializing...')
state.panes['SMART'] = tmux_split_window(
behind=True, lines=12, vertical=True, watch=state.smart_out)
@@ -1016,19 +1148,19 @@ def run_ddrescue(state, pass_settings):
command=['sudo', 'journalctl', '-f'])
# Fix layout
- fix_tmux_panes(state, forced=True)
+ state.fix_tmux_panes(forced=True)
# Run pass for each block-pair
- for bp in state.block_pairs:
- if bp.pass_done[state.current_pass]:
+ for b_pair in state.block_pairs:
+ if b_pair.pass_done[state.current_pass]:
# Skip to next block-pair
continue
update_sidepane(state)
# Set ddrescue cmd
cmd = [
- 'ddrescue', *pass_settings,
- bp.source_path, bp.dest_path, bp.map_path]
+ 'sudo', 'ddrescue', *pass_settings,
+ b_pair.source_path, b_pair.dest_path, b_pair.map_path]
if state.mode == 'clone':
cmd.append('--force')
if state.current_pass == 0:
@@ -1043,36 +1175,36 @@ def run_ddrescue(state, pass_settings):
# Start ddrescue
try:
clear_screen()
- print_info('Current dev: {}'.format(bp.source_path))
+ print_info('Current dev: {}'.format(b_pair.source_path))
ddrescue_proc = popen_program(cmd)
i = 0
while True:
# Update SMART display (every 30 seconds)
if i % 30 == 0:
state.smart_source.get_smart_details()
- with open(state.smart_out, 'w') as f:
+ with open(state.smart_out, 'w') as _f:
report = state.smart_source.generate_attribute_report(
- timestamp=True)
+ timestamp=True)
for line in report:
- f.write('{}\n'.format(line))
+ _f.write('{}\n'.format(line))
i += 1
# Update progress
- bp.update_progress(state.current_pass)
+ b_pair.update_progress(state.current_pass)
update_sidepane(state)
# Fix panes
- fix_tmux_panes(state)
+ state.fix_tmux_panes()
# Check if ddrescue has finished
try:
ddrescue_proc.wait(timeout=1)
sleep(2)
- bp.update_progress(state.current_pass)
+ b_pair.update_progress(state.current_pass)
update_sidepane(state)
break
except subprocess.TimeoutExpired:
- # Catch to update smart/bp/sidepane
+ # Catch to update smart/b_pair/sidepane
pass
except KeyboardInterrupt:
@@ -1081,7 +1213,7 @@ def run_ddrescue(state, pass_settings):
ddrescue_proc.wait(timeout=10)
# Update progress/sidepane again
- bp.update_progress(state.current_pass)
+ b_pair.update_progress(state.current_pass)
update_sidepane(state)
# Was ddrescue aborted?
@@ -1103,7 +1235,7 @@ def run_ddrescue(state, pass_settings):
break
else:
# Mark pass finished
- bp.finish_pass(state.current_pass)
+ b_pair.finish_pass(state.current_pass)
update_sidepane(state)
# Done
@@ -1119,6 +1251,8 @@ def run_ddrescue(state, pass_settings):
def select_parts(source_device):
+ # pylint: disable=too-many-branches
+ # TODO: Clean up and/or replace with new menu-select function
"""Select partition(s) or whole device, returns list of DevObj()s."""
selected_parts = []
children = source_device.details.get('children', [])
@@ -1180,24 +1314,26 @@ def select_parts(source_device):
raise GenericAbort()
# Build list of selected parts
- for d in dev_options:
- if d['Selected']:
- d['Dev'].model = source_device.model
- d['Dev'].model_size = source_device.model_size
- d['Dev'].update_filename_prefix()
- selected_parts.append(d['Dev'])
+ for _d in dev_options:
+ if _d['Selected']:
+ _d['Dev'].model = source_device.model
+ _d['Dev'].model_size = source_device.model_size
+ _d['Dev'].update_filename_prefix()
+ selected_parts.append(_d['Dev'])
return selected_parts
def select_path(skip_device=None):
+ # pylint: disable=too-many-branches,too-many-locals
+ # TODO: Clean up and/or replace with new menu-select function
"""Optionally mount local dev and select path, returns DirObj."""
- wd = os.path.realpath(global_vars['Env']['PWD'])
+ work_dir = os.path.realpath(global_vars['Env']['PWD'])
selected_path = None
# Build menu
path_options = [
- {'Name': 'Current directory: {}'.format(wd), 'Path': wd},
+ {'Name': 'Current directory: {}'.format(work_dir), 'Path': work_dir},
{'Name': 'Local device', 'Path': None},
{'Name': 'Enter manually', 'Path': None}]
actions = [{'Name': 'Quit', 'Letter': 'Q'}]
@@ -1212,9 +1348,9 @@ def select_path(skip_device=None):
raise GenericAbort()
elif selection.isnumeric():
index = int(selection) - 1
- if path_options[index]['Path'] == wd:
+ if path_options[index]['Path'] == work_dir:
# Current directory
- selected_path = DirObj(wd)
+ selected_path = DirObj(work_dir)
elif path_options[index]['Name'] == 'Local device':
# Local device
@@ -1230,15 +1366,15 @@ def select_path(skip_device=None):
# Select volume
vol_options = []
- for k, v in sorted(report.items()):
- disabled = v['show_data']['data'] == 'Failed to mount'
+ for _k, _v in sorted(report.items()):
+ disabled = _v['show_data']['data'] == 'Failed to mount'
if disabled:
- name = '{name} (Failed to mount)'.format(**v)
+ name = '{name} (Failed to mount)'.format(**_v)
else:
- name = '{name} (mounted on "{mount_point}")'.format(**v)
+ name = '{name} (mounted on "{mount_point}")'.format(**_v)
vol_options.append({
'Name': name,
- 'Path': v['mount_point'],
+ 'Path': _v['mount_point'],
'Disabled': disabled})
selection = menu_select(
title='Please select a volume',
@@ -1313,15 +1449,17 @@ def select_device(description='device', skip_device=None):
action_entries=actions,
disabled_label='ALREADY SELECTED')
+ if selection == 'Q':
+ raise GenericAbort()
+
if selection.isnumeric():
return dev_options[int(selection)-1]['Dev']
- elif selection == 'Q':
- raise GenericAbort()
def setup_loopback_device(source_path):
"""Setup loopback device for source_path, returns dev_path as str."""
cmd = (
+ 'sudo',
'losetup',
'--find',
'--partscan',
@@ -1355,6 +1493,7 @@ def show_selection_details(state):
def show_usage(script_name):
+ """Show usage."""
print_info('Usage:')
print_standard(USAGE.format(script_name=script_name))
pause()
@@ -1378,14 +1517,14 @@ def update_sidepane(state):
output.append('─────────────────────')
# Source(s) progress
- for bp in state.block_pairs:
+ for b_pair in state.block_pairs:
if state.source.is_image():
output.append('{BLUE}Image File{CLEAR}'.format(**COLORS))
else:
output.append('{BLUE}{source}{CLEAR}'.format(
- source=bp.source_path,
+ source=b_pair.source_path,
**COLORS))
- output.extend(bp.status)
+ output.extend(b_pair.status)
output.append(' ')
# EToC
@@ -1404,11 +1543,9 @@ def update_sidepane(state):
# Add line-endings
output = ['{}\n'.format(line) for line in output]
- with open(state.progress_out, 'w') as f:
- f.writelines(output)
+ with open(state.progress_out, 'w') as _f:
+ _f.writelines(output)
if __name__ == '__main__':
print("This file is not meant to be called directly.")
-
-# vim: sts=2 sw=2 ts=2
diff --git a/.bin/Scripts/functions/hw_diags.py b/.bin/Scripts/functions/hw_diags.py
index 8a5a441f..ec5b2373 100644
--- a/.bin/Scripts/functions/hw_diags.py
+++ b/.bin/Scripts/functions/hw_diags.py
@@ -59,6 +59,13 @@ class CpuObj():
report.append('{BLUE}Device{CLEAR}'.format(**COLORS))
report.append(' {}'.format(self.name))
+ # Include RAM details
+ ram_details = get_ram_details()
+ ram_total = human_readable_size(ram_details.pop('Total', 0)).strip()
+ ram_dimms = ['{}x {}'.format(v, k) for k, v in sorted(ram_details.items())]
+ report.append('{BLUE}RAM{CLEAR}'.format(**COLORS))
+ report.append(' {} ({})'.format(ram_total, ', '.join(ram_dimms)))
+
# Tests
for test in self.tests.values():
report.extend(test.report)
@@ -87,7 +94,15 @@ class DiskObj():
self.get_size()
# Try enabling SMART
- run_program(['sudo', 'smartctl', '--smart=on', self.path], check=False)
+ run_program(
+ cmd=[
+ 'sudo',
+ 'smartctl',
+ '--tolerance=permissive',
+ '--smart=on',
+ self.path,
+ ],
+ check=False)
# Get NVMe/SMART data and set description
self.get_smart_details()
@@ -181,8 +196,8 @@ class DiskObj():
disk_ok = False
# Disable override if necessary
- self.override_disabled |= ATTRIBUTES[attr_type][k].get(
- 'Critical', False)
+ if ATTRIBUTES[attr_type][k].get('Critical', False):
+ self.override_disabled = True
# SMART overall assessment
## NOTE: Only fail drives if the overall value exists and reports failed
@@ -303,6 +318,11 @@ class DiskObj():
attr_type=self.attr_type, **COLORS))
report.extend(sorted(self.nvme_smart_notes.keys()))
+ # 4K alignment check
+ if not self.is_4k_aligned():
+ report.append('{YELLOW}Warning{CLEAR}'.format(**COLORS))
+ report.append(' One or more partitions are not 4K aligned')
+
# Tests
for test in self.tests.values():
report.extend(test.report)
@@ -353,8 +373,15 @@ class DiskObj():
def get_smart_details(self):
"""Get data from smartctl."""
- cmd = ['sudo', 'smartctl', '--all', '--json', self.path]
- self.smartctl = get_json_from_command(cmd)
+ cmd = [
+ 'sudo',
+ 'smartctl',
+ '--tolerance=verypermissive',
+ '--all',
+ '--json',
+ self.path,
+ ]
+ self.smartctl = get_json_from_command(cmd, check=False)
# Check for attributes
if KEY_NVME in self.smartctl:
@@ -399,6 +426,26 @@ class DiskObj():
'self_test', {}).get(
k, {})
+ def is_4k_aligned(self):
+ """Check if partitions are 4K aligned, returns bool."""
+ cmd = [
+ 'sudo',
+ 'sfdisk',
+ '--json',
+ self.path,
+ ]
+ aligned = True
+
+ # Get partition details
+ json_data = get_json_from_command(cmd)
+
+ # Check partitions
+ for part in json_data.get('partitiontable', {}).get('partitions', []):
+ aligned = aligned and part.get('start', -1) % 4096 == 0
+
+ # Done
+ return aligned
+
def safety_check(self, silent=False):
"""Run safety checks and disable tests if necessary."""
test_running = False
@@ -459,6 +506,7 @@ class DiskObj():
class State():
"""Object to track device objects and overall state."""
def __init__(self):
+ self.args = None
self.cpu = None
self.disks = []
self.ost = osTicket(TESTS_CPU, TESTS_DISK)
@@ -489,6 +537,83 @@ class State():
self.ticket_name = None
self.ticket_id = None
+ def build_outer_panes(self):
+ """Build top and side panes."""
+ clear_screen()
+
+ # Top
+ self.panes['Top'] = tmux_split_window(
+ behind=True, lines=2, vertical=True,
+ text=TOP_PANE_TEXT)
+
+ # Started
+ self.panes['Started'] = tmux_split_window(
+ lines=SIDE_PANE_WIDTH, target_pane=self.panes['Top'],
+ text='{BLUE}Started{CLEAR}\n{s}'.format(
+ s=time.strftime("%Y-%m-%d %H:%M %Z"),
+ **COLORS))
+
+ # Progress
+ self.panes['Progress'] = tmux_split_window(
+ lines=SIDE_PANE_WIDTH,
+ watch=self.progress_out)
+
+ def fix_tmux_panes(self):
+ """Fix pane sizes if the window has been resized."""
+ needs_fixed = False
+
+ # Bail?
+ if not self.panes:
+ return
+
+ # Check layout
+ for k, v in self.tmux_layout.items():
+ if not v.get('Check'):
+ # Not concerned with the size of this pane
+ continue
+ # Get target
+ target = None
+ if k != 'Current':
+ if k not in self.panes:
+ # Skip missing panes
+ continue
+ else:
+ target = self.panes[k]
+
+ # Check pane size
+ x, y = tmux_get_pane_size(pane_id=target)
+ if v.get('x', False) and v['x'] != x:
+ needs_fixed = True
+ if v.get('y', False) and v['y'] != y:
+ needs_fixed = True
+
+ # Bail?
+ if not needs_fixed:
+ return
+
+ # Update layout
+ for k, v in self.tmux_layout.items():
+ # Get target
+ target = None
+ if k != 'Current':
+ if k not in self.panes:
+ # Skip missing panes
+ continue
+ else:
+ target = self.panes[k]
+
+ # Resize pane
+ tmux_resize_pane(pane_id=target, **v)
+
+ def fix_tmux_panes_loop(self):
+ while True:
+ try:
+ self.fix_tmux_panes()
+ sleep(1)
+ except RuntimeError:
+ # Assuming layout definitions changes mid-run, ignoring
+ pass
+
def init(self):
"""Remove test objects, set log, and add devices."""
self.disks = []
@@ -534,7 +659,7 @@ class State():
# Start tmux thread
self.tmux_layout = TMUX_LAYOUT.copy()
- start_thread(fix_tmux_panes_loop, args=[self])
+ start_thread(self.fix_tmux_panes_loop)
def set_top_pane_text(self, text):
"""Set top pane text using TOP_PANE_TEXT and provided text."""
@@ -578,28 +703,6 @@ class TestObj():
# Functions
-def build_outer_panes(state):
- """Build top and side panes."""
- clear_screen()
-
- # Top
- state.panes['Top'] = tmux_split_window(
- behind=True, lines=2, vertical=True,
- text=TOP_PANE_TEXT)
-
- # Started
- state.panes['Started'] = tmux_split_window(
- lines=SIDE_PANE_WIDTH, target_pane=state.panes['Top'],
- text='{BLUE}Started{CLEAR}\n{s}'.format(
- s=time.strftime("%Y-%m-%d %H:%M %Z"),
- **COLORS))
-
- # Progress
- state.panes['Progress'] = tmux_split_window(
- lines=SIDE_PANE_WIDTH,
- watch=state.progress_out)
-
-
def build_status_string(label, status, info_label=False):
"""Build status string with appropriate colors."""
status_color = COLORS['CLEAR']
@@ -616,64 +719,6 @@ def build_status_string(label, status, info_label=False):
**COLORS)
-def fix_tmux_panes_loop(state):
- while True:
- try:
- fix_tmux_panes(state)
- sleep(1)
- except RuntimeError:
- # Assuming layout definitions changes mid-run, ignoring
- pass
-
-
-def fix_tmux_panes(state):
- """Fix pane sizes if the window has been resized."""
- needs_fixed = False
-
- # Bail?
- if not state.panes:
- return
-
- # Check layout
- for k, v in state.tmux_layout.items():
- if not v.get('Check'):
- # Not concerned with the size of this pane
- continue
- # Get target
- target = None
- if k != 'Current':
- if k not in state.panes:
- # Skip missing panes
- continue
- else:
- target = state.panes[k]
-
- # Check pane size
- x, y = tmux_get_pane_size(pane_id=target)
- if v.get('x', False) and v['x'] != x:
- needs_fixed = True
- if v.get('y', False) and v['y'] != y:
- needs_fixed = True
-
- # Bail?
- if not needs_fixed:
- return
-
- # Update layout
- for k, v in state.tmux_layout.items():
- # Get target
- target = None
- if k != 'Current':
- if k not in state.panes:
- # Skip missing panes
- continue
- else:
- target = state.panes[k]
-
- # Resize pane
- tmux_resize_pane(pane_id=target, **v)
-
-
def generate_horizontal_graph(rates, oneline=False):
"""Generate horizontal graph from rates, returns list."""
graph = ['', '', '', '']
@@ -733,6 +778,44 @@ def get_graph_step(rate, scale=16):
return step
+def get_ram_details():
+ """Get RAM details via dmidecode, returns dict."""
+ cmd = ['sudo', 'dmidecode', '--type', 'memory']
+ manufacturer = 'UNKNOWN'
+ ram_details = {'Total': 0}
+ size = 0
+
+ # Get DMI data
+ result = run_program(cmd, encoding='utf-8', errors='ignore')
+ dmi_data = result.stdout.splitlines()
+
+ # Parse data
+ for line in dmi_data:
+ line = line.strip()
+ if line == 'Memory Device':
+ # Reset vars
+ manufacturer = 'UNKNOWN'
+ size = 0
+ elif line.startswith('Size:'):
+ size = convert_to_bytes(line.replace('Size: ', ''))
+ elif line.startswith('Manufacturer:'):
+ manufacturer = line.replace('Manufacturer: ', '')
+ if size > 0:
+ # Add RAM to list if slot populated
+ ram_str = '{} {}'.format(
+ human_readable_size(size).strip(),
+ manufacturer,
+ )
+ ram_details['Total'] += size
+ if ram_str in ram_details:
+ ram_details[ram_str] += 1
+ else:
+ ram_details[ram_str] = 1
+
+ # Done
+ return ram_details
+
+
def get_read_rate(s):
"""Get read rate in bytes/s from dd progress output."""
real_rate = None
@@ -745,6 +828,7 @@ def get_read_rate(s):
def menu_diags(state, args):
"""Main menu to select and run HW tests."""
args = [a.lower() for a in args]
+ state.args = args
checkmark = '*'
if 'DISPLAY' in global_vars['Env']:
checkmark = '✓'
@@ -791,7 +875,7 @@ def menu_diags(state, args):
# If so, verify no other tests are enabled and set quick_mode
state.quick_mode = True
for opt in main_options[4:5] + main_options[6:]:
- state.quick_mode &= not opt['Enabled']
+ state.quick_mode = state.quick_mode and not opt['Enabled']
else:
state.quick_mode = False
@@ -972,12 +1056,13 @@ def run_hw_tests(state):
state.init()
tests_enabled = False
- # Disable osTicket Integration if in quick mode
- state.ost.disabled |= state.quick_mode
+ # Disable osTicket Integration if necessary
+ if '--quick' in state.args:
+ state.ost.disabled = True
# Build Panes
update_progress_pane(state)
- build_outer_panes(state)
+ state.build_outer_panes()
# Show selected tests and create TestObj()s
print_info('Selected Tests:')
@@ -1020,7 +1105,8 @@ def run_hw_tests(state):
# Run disk safety checks (if necessary)
_disk_tests_enabled = False
for k in TESTS_DISK:
- _disk_tests_enabled |= state.tests[k]['Enabled']
+ if state.tests[k]['Enabled']:
+ _disk_tests_enabled = True
if _disk_tests_enabled:
for disk in state.disks:
try:
@@ -1062,7 +1148,7 @@ def run_hw_tests(state):
# Rebuild panes
update_progress_pane(state)
- build_outer_panes(state)
+ state.build_outer_panes()
# Mark unfinished tests as aborted
for k, v in state.tests.items():
@@ -1092,8 +1178,8 @@ def run_hw_tests(state):
# Aborted/Unknown/etc
all_disks_passed = False
else:
- all_disks_passed &= disk.checkbox
- disk_failures |= not disk.checkbox
+ all_disks_passed = all_disks_passed and disk.checkbox
+ disk_failures = disk_failures or not disk.checkbox
# Update checkbox if necessary
if disk_failures:
@@ -1109,6 +1195,18 @@ def run_hw_tests(state):
print_warning('Errors encountered posting results to osTicket.')
print_standard(' ')
+ # Upload for review
+ if ENABLED_UPLOAD_DATA and ask('Upload results for review?'):
+ try_and_print(
+ message='Saving debug reports...',
+ function=save_debug_reports,
+ state=state, global_vars=global_vars)
+ try_and_print(
+ message='Uploading Data...',
+ function=upload_logdir,
+ global_vars=global_vars,
+ reason='Review')
+
# Done
sleep(1)
if state.quick_mode:
@@ -1459,7 +1557,7 @@ def run_mprime_test(state, test):
# Add temps to report
test.report.append('{BLUE}Temps{CLEAR}'.format(**COLORS))
for line in generate_sensor_report(
- test.sensor_data, 'Idle', 'Max', 'Cooldown', core_only=True):
+ test.sensor_data, 'Idle', 'Max', 'Cooldown', cpu_only=True):
test.report.append(' {}'.format(line))
# Add abort message(s)
@@ -1579,7 +1677,13 @@ def run_smart_short_test(state, test):
# Start short test
print_standard('Running self-test...')
- cmd = ['sudo', 'smartctl', '--test=short', dev.path]
+ cmd = [
+ 'sudo',
+ 'smartctl',
+ '--tolerance=normal',
+ '--test=short',
+ dev.path,
+ ]
run_program(cmd, check=False)
# Monitor progress
@@ -1653,7 +1757,8 @@ def show_results(state):
# CPU tests
_enabled = False
for k in TESTS_CPU:
- _enabled |= state.tests[k]['Enabled']
+ if state.tests[k]['Enabled']:
+ _enabled = True
if _enabled:
print_success('CPU:'.format(k))
show_report(state.cpu.generate_cpu_report(), log_report=True)
@@ -1662,7 +1767,8 @@ def show_results(state):
# Disk tests
_enabled = False
for k in TESTS_DISK:
- _enabled |= state.tests[k]['Enabled']
+ if state.tests[k]['Enabled']:
+ _enabled = True
if _enabled:
print_success('Disk{}:'.format(
'' if len(state.disks) == 1 else 's'))
diff --git a/.bin/Scripts/functions/info.py b/.bin/Scripts/functions/info.py
index 84d92663..b1959090 100644
--- a/.bin/Scripts/functions/info.py
+++ b/.bin/Scripts/functions/info.py
@@ -95,7 +95,7 @@ def get_installed_antivirus():
out = out.stdout.decode().strip()
state = out.split('=')[1]
state = hex(int(state))
- if str(state)[3:5] != '10':
+ if str(state)[3:5] not in ['10', '11']:
programs.append('[Disabled] {}'.format(prod))
else:
programs.append(prod)
@@ -446,16 +446,19 @@ def show_os_name():
def show_temp_files_size():
"""Show total size of temp files identified by BleachBit."""
- size = None
+ size_str = None
+ total = 0
with open(r'{LogDir}\Tools\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):
+ 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)
+ total += convert_to_bytes(size)
+ size_str = human_readable_size(total, decimals=1)
+ if size_str is None:
+ print_warning('UNKNOWN', timestamp=False)
else:
- print_standard(size, timestamp=False)
+ print_standard(size_str, timestamp=False)
def show_user_data_summary(indent=8, width=32):
diff --git a/.bin/Scripts/functions/json.py b/.bin/Scripts/functions/json.py
index b4527c0d..49481903 100644
--- a/.bin/Scripts/functions/json.py
+++ b/.bin/Scripts/functions/json.py
@@ -4,7 +4,7 @@ import json
from functions.common import *
-def get_json_from_command(cmd, ignore_errors=True):
+def get_json_from_command(cmd, check=True, ignore_errors=True):
"""Capture JSON content from cmd output, returns dict.
If the data can't be decoded then either an exception is raised
@@ -17,7 +17,7 @@ def get_json_from_command(cmd, ignore_errors=True):
errors = 'ignore'
try:
- result = run_program(cmd, encoding='utf-8', errors=errors)
+ result = run_program(cmd, check=check, encoding='utf-8', errors=errors)
json_data = json.loads(result.stdout)
except (subprocess.CalledProcessError, json.decoder.JSONDecodeError):
if not ignore_errors:
diff --git a/.bin/Scripts/functions/network.py b/.bin/Scripts/functions/network.py
index 492ba16f..5b5d4f52 100644
--- a/.bin/Scripts/functions/network.py
+++ b/.bin/Scripts/functions/network.py
@@ -15,27 +15,6 @@ REGEX_VALID_IP = re.compile(
re.IGNORECASE)
-def connect_to_network():
- """Connect to network if not already connected."""
- net_ifs = psutil.net_if_addrs()
- net_ifs = [i[:2] for i in net_ifs.keys()]
-
- # Bail if currently connected
- if is_connected():
- return
-
- # WiFi
- if 'wl' in net_ifs:
- cmd = [
- 'nmcli', 'dev', 'wifi',
- 'connect', WIFI_SSID,
- 'password', WIFI_PASSWORD]
- try_and_print(
- message = 'Connecting to {}...'.format(WIFI_SSID),
- function = run_program,
- cmd = cmd)
-
-
def is_connected():
"""Check for a valid private IP."""
devs = psutil.net_if_addrs()
diff --git a/.bin/Scripts/functions/osticket.py b/.bin/Scripts/functions/osticket.py
index aed84f92..5ec9529e 100644
--- a/.bin/Scripts/functions/osticket.py
+++ b/.bin/Scripts/functions/osticket.py
@@ -189,11 +189,14 @@ class osTicket():
def generate_report(self, dev, ticket_id, ticket_name):
"""Generate device report for osTicket, returns list."""
- report = []
+ report = ['']
results = self.get_device_overall_results(dev)
+ test_station = TEST_STATIONS.get(get_hostname().lower(), '')
# Header
- report.append('[Report for ticket #{} {}]'.format(ticket_id, ticket_name))
+ if test_station:
+ report[0] += '[Test-Station: {}] '.format(test_station)
+ report[0] += '[Report for ticket #{} {}]'.format(ticket_id, ticket_name)
if results['Full Diag']:
report.append(
'{Dev Type} hardware diagnostic tests: {Status}'.format(**results))
@@ -346,8 +349,15 @@ class osTicket():
results['Status'] += '*'
# Enable CoreStorage searches
- results['Core'] = (results['Full Diag'] and
- results['Passed']+results['N/A']+results['OVERRIDE'] == len(test_list))
+ results['Core'] = False
+ if results['Full Diag']:
+ num_passed = results['Passed'] + results['N/A'] + results['OVERRIDE']
+ if num_passed == len(test_list):
+ # We ran all disk tests and all results were acceptable
+ results['Core'] = True
+ elif results['Failed'] == 1 and dev.tests['I/O Benchmark'].failed:
+ # We ran all disk tests and only I/O Benchmark failed
+ results['Core'] = True
# Done
return results
@@ -395,28 +405,13 @@ class osTicket():
self.disconnect()
return flag_value
- def get_ticket_name(self, ticket_id):
- """Lookup ticket and return name as str."""
- name = None
- sql_cmd = "SELECT name FROM `{Ticket}`".format(**OSTICKET['Tables'])
- sql_cmd += " WHERE `ticket_id` = {}".format(ticket_id)
- sql_cmd += ";"
-
- # Lookup name
- # NOTE: If multiple entries are found it will return the last
- self.db_cursor.execute(sql_cmd)
- for s in self.db_cursor:
- name = s[0]
-
- # Done
- return name
-
def get_ticket_details(self):
"""Get ticket number and name from osTicket DB, returns tuple."""
ticket_name = None
ticket_number = None
# Connect
+ print_standard('Connecting to osTicket...')
while True:
try:
self.connect(silent=False)
@@ -434,36 +429,74 @@ class osTicket():
# Main loop
while ticket_number is None:
print_standard(' ')
- _input = input('Enter ticket number (or leave blank to disable): ')
- _input = _input.strip()
+ _ticket_id = input('Enter ticket number (or leave blank to disable): ')
+ _ticket_id = _ticket_id.strip()
# No ticket ID entered
- if re.match(r'^\s*$', _input):
+ if re.match(r'^\s*$', _ticket_id):
if ask('Disable osTicket integration for this run?'):
self.disabled = True
break
# Invalid ID entered
- if not re.match(r'^(\d+)$', _input):
+ if not re.match(r'^(\d+)$', _ticket_id):
continue
- # Valid ID entered, lookup name and verify
+ # Valid ID entered, lookup name
try:
- _name = self.get_ticket_name(_input)
+ _name = self.get_ticket_field(_ticket_id, 'name')
except Exception:
# Ignore and return None below
break
- if _name:
- print_standard('You have selected ticket #{} {}'.format(
- _input, _name))
- if ask('Is this correct?'):
- ticket_name = _name
- ticket_number = _input
+
+ # Verify ticket exists
+ if _name is None:
+ print_error('ERROR: Ticket {} not found.'.format(_ticket_id))
+ continue
+
+ # Lookup subject
+ try:
+ _subject = self.get_ticket_field(_ticket_id, 'subject')
+ except Exception:
+ # Ignore and set to None
+ _subject = None
+
+ # Verify the selected ticket is correct
+ print_standard(
+ 'You have selected ticket {BLUE}#{ticket_id}{CLEAR} {name}'.format(
+ ticket_id=_ticket_id,
+ name=_name,
+ **COLORS))
+ print_standard('{CYAN} {subject}{CLEAR}'.format(
+ subject=_subject,
+ **COLORS))
+ print_standard(' ')
+ if ask('Is this correct?'):
+ ticket_name = _name
+ ticket_number = _ticket_id
# Done
self.disconnect()
return (ticket_number, ticket_name)
+ def get_ticket_field(self, ticket_id, field):
+ """Lookup ticket and return field as str."""
+ data = None
+ sql_cmd = "SELECT {field} FROM `{Ticket}`".format(
+ field=field,
+ **OSTICKET['Tables'])
+ sql_cmd += " WHERE `ticket_id` = {}".format(ticket_id)
+ sql_cmd += ";"
+
+ # Lookup data
+ # NOTE: If multiple entries are found it will return the last
+ self.db_cursor.execute(sql_cmd)
+ for s in self.db_cursor:
+ data = s[0]
+
+ # Done
+ return data
+
def post_device_results(self, dev, ticket_id, ticket_name):
"""Generate osTicket friendly report and post as response to ticket."""
if not dev.tests:
@@ -555,6 +588,13 @@ class osTicket():
# Functions
+def get_hostname():
+ """Get hostname, returns str."""
+ cmd = ['hostnamectl', '--static']
+ result = run_program(cmd, check=False, encoding='utf-8', errors='ignore')
+ return result.stdout.strip()
+
+
def pad_with_dots(s, pad_right=False):
"""Replace space padding with dots, returns str."""
s = str(s).replace(' ', '..')
diff --git a/.bin/Scripts/functions/sensors.py b/.bin/Scripts/functions/sensors.py
index 8525deb8..49a7472c 100644
--- a/.bin/Scripts/functions/sensors.py
+++ b/.bin/Scripts/functions/sensors.py
@@ -1,4 +1,6 @@
-# Wizard Kit: Functions - Sensors
+'''Wizard Kit: Functions - Sensors'''
+# pylint: disable=no-name-in-module,wildcard-import
+# vim: sts=2 sw=2 ts=2
import json
import re
@@ -9,7 +11,7 @@ from settings.sensors import *
# Error Classes
class ThermalLimitReachedError(Exception):
- pass
+ '''Thermal limit reached error.'''
def clear_temps(sensor_data):
@@ -20,28 +22,30 @@ def clear_temps(sensor_data):
_data['Temps'] = []
-def fix_sensor_str(s):
+def fix_sensor_str(_s):
"""Cleanup string and return str."""
- s = re.sub(r'^(\w+)-(\w+)-(\w+)', r'\1 (\2 \3)', s, re.IGNORECASE)
- s = s.title()
- s = s.replace('Coretemp', 'CoreTemp')
- s = s.replace('Acpi', 'ACPI')
- s = s.replace('ACPItz', 'ACPI TZ')
- s = s.replace('Isa ', 'ISA ')
- s = s.replace('Id ', 'ID ')
- s = re.sub(r'(\D+)(\d+)', r'\1 \2', s, re.IGNORECASE)
- s = s.replace(' ', ' ')
- return s
+ _s = re.sub(r'^(\w+)-(\w+)-(\w+)', r'\1 (\2 \3)', _s, re.IGNORECASE)
+ _s = _s.title()
+ _s = _s.replace('Coretemp', 'CPUTemp')
+ _s = _s.replace('Acpi', 'ACPI')
+ _s = _s.replace('ACPItz', 'ACPI TZ')
+ _s = _s.replace('Isa ', 'ISA ')
+ _s = _s.replace('Pci ', 'PCI ')
+ _s = _s.replace('Id ', 'ID ')
+ _s = re.sub(r'(\D+)(\d+)', r'\1 \2', _s, re.IGNORECASE)
+ _s = re.sub(r'^K (\d+)Temp', r'AMD K\1 Temps', _s, re.IGNORECASE)
+ _s = re.sub(r'T(ctl|die)', r'CPU (T\1)', _s, re.IGNORECASE)
+ return _s
def generate_sensor_report(
sensor_data, *temp_labels,
- colors=True, core_only=False):
+ colors=True, cpu_only=False):
"""Generate report based on temp_labels, returns list if str."""
report = []
for _section, _adapters in sorted(sensor_data.items()):
- # CoreTemps then Other temps
- if core_only and 'Core' not in _section:
+ # CPU temps then Other temps
+ if cpu_only and 'CPU' not in _section:
continue
for _adapter, _sources in sorted(_adapters.items()):
# Adapter
@@ -56,7 +60,7 @@ def generate_sensor_report(
': ' if _label != 'Current' else '',
get_temp_str(_data.get(_label, '???'), colors=colors))
report.append(_line)
- if not core_only:
+ if not cpu_only:
report.append(' ')
# Handle empty reports (i.e. no sensors detected)
@@ -91,15 +95,15 @@ def get_colored_temp_str(temp):
else:
color = COLORS['CLEAR']
return '{color}{prefix}{temp:2.0f}°C{CLEAR}'.format(
- color = color,
- prefix = '-' if temp < 0 else '',
- temp = temp,
+ color=color,
+ prefix='-' if temp < 0 else '',
+ temp=temp,
**COLORS)
def get_raw_sensor_data():
"""Read sensor data and return dict."""
- data = {}
+ json_data = {}
cmd = ['sensors', '-j']
# Get raw data
@@ -122,8 +126,8 @@ def get_raw_sensor_data():
try:
json_data = json.loads('\n'.join(raw_data))
except json.JSONDecodeError:
- # Still broken, just set to empty dict
- json_data = {}
+ # Still broken, just return the empty dict
+ pass
# Done
return json_data
@@ -132,10 +136,10 @@ def get_raw_sensor_data():
def get_sensor_data():
"""Parse raw sensor data and return new dict."""
json_data = get_raw_sensor_data()
- sensor_data = {'CoreTemps': {}, 'Other': {}}
+ sensor_data = {'CPUTemps': {}, 'Other': {}}
for _adapter, _sources in json_data.items():
- if 'coretemp' in _adapter:
- _section = 'CoreTemps'
+ if is_cpu_adapter(_adapter):
+ _section = 'CPUTemps'
else:
_section = 'Other'
sensor_data[_section][_adapter] = {}
@@ -157,8 +161,8 @@ def get_sensor_data():
}
# Remove empty sections
- for k, v in sensor_data.items():
- v = {k2: v2 for k2, v2 in v.items() if v2}
+ for _k, _v in sensor_data.items():
+ _v = {_k2: _v2 for _k2, _v2 in _v.items() if _v2}
# Done
return sensor_data
@@ -178,14 +182,20 @@ def get_temp_str(temp, colors=True):
temp)
+def is_cpu_adapter(adapter):
+ """Checks if adapter is a known CPU adapter, returns bool."""
+ is_cpu = re.search(r'(core|k\d+)temp', adapter, re.IGNORECASE)
+ return bool(is_cpu)
+
+
def monitor_sensors(monitor_pane, monitor_file):
"""Continually update sensor data and report to screen."""
sensor_data = get_sensor_data()
while True:
update_sensor_data(sensor_data)
- with open(monitor_file, 'w') as f:
+ with open(monitor_file, 'w') as _f:
report = generate_sensor_report(sensor_data, 'Current', 'Max')
- f.write('\n'.join(report))
+ _f.write('\n'.join(report))
sleep(1)
if monitor_pane and not tmux_poll_pane(monitor_pane):
break
@@ -196,7 +206,7 @@ def save_average_temp(sensor_data, temp_label, seconds=10):
clear_temps(sensor_data)
# Get temps
- for i in range(seconds):
+ for _i in range(seconds): # pylint: disable=unused-variable
update_sensor_data(sensor_data)
sleep(1)
@@ -219,24 +229,15 @@ def update_sensor_data(sensor_data, thermal_limit=None):
_data['Current'] = _temp
_data['Max'] = max(_temp, _data['Max'])
_data['Temps'].append(_temp)
- except Exception:
+ except Exception: # pylint: disable=broad-except
# Dumb workound for Dell sensors with changing source names
pass
# Check if thermal limit reached
- if thermal_limit and _section == 'CoreTemps':
+ if thermal_limit and _section == 'CPUTemps':
if max(_data['Current'], _data['Max']) >= thermal_limit:
- raise ThermalLimitReachedError('CoreTemps reached limit')
-
-
-def join_columns(column1, column2, width=55):
- return '{:<{}}{}'.format(
- column1,
- 55+len(column1)-len(REGEX_COLORS.sub('', column1)),
- column2)
+ raise ThermalLimitReachedError('CPU temps reached limit')
if __name__ == '__main__':
print("This file is not meant to be called directly.")
-
-# vim: sts=2 sw=2 ts=2
diff --git a/.bin/Scripts/functions/setup.py b/.bin/Scripts/functions/setup.py
index 7c2062ac..d75a9965 100644
--- a/.bin/Scripts/functions/setup.py
+++ b/.bin/Scripts/functions/setup.py
@@ -1,6 +1,7 @@
# Wizard Kit: Functions - Setup
from functions.browsers import *
+from functions.json import *
from functions.update import *
from settings.setup import *
from settings.sources import *
@@ -65,9 +66,13 @@ def config_explorer_system():
write_registry_settings(SETTINGS_EXPLORER_SYSTEM, all_users=True)
-def config_explorer_user():
- """Configure Windows Explorer for current user."""
- write_registry_settings(SETTINGS_EXPLORER_USER, all_users=False)
+def config_explorer_user(setup_mode='All'):
+ """Configure Windows Explorer for current user per setup_mode."""
+ settings_explorer_user = {
+ k: v for k, v in SETTINGS_EXPLORER_USER.items()
+ if setup_mode not in v.get('Invalid modes', [])
+ }
+ write_registry_settings(settings_explorer_user, all_users=False)
def config_windows_updates():
@@ -85,6 +90,11 @@ def create_system_restore_point():
run_program(cmd)
+def disable_fast_startup():
+ """Disable Fast Startup."""
+ write_registry_settings(SETTINGS_FAST_STARTUP, all_users=True)
+
+
def disable_windows_telemetry():
"""Disable Windows 10 telemetry settings with O&O ShutUp10."""
extract_item('ShutUp10', silent=True)
@@ -95,6 +105,12 @@ def disable_windows_telemetry():
run_program(cmd)
+def enable_hibernation():
+ """Enable hibernation."""
+ cmd = ['powercfg', '/hibernate', 'on']
+ run_program(cmd)
+
+
def enable_regback():
"""Enable RegBack."""
write_registry_settings(SETTINGS_REGBACK, all_users=True)
@@ -123,9 +139,10 @@ def enable_system_restore():
'/maxsize=8%']
run_program(cmd)
+
def update_clock():
"""Set Timezone and sync clock."""
- run_program(['tzutil' ,'/s', WINDOWS_TIME_ZONE], check=False)
+ run_program(['tzutil', '/s', WINDOWS_TIME_ZONE], check=False)
run_program(['net', 'stop', 'w32ime'], check=False)
run_program(
['w32tm', '/config', '/syncfromflags:manual',
@@ -157,6 +174,39 @@ def write_registry_settings(settings, all_users=False):
# Installations
+def find_current_software():
+ """Find currently installed software, returns list."""
+ ninite_extras_path = r'{BaseDir}\Installers\Extras'.format(**global_vars)
+ installers = []
+
+ # Browsers
+ scan_for_browsers(skip_ie=True, silent=True)
+ for browser in ('Google Chrome', 'Mozilla Firefox', 'Opera Chromium'):
+ if is_installed(browser):
+ installers.append(
+ r'{}\Web Browsers\{}.exe'.format(ninite_extras_path, browser))
+
+ # TODO: Add more sections
+
+ return installers
+
+def find_missing_software():
+ """Find missing software based on dirs/files present, returns list."""
+ ninite_extras_path = r'{BaseDir}\Installers\Extras'.format(**global_vars)
+ installers = []
+
+ # Browsers
+ scan_for_browsers(skip_ie=True, silent=True)
+ for browser in ('Google Chrome', 'Mozilla Firefox', 'Opera Chromium'):
+ if profile_present(browser):
+ installers.append(
+ r'{}\Web Browsers\{}.exe'.format(ninite_extras_path, browser))
+
+ # TODO: Add more sections
+
+ return installers
+
+
def install_adobe_reader():
"""Install Adobe Reader."""
cmd = [
@@ -188,36 +238,26 @@ def install_classicstart_skin():
shutil.copy(source, dest)
-def install_eset_nod32_av(scan_pups=True):
+def install_eset_nod32_av(msp=False):
"""Install ESET NOD32 AV with custom config."""
extract_item('ESETConfigs', silent=True)
config_file = r'{BinDir}\ESETConfigs\{config_file}.xml'.format(
- config_file='eset-config' if scan_pups else 'eset-config-no-pup',
+ config_file='eset-config-msp' if msp else 'eset-config',
**global_vars)
- # Apply user configuration
- write_registry_settings(SETTINGS_ESET, all_users=False)
-
- # Download
- result = try_and_print(message='Downloading Setup...', cs='Done',
- other_results=OTHER_RESULTS, function=download_generic,
- out_dir=global_vars['ClientDir'],
- out_name='eav_nt64.exe',
- source_url=SOURCE_URLS['ESET NOD32 AV'])
- installer = r'{ClientDir}\eav_nt64.exe'.format(**global_vars)
- if not result['CS']:
- raise GenericError('Failed to download ESET NOD32 AV')
+ # Registry settings
+ write_registry_settings(SETTINGS_ESET_SYSTEM, all_users=True)
+ write_registry_settings(SETTINGS_ESET_USER, all_users=False)
# Install
- cmd = [installer,
+ cmd = [
+ r'{}\Installers\Extras\Security\ESET NOD32 x64.exe'.format(
+ global_vars['BaseDir']),
'--silent', '--accepteula', '--msi-property',
'PRODUCTTYPE=eav', 'PRODUCT_LANG=1033', 'PRODUCT_LANG_CODE=en-US',
- 'ADMINCFG="{}"'.format(config_file)]
- try_and_print(message='Installing ESET NOD32 AV...',
- other_results=OTHER_RESULTS, function=run_program, cmd=cmd)
-
- # Delete installer
- remove_item(installer)
+ 'ADMINCFG="{}"'.format(config_file),
+ ]
+ run_program(cmd)
def install_firefox_extensions():
"""Install Firefox extensions for all users."""
@@ -240,10 +280,49 @@ def install_firefox_extensions():
run_program(cmd)
-def install_ninite_bundle(browsers_only=False, mse=False, libreoffice=False):
+def install_libreoffice(
+ quickstart=True, register_mso_types=True,
+ use_mso_formats=False, vcredist=False):
+ """Install LibreOffice using specified settings."""
+ cmd = [
+ 'msiexec', '/passive', '/norestart',
+ '/i', r'{}\Installers\Extras\Office\LibreOffice.msi'.format(
+ global_vars['BaseDir']),
+ 'REBOOTYESNO=No',
+ 'ISCHECKFORPRODUCTUPDATES=0',
+ 'QUICKSTART={}'.format(1 if quickstart else 0),
+ 'UI_LANGS=en_US',
+ 'VC_REDIST={}'.format(1 if vcredist else 0),
+ ]
+ if register_mso_types:
+ cmd.append('REGISTER_ALL_MSO_TYPES=1')
+ else:
+ cmd.append('REGISTER_NO_MSO_TYPES=1')
+ xcu_dir = r'{APPDATA}\LibreOffice\4\user'.format(**global_vars['Env'])
+ xcu_file = r'{}\registrymodifications.xcu'.format(xcu_dir)
+
+ # Set default save format
+ if use_mso_formats and not os.path.exists(xcu_file):
+ os.makedirs(xcu_dir, exist_ok=True)
+ with open(xcu_file, 'w', encoding='utf-8', newline='\n') as f:
+ f.write(LIBREOFFICE_XCU_DATA)
+
+ # Install LibreOffice
+ run_program(cmd, check=True)
+
+def install_ninite_bundle(
+ # pylint: disable=too-many-arguments,too-many-branches
+ base=True,
+ browsers_only=False,
+ libreoffice=False,
+ missing=False,
+ mse=False,
+ standard=True,
+ ):
"""Run Ninite installer(s), returns list of Popen objects."""
popen_objects = []
if browsers_only:
+ # This option is deprecated
installer_path = r'{BaseDir}\Installers\Extras\Web Browsers'.format(
**global_vars)
scan_for_browsers(skip_ie=True, silent=True)
@@ -251,26 +330,65 @@ def install_ninite_bundle(browsers_only=False, mse=False, libreoffice=False):
if is_installed(browser):
cmd = r'{}\{}.exe'.format(installer_path, browser)
popen_objects.append(popen_program(cmd))
- elif global_vars['OS']['Version'] in ('8', '8.1', '10'):
- # Modern selection
- popen_objects.append(
- popen_program(r'{BaseDir}\Installers\Extras\Bundles\Modern.exe'.format(
- **global_vars)))
- else:
- # Legacy selection
- if mse:
- cmd = r'{BaseDir}\Installers\Extras\Security'.format(**global_vars)
- cmd += r'\Microsoft Security Essentials.exe'
- popen_objects.append(popen_program(cmd))
- popen_objects.append(
- popen_program(r'{BaseDir}\Installers\Extras\Bundles\Legacy.exe'.format(
- **global_vars)))
+
+ # Bail
+ return popen_objects
+
+ # Main selections
+ main_selections = []
+ if base:
+ main_selections.append('base')
+ if standard:
+ if global_vars['OS']['Version'] in ('8', '8.1', '10'):
+ main_selections.append('standard')
+ else:
+ main_selections.append('standard7')
+ if main_selections:
+ # Only run if base and/or standard are enabled
+ cmd = r'{}\Installers\Extras\Bundles\{}.exe'.format(
+ global_vars['BaseDir'],
+ '-'.join(main_selections),
+ )
+ popen_objects.append(popen_program([cmd]))
+
+ # Extra selections
+ extra_selections = {}
+ for cmd in find_current_software():
+ extra_selections[cmd] = True
+ if missing:
+ for cmd in find_missing_software():
+ extra_selections[cmd] = True
+
+ # Remove overlapping selections
+ regex = []
+ for n_name, n_group in NINITE_REGEX.items():
+ if n_name in main_selections:
+ regex.extend(n_group)
+ regex = '({})'.format('|'.join(regex))
+ extra_selections = {
+ cmd: True for cmd in extra_selections
+ if not re.search(regex, cmd, re.IGNORECASE)
+ }
+
+ # Start extra selections
+ for cmd in extra_selections:
+ popen_objects.append(popen_program([cmd]))
+
+ # Microsoft Security Essentials
+ if mse:
+ cmd = r'{}\Installers\Extras\Security\{}'.format(
+ global_vars['BaseDir'],
+ 'Microsoft Security Essentials.exe',
+ )
+ popen_objects.append(popen_program([cmd]))
# LibreOffice
if libreoffice:
- cmd = r'{BaseDir}\Installers\Extras\Office'.format(**global_vars)
- cmd += r'\LibreOffice.exe'
- popen_objects.append(popen_program(cmd))
+ cmd = r'{}\Installers\Extras\Office\{}'.format(
+ global_vars['BaseDir'],
+ 'LibreOffice.exe',
+ )
+ popen_objects.append(popen_program([cmd]))
# Done
return popen_objects
@@ -293,6 +411,32 @@ def install_vcredists():
# Misc
+def drive_is_rotational(drive):
+ """Check if drive is rotational, returns bool.
+
+ NOTE: This is a quick, naive check with a bias towards rotational."""
+ is_rotational = True
+
+ # Get SMART data
+ extract_item('smartmontools', silent=True)
+ cmd = [
+ global_vars['Tools']['smartctl'],
+ '--info',
+ '--json',
+ drive,
+ ]
+ data = get_json_from_command(cmd, check=False)
+
+ # Check rotation rate
+ try:
+ is_rotational = int(data.get('rotation_rate', '01189998819991197253')) == 0
+ except ValueError:
+ # Ignore and assume rotational
+ pass
+
+ return is_rotational
+
+
def open_device_manager():
popen_program(['mmc', 'devmgmt.msc'])
@@ -303,6 +447,10 @@ def open_snappy_driver_origin():
popen_program(cmd, cwd=cwd, pipe=True)
+def open_speedtest():
+ popen_program(['start', '', 'https://fast.com'], shell=True)
+
+
def open_windows_activation():
popen_program(['slui'])
diff --git a/.bin/Scripts/functions/sw_diags.py b/.bin/Scripts/functions/sw_diags.py
index 3aa2838c..1c5b943f 100644
--- a/.bin/Scripts/functions/sw_diags.py
+++ b/.bin/Scripts/functions/sw_diags.py
@@ -6,6 +6,35 @@ from functions.common import *
from settings.sw_diags import *
+def check_4k_alignment(show_alert=False):
+ """Check that all partitions are 4K aligned."""
+ aligned = True
+ cmd = ['WMIC', 'partition', 'get', 'StartingOffset']
+ offsets = []
+
+ # Get offsets
+ result = run_program(cmd, encoding='utf-8', errors='ignore', check=False)
+ offsets = result.stdout.splitlines()
+
+ # Check offsets
+ for off in offsets:
+ off = off.strip()
+ if not off.isnumeric():
+ # Skip
+ continue
+
+ try:
+ aligned = aligned and int(off) % 4096 == 0
+ except ValueError:
+ # Ignore, this check is low priority
+ pass
+
+ # Show alert
+ if show_alert:
+ show_alert_box('One or more partitions are not 4K aligned')
+ raise Not4KAlignedError
+
+
def check_connection():
"""Check if the system is online and optionally abort the script."""
while True:
@@ -19,6 +48,37 @@ def check_connection():
abort()
+def check_os_support_status():
+ """Check if current OS is supported."""
+ msg = ''
+ outdated = False
+ unsupported = False
+
+ # Check OS version/notes
+ os_info = global_vars['OS'].copy()
+ if os_info['Notes'] == 'unsupported':
+ msg = 'The installed version of Windows is no longer supported'
+ unsupported = True
+ elif os_info['Notes'] == 'preview build':
+ msg = 'Preview builds are not officially supported'
+ unsupported = True
+ elif os_info['Version'] == '10' and os_info['Notes'] == 'outdated':
+ msg = 'The installed version of Windows is outdated'
+ outdated = True
+ if 'Preview' not in msg:
+ msg += '\n\nPlease consider upgrading before continuing setup.'
+
+ # Show alert
+ if outdated or unsupported:
+ show_alert_box(msg)
+
+ # Raise exception if necessary
+ if outdated:
+ raise WindowsOutdatedError
+ if unsupported:
+ raise WindowsUnsupportedError
+
+
def check_secure_boot_status(show_alert=False):
"""Checks UEFI Secure Boot status via PowerShell."""
boot_mode = get_boot_mode()
@@ -81,33 +141,6 @@ def get_boot_mode():
return type_str
-def os_is_unsupported(show_alert=False):
- """Checks if the current OS is unsupported, returns bool."""
- msg = ''
- unsupported = False
-
- # Check OS version/notes
- os_info = global_vars['OS'].copy()
- if os_info['Notes'] == 'unsupported':
- msg = 'The installed version of Windows is no longer supported'
- unsupported = True
- elif os_info['Notes'] == 'preview build':
- msg = 'Preview builds are not officially supported'
- unsupported = True
- elif os_info['Version'] == '10' and os_info['Notes'] == 'outdated':
- msg = 'The installed version of Windows is outdated'
- unsupported = True
- if 'Preview' not in msg:
- msg += '\n\nPlease consider upgrading before continuing setup.'
-
- # Show alert
- if unsupported and show_alert:
- show_alert_box(msg)
-
- # Done
- return unsupported
-
-
def run_autoruns():
"""Run AutoRuns in the background with VirusTotal checks enabled."""
extract_item('Autoruns', filter='autoruns*', silent=True)
diff --git a/.bin/Scripts/functions/ufd.py b/.bin/Scripts/functions/ufd.py
new file mode 100644
index 00000000..e92c8bd8
--- /dev/null
+++ b/.bin/Scripts/functions/ufd.py
@@ -0,0 +1,471 @@
+"""Wizard Kit: Functions - UFD"""
+# pylint: disable=broad-except,wildcard-import
+# vim: sts=2 sw=2 ts=2
+
+import os
+import re
+import shutil
+import pathlib
+from collections import OrderedDict
+from functions.common import *
+
+
+def case_insensitive_search(path, item):
+ """Search path for item case insensitively, returns str."""
+ regex_match = '^{}$'.format(item)
+ real_path = ''
+
+ # Quick check first
+ if os.path.exists('{}/{}'.format(path, item)):
+ real_path = '{}{}{}'.format(
+ path,
+ '' if path == '/' else '/',
+ item,
+ )
+
+ # Check all items in dir
+ for entry in os.scandir(path):
+ if re.match(regex_match, entry.name, re.IGNORECASE):
+ real_path = '{}{}{}'.format(
+ path,
+ '' if path == '/' else '/',
+ entry.name,
+ )
+
+ # Done
+ if not real_path:
+ raise FileNotFoundError('{}/{}'.format(path, item))
+
+ return real_path
+
+
+def confirm_selections(args):
+ """Ask tech to confirm selections, twice if necessary."""
+ if not ask('Is the above information correct?'):
+ abort(False)
+ ## Safety check
+ if not args['--update']:
+ print_standard(' ')
+ print_warning('SAFETY CHECK')
+ print_standard(
+ 'All data will be DELETED from the disk and partition(s) listed above.')
+ print_standard(
+ 'This is irreversible and will lead to {RED}DATA LOSS.{CLEAR}'.format(
+ **COLORS))
+ if not ask('Asking again to confirm, is this correct?'):
+ abort(False)
+
+ print_standard(' ')
+
+
+def copy_source(source, items, overwrite=False):
+ """Copy source items to /mnt/UFD."""
+ is_image = source.is_file()
+
+ # Mount source if necessary
+ if is_image:
+ mount(source, '/mnt/Source')
+
+ # Copy items
+ for i_source, i_dest in items:
+ i_source = '{}{}'.format(
+ '/mnt/Source' if is_image else source,
+ i_source,
+ )
+ i_dest = '/mnt/UFD{}'.format(i_dest)
+ try:
+ recursive_copy(i_source, i_dest, overwrite=overwrite)
+ except FileNotFoundError:
+ # Going to assume (hope) that this is fine
+ pass
+
+ # Unmount source if necessary
+ if is_image:
+ unmount('/mnt/Source')
+
+
+def find_first_partition(dev_path):
+ """Find path to first partition of dev, returns str."""
+ cmd = [
+ 'lsblk',
+ '--list',
+ '--noheadings',
+ '--output', 'name',
+ '--paths',
+ dev_path,
+ ]
+ result = run_program(cmd, encoding='utf-8', errors='ignore')
+ part_path = result.stdout.splitlines()[-1].strip()
+
+ return part_path
+
+
+def find_path(path):
+ """Find path case-insensitively, returns pathlib.Path obj."""
+ path_obj = pathlib.Path(path).resolve()
+
+ # Quick check first
+ if path_obj.exists():
+ return path_obj
+
+ # Fix case
+ parts = path_obj.relative_to('/').parts
+ real_path = '/'
+ for part in parts:
+ try:
+ real_path = case_insensitive_search(real_path, part)
+ except NotADirectoryError:
+ # Reclassify error
+ raise FileNotFoundError(path)
+
+ # Raise error if path doesn't exist
+ path_obj = pathlib.Path(real_path)
+ if not path_obj.exists():
+ raise FileNotFoundError(path_obj)
+
+ # Done
+ return path_obj
+
+
+def get_user_home(user):
+ """Get path to user's home dir, returns str."""
+ home_dir = None
+ cmd = ['getent', 'passwd', user]
+ result = run_program(cmd, encoding='utf-8', errors='ignore', check=False)
+ try:
+ home_dir = result.stdout.split(':')[5]
+ except Exception:
+ # Just use HOME from ENV (or '/root' if that fails)
+ home_dir = os.environ.get('HOME', '/root')
+
+ return home_dir
+
+
+def get_user_name():
+ """Get real user name, returns str."""
+ user = None
+ if 'SUDO_USER' in os.environ:
+ user = os.environ.get('SUDO_USER', 'Unknown')
+ else:
+ user = os.environ.get('USER', 'Unknown')
+
+ return user
+
+
+def hide_items(ufd_dev, items):
+ """Set FAT32 hidden flag for items."""
+ # pylint: disable=invalid-name
+ with open('/root/.mtoolsrc', 'w') as f:
+ f.write('drive U: file="{}"\n'.format(
+ find_first_partition(ufd_dev)))
+ f.write('mtools_skip_check=1\n')
+
+ # Hide items
+ for item in items:
+ cmd = ['yes | mattrib +h "U:/{}"'.format(item)]
+ run_program(cmd, check=False, shell=True)
+
+
+def install_syslinux_to_dev(ufd_dev, use_mbr):
+ """Install Syslinux to UFD (dev)."""
+ cmd = [
+ 'dd',
+ 'bs=440',
+ 'count=1',
+ 'if=/usr/lib/syslinux/bios/{}.bin'.format(
+ 'mbr' if use_mbr else 'gptmbr',
+ ),
+ 'of={}'.format(ufd_dev),
+ ]
+ run_program(cmd)
+
+
+def install_syslinux_to_partition(partition):
+ """Install Syslinux to UFD (partition)."""
+ cmd = [
+ 'syslinux',
+ '--install',
+ '--directory',
+ '/arch/boot/syslinux/',
+ partition,
+ ]
+ run_program(cmd)
+
+
+def is_valid_path(path_obj, path_type):
+ """Verify path_obj is valid by type, returns bool."""
+ valid_path = False
+ if path_type == 'DIR':
+ valid_path = path_obj.is_dir()
+ elif path_type == 'KIT':
+ valid_path = path_obj.is_dir() and path_obj.joinpath('.bin').exists()
+ elif path_type == 'IMG':
+ valid_path = path_obj.is_file() and path_obj.suffix.lower() == '.img'
+ elif path_type == 'ISO':
+ valid_path = path_obj.is_file() and path_obj.suffix.lower() == '.iso'
+ elif path_type == 'UFD':
+ valid_path = path_obj.is_block_device()
+
+ return valid_path
+
+
+def mount(mount_source, mount_point, read_write=False):
+ """Mount mount_source on mount_point."""
+ os.makedirs(mount_point, exist_ok=True)
+ cmd = [
+ 'mount',
+ mount_source,
+ mount_point,
+ '-o',
+ 'rw' if read_write else 'ro',
+ ]
+ run_program(cmd)
+
+
+def prep_device(dev_path, label, use_mbr=False, indent=2):
+ """Format device in preparation for applying the WizardKit components
+
+ This is done is four steps:
+ 1. Zero-out first 64MB (this deletes the partition table and/or bootloader)
+ 2. Create a new partition table (GPT by default, optionally MBR)
+ 3. Set boot flag
+ 4. Format partition (FAT32, 4K aligned)
+ """
+ # Zero-out first 64MB
+ cmd = 'dd bs=4M count=16 if=/dev/zero of={}'.format(dev_path).split()
+ try_and_print(
+ indent=indent,
+ message='Zeroing first 64MB...',
+ function=run_program,
+ cmd=cmd,
+ )
+
+ # Create partition table
+ cmd = 'parted {} --script -- mklabel {} mkpart primary fat32 4MiB {}'.format(
+ dev_path,
+ 'msdos' if use_mbr else 'gpt',
+ '-1s' if use_mbr else '-4MiB',
+ ).split()
+ try_and_print(
+ indent=indent,
+ message='Creating partition table...',
+ function=run_program,
+ cmd=cmd,
+ )
+
+ # Set boot flag
+ cmd = 'parted {} set 1 {} on'.format(
+ dev_path,
+ 'boot' if use_mbr else 'legacy_boot',
+ ).split()
+ try_and_print(
+ indent=indent,
+ message='Setting boot flag...',
+ function=run_program,
+ cmd=cmd,
+ )
+
+ # Format partition
+ cmd = [
+ 'mkfs.vfat', '-F', '32',
+ '-n', label,
+ find_first_partition(dev_path),
+ ]
+ try_and_print(
+ indent=indent,
+ message='Formatting partition...',
+ function=run_program,
+ cmd=cmd,
+ )
+
+
+def recursive_copy(source, dest, overwrite=False):
+ """Copy source to dest recursively.
+
+ NOTE: This uses rsync style source/dest syntax.
+ If the source has a trailing slash then it's contents are copied,
+ otherwise the source itself is copied.
+
+ Examples assuming "ExDir/ExFile.txt" exists:
+ recursive_copy("ExDir", "Dest/") results in "Dest/ExDir/ExFile.txt"
+ recursive_copy("ExDir/", "Dest/") results in "Dest/ExFile.txt"
+
+ NOTE 2: dest does not use find_path because it might not exist.
+ """
+ copy_contents = source.endswith('/')
+ source = find_path(source)
+ dest = pathlib.Path(dest).resolve().joinpath(source.name)
+ os.makedirs(dest.parent, exist_ok=True)
+
+ if source.is_dir():
+ if copy_contents:
+ # Trailing slash syntax
+ for item in os.scandir(source):
+ recursive_copy(item.path, dest.parent, overwrite=overwrite)
+ elif not dest.exists():
+ # No conflict, copying whole tree (no merging needed)
+ shutil.copytree(source, dest)
+ elif not dest.is_dir():
+ # Refusing to replace file with dir
+ raise FileExistsError('Refusing to replace file: {}'.format(dest))
+ else:
+ # Dest exists and is a dir, merge dirs
+ for item in os.scandir(source):
+ recursive_copy(item.path, dest, overwrite=overwrite)
+ elif source.is_file():
+ if not dest.exists():
+ # No conflict, copying file
+ shutil.copy2(source, dest)
+ elif not dest.is_file():
+ # Refusing to replace dir with file
+ raise FileExistsError('Refusing to replace dir: {}'.format(dest))
+ elif overwrite:
+ # Dest file exists, deleting and replacing file
+ os.remove(dest)
+ shutil.copy2(source, dest)
+ else:
+ # Refusing to delete file when overwrite=False
+ raise FileExistsError('Refusing to delete file: {}'.format(dest))
+
+
+def remove_arch():
+ """Remove arch dir from UFD.
+
+ This ensures a clean installation to the UFD and resets the boot files
+ """
+ shutil.rmtree(find_path('/mnt/UFD/arch'))
+
+
+def running_as_root():
+ """Check if running with effective UID of 0, returns bool."""
+ return os.geteuid() == 0
+
+
+def show_selections(args, sources, ufd_dev, ufd_sources):
+ """Show selections including non-specified options."""
+
+ # Sources
+ print_info('Sources')
+ for label in ufd_sources.keys():
+ if label in sources:
+ print_standard(' {label:<18} {path}'.format(
+ label=label+':',
+ path=sources[label],
+ ))
+ else:
+ print_standard(' {label:<18} {YELLOW}Not Specified{CLEAR}'.format(
+ label=label+':',
+ **COLORS,
+ ))
+ print_standard(' ')
+
+ # Destination
+ print_info('Destination')
+ cmd = [
+ 'lsblk', '--nodeps', '--noheadings', '--paths',
+ '--output', 'NAME,FSTYPE,TRAN,SIZE,VENDOR,MODEL,SERIAL',
+ ufd_dev,
+ ]
+ result = run_program(cmd, check=False, encoding='utf-8', errors='ignore')
+ print_standard(result.stdout.strip())
+ cmd = [
+ 'lsblk', '--noheadings', '--paths',
+ '--output', 'NAME,SIZE,FSTYPE,LABEL,MOUNTPOINT',
+ ufd_dev,
+ ]
+ result = run_program(cmd, check=False, encoding='utf-8', errors='ignore')
+ for line in result.stdout.splitlines()[1:]:
+ print_standard(line)
+
+ # Notes
+ if args['--update']:
+ print_warning('Updating kit in-place')
+ elif args['--use-mbr']:
+ print_warning('Formatting using legacy MBR')
+ print_standard(' ')
+
+
+def unmount(mount_point):
+ """Unmount mount_point."""
+ cmd = ['umount', mount_point]
+ run_program(cmd)
+
+
+def update_boot_entries(boot_entries, boot_files, iso_label, ufd_label):
+ """Update boot files for UFD usage"""
+ configs = []
+
+ # Find config files
+ for c_path, c_ext in boot_files.items():
+ c_path = find_path('/mnt/UFD{}'.format(c_path))
+ for item in os.scandir(c_path):
+ if item.name.lower().endswith(c_ext.lower()):
+ configs.append(item.path)
+
+ # Update Linux labels
+ cmd = [
+ 'sed',
+ '--in-place',
+ '--regexp-extended',
+ 's/(eSysRescueLiveCD|{})/{}/'.format(iso_label, ufd_label),
+ *configs,
+ ]
+ run_program(cmd)
+
+ # Uncomment extra entries if present
+ for b_path, b_comment in boot_entries.items():
+ try:
+ find_path('/mnt/UFD{}'.format(b_path))
+ except (FileNotFoundError, NotADirectoryError):
+ # Entry not found, continue to next entry
+ continue
+
+ # Entry found, update config files
+ cmd = [
+ 'sed',
+ '--in-place',
+ 's/#{}#//'.format(b_comment),
+ *configs,
+ ]
+ run_program(cmd, check=False)
+
+
+def verify_sources(args, ufd_sources):
+ """Check all sources and abort if necessary, returns dict."""
+ sources = OrderedDict()
+
+ for label, data in ufd_sources.items():
+ s_path = args[data['Arg']]
+ if s_path:
+ try:
+ s_path_obj = find_path(s_path)
+ except FileNotFoundError:
+ print_error('ERROR: {} not found: {}'.format(label, s_path))
+ abort(False)
+ if not is_valid_path(s_path_obj, data['Type']):
+ print_error('ERROR: Invalid {} source: {}'.format(label, s_path))
+ abort(False)
+ sources[label] = s_path_obj
+
+ return sources
+
+
+def verify_ufd(dev_path):
+ """Check that dev_path is a valid UFD, returns pathlib.Path obj."""
+ ufd_dev = None
+
+ try:
+ ufd_dev = find_path(dev_path)
+ except FileNotFoundError:
+ print_error('ERROR: UFD device not found: {}'.format(dev_path))
+ abort(False)
+
+ if not is_valid_path(ufd_dev, 'UFD'):
+ print_error('ERROR: Invalid UFD device: {}'.format(ufd_dev))
+ abort(False)
+
+ return ufd_dev
+
+
+if __name__ == '__main__':
+ print("This file is not meant to be called directly.")
diff --git a/.bin/Scripts/functions/update.py b/.bin/Scripts/functions/update.py
index 6ebc52f2..e2ac3f21 100755
--- a/.bin/Scripts/functions/update.py
+++ b/.bin/Scripts/functions/update.py
@@ -702,6 +702,39 @@ def update_eset_config():
if os.path.exists(include_path):
shutil.copytree(include_path, dest)
+
+def update_eset_nod32():
+ # Prep
+ dest = r'{}\Installers\Extras\Security'.format(
+ global_vars['BaseDir'])
+
+ # Remove existing installer
+ try:
+ os.remove(r'{}\ESET NOD32 x64.exe'.format(dest))
+ except FileNotFoundError:
+ pass
+
+ # Download
+ download_generic(
+ dest, 'ESET NOD32 x64.exe', SOURCE_URLS['ESET NOD32 AV'])
+
+
+def update_libreoffice():
+ # Prep
+ dest = r'{}\Installers\Extras\Office'.format(
+ global_vars['BaseDir'])
+
+ # Remove existing installer
+ try:
+ os.remove(r'{}\LibreOffice.msi'.format(dest))
+ except FileNotFoundError:
+ pass
+
+ # Download
+ download_generic(
+ dest, 'LibreOffice.msi', SOURCE_URLS['LibreOffice'])
+
+
def update_macs_fan_control():
# Prep
dest = r'{}\Installers'.format(
@@ -935,6 +968,42 @@ def update_shutup10():
'OOSU10.exe',
SOURCE_URLS['ShutUp10'])
+
+def update_smartmontools():
+ # Stop running processes
+ for process in ['smartctl.exe', 'smartctl64.exe']:
+ kill_process(process)
+
+ # Remove existing folders
+ remove_from_kit('smartmontools')
+
+ # Download installer
+ download_to_temp('smartmontools.exe', SOURCE_URLS['smartmontools'])
+ _installer = r'{}\smartmontools.exe'.format(global_vars['TmpDir'])
+
+ # Extract 64-bit
+ extract_temp_to_cbin(
+ _installer,
+ 'smartmontools',
+ mode='e',
+ sz_args=[r'bin64\smartctl.exe'],
+ )
+ shutil.move(
+ r'{}\smartmontools\smartctl.exe'.format(global_vars['CBinDir']),
+ r'{}\smartmontools\smartctl64.exe'.format(global_vars['CBinDir']))
+
+ # Extract 32-bit
+ extract_temp_to_cbin(
+ _installer,
+ 'smartmontools',
+ mode='e',
+ sz_args=[r'bin\drivedb.h', r'bin\smartctl.exe'],
+ )
+
+ # Cleanup
+ remove_item(_installer)
+
+
def update_wiztree():
# Stop running processes
for process in ['WizTree.exe', 'WizTree64.exe']:
diff --git a/.bin/Scripts/hw-diags-audio b/.bin/Scripts/hw-diags-audio
index 3d3a5991..e581330f 100755
--- a/.bin/Scripts/hw-diags-audio
+++ b/.bin/Scripts/hw-diags-audio
@@ -34,8 +34,8 @@ if __name__ == '__main__':
#print_standard('\nDone.')
#pause("Press Enter to exit...")
exit_script()
- except SystemExit:
- pass
+ except SystemExit as sys_exit:
+ exit_script(sys_exit.code)
except:
major_exception()
diff --git a/.bin/Scripts/hw-diags-menu b/.bin/Scripts/hw-diags-menu
index 58bf5280..fc95e04a 100755
--- a/.bin/Scripts/hw-diags-menu
+++ b/.bin/Scripts/hw-diags-menu
@@ -22,9 +22,8 @@ if __name__ == '__main__':
print_standard(' ')
sleep(1)
pause('Press Enter to exit...')
- except SystemExit:
- # Normal exit
- pass
+ except SystemExit as sys_exit:
+ exit_script(sys_exit.code)
except:
# Cleanup
tmux_kill_all_panes()
diff --git a/.bin/Scripts/hw-diags-network b/.bin/Scripts/hw-diags-network
index 3047e131..138ea67e 100755
--- a/.bin/Scripts/hw-diags-network
+++ b/.bin/Scripts/hw-diags-network
@@ -40,8 +40,8 @@ if __name__ == '__main__':
print_standard('\nDone.')
#pause("Press Enter to exit...")
exit_script()
- except SystemExit:
- pass
+ except SystemExit as sys_exit:
+ exit_script(sys_exit.code)
except:
major_exception()
diff --git a/.bin/Scripts/hw-drive-info b/.bin/Scripts/hw-drive-info
index 71a8d388..df1e1748 100755
--- a/.bin/Scripts/hw-drive-info
+++ b/.bin/Scripts/hw-drive-info
@@ -3,9 +3,9 @@
BLUE='\033[34m'
CLEAR='\033[0m'
+IFS=$'\n'
# List devices
-IFS=$'\n'
for line in $(lsblk -do NAME,TRAN,SIZE,VENDOR,MODEL,SERIAL); do
if [[ "${line:0:4}" == "NAME" ]]; then
echo -e "${BLUE}${line}${CLEAR}"
@@ -15,6 +15,18 @@ for line in $(lsblk -do NAME,TRAN,SIZE,VENDOR,MODEL,SERIAL); do
done
echo ""
+# List loopback devices
+if [[ "$(losetup -l | wc -l)" > 0 ]]; then
+ for line in $(losetup -lO NAME,PARTSCAN,RO,BACK-FILE); do
+ if [[ "${line:0:4}" == "NAME" ]]; then
+ echo -e "${BLUE}${line}${CLEAR}"
+ else
+ echo "${line}" | sed -r 's#/dev/(loop[0-9]+)#\1 #'
+ fi
+ done
+ echo ""
+fi
+
# List partitions
for line in $(lsblk -o NAME,SIZE,FSTYPE,LABEL,MOUNTPOINT); do
if [[ "${line:0:4}" == "NAME" ]]; then
diff --git a/.bin/Scripts/hw-sensors-monitor b/.bin/Scripts/hw-sensors-monitor
index c27d786a..ffdbbad3 100755
--- a/.bin/Scripts/hw-sensors-monitor
+++ b/.bin/Scripts/hw-sensors-monitor
@@ -28,8 +28,8 @@ if __name__ == '__main__':
run_program(cmd, check=False)
monitor_sensors(monitor_pane, monitor_file)
exit_script()
- except SystemExit:
- pass
+ except SystemExit as sys_exit:
+ exit_script(sys_exit.code)
except:
major_exception()
diff --git a/.bin/Scripts/install_eset_nod32_av.py b/.bin/Scripts/install_eset_nod32_av.py
index ecdd9da6..7a2509f7 100644
--- a/.bin/Scripts/install_eset_nod32_av.py
+++ b/.bin/Scripts/install_eset_nod32_av.py
@@ -16,12 +16,12 @@ if __name__ == '__main__':
stay_awake()
clear_screen()
print_info('{}: Install ESET NOD32 AV\n'.format(KIT_NAME_FULL))
- scan_pups = ask('Enable PUP scans in ESET?')
- install_eset_nod32_av(scan_pups)
+ msp = ask('Use MSP settings (ITS/VIP)?')
+ install_eset_nod32_av(msp=msp)
print_standard('\nDone.')
exit_script()
- except SystemExit:
- pass
+ except SystemExit as sys_exit:
+ exit_script(sys_exit.code)
except:
major_exception()
diff --git a/.bin/Scripts/install_sw_bundle.py b/.bin/Scripts/install_sw_bundle.py
index 25f45638..c69a19dd 100644
--- a/.bin/Scripts/install_sw_bundle.py
+++ b/.bin/Scripts/install_sw_bundle.py
@@ -64,8 +64,8 @@ if __name__ == '__main__':
other_results=other_results)
print_standard('\nDone.')
exit_script()
- except SystemExit:
- pass
+ except SystemExit as sys_exit:
+ exit_script(sys_exit.code)
except:
major_exception()
diff --git a/.bin/Scripts/install_vcredists.py b/.bin/Scripts/install_vcredists.py
index a22cc729..1cd31d95 100644
--- a/.bin/Scripts/install_vcredists.py
+++ b/.bin/Scripts/install_vcredists.py
@@ -27,8 +27,8 @@ if __name__ == '__main__':
print_standard('\nDone.')
exit_script()
- except SystemExit:
- pass
+ except SystemExit as sys_exit:
+ exit_script(sys_exit.code)
except:
major_exception()
diff --git a/.bin/Scripts/mount-all-volumes b/.bin/Scripts/mount-all-volumes
index f49439f2..5b34c579 100755
--- a/.bin/Scripts/mount-all-volumes
+++ b/.bin/Scripts/mount-all-volumes
@@ -30,8 +30,8 @@ if __name__ == '__main__':
pause("Press Enter to exit...")
popen_program(['nohup', 'thunar', '/media'], pipe=True)
exit_script()
- except SystemExit:
- pass
+ except SystemExit as sys_exit:
+ exit_script(sys_exit.code)
except:
major_exception()
diff --git a/.bin/Scripts/mount-backup-shares b/.bin/Scripts/mount-backup-shares
index 57fbe572..0d8b7fd3 100755
--- a/.bin/Scripts/mount-backup-shares
+++ b/.bin/Scripts/mount-backup-shares
@@ -16,9 +16,6 @@ if __name__ == '__main__':
# Prep
clear_screen()
- # Connect
- connect_to_network()
-
# Mount
if is_connected():
mount_backup_shares(read_write=True)
@@ -30,8 +27,8 @@ if __name__ == '__main__':
print_standard('\nDone.')
#pause("Press Enter to exit...")
exit_script()
- except SystemExit:
- pass
+ except SystemExit as sys_exit:
+ exit_script(sys_exit.code)
except:
major_exception()
diff --git a/.bin/Scripts/msword-search b/.bin/Scripts/msword-search
index b005c3c1..879e6b8d 100755
--- a/.bin/Scripts/msword-search
+++ b/.bin/Scripts/msword-search
@@ -76,8 +76,8 @@ if __name__ == '__main__':
print_standard('\nDone.')
#pause("Press Enter to exit...")
exit_script()
- except SystemExit:
- pass
+ except SystemExit as sys_exit:
+ exit_script(sys_exit.code)
except:
major_exception()
diff --git a/.bin/Scripts/network_stability_test.py b/.bin/Scripts/network_stability_test.py
index a1ca63b3..cb38ac8d 100644
--- a/.bin/Scripts/network_stability_test.py
+++ b/.bin/Scripts/network_stability_test.py
@@ -38,7 +38,7 @@ if __name__ == '__main__':
print_standard('\nDone.')
pause('Press Enter to exit...')
exit_script()
- except SystemExit:
- pass
+ except SystemExit as sys_exit:
+ exit_script(sys_exit.code)
except:
major_exception()
diff --git a/.bin/Scripts/new_system_setup.py b/.bin/Scripts/new_system_setup.py
deleted file mode 100644
index f3e3e9b2..00000000
--- a/.bin/Scripts/new_system_setup.py
+++ /dev/null
@@ -1,199 +0,0 @@
-# Wizard Kit: New system setup
-
-import os
-import sys
-
-# Init
-os.chdir(os.path.dirname(os.path.realpath(__file__)))
-sys.path.append(os.getcwd())
-from functions.activation import *
-from functions.browsers import *
-from functions.cleanup import *
-from functions.info import *
-from functions.product_keys import *
-from functions.setup import *
-from functions.sw_diags import *
-init_global_vars()
-os.system('title {}: New System Setup'.format(KIT_NAME_FULL))
-set_log_file('New System Setup.log')
-
-if __name__ == '__main__':
- other_results = {
- 'Error': {
- 'BIOSKeyNotFoundError': 'BIOS key not found',
- 'CalledProcessError': 'Unknown Error',
- 'FileNotFoundError': 'File not found',
- 'GenericError': 'Unknown Error',
- 'SecureBootDisabledError': 'Disabled',
- },
- 'Warning': {
- 'GenericRepair': 'Repaired',
- 'NoProfilesError': 'No profiles found',
- 'NotInstalledError': 'Not installed',
- 'OSInstalledLegacyError': 'OS installed Legacy',
- 'SecureBootNotAvailError': 'Not available',
- 'SecureBootUnknownError': 'Unknown',
- 'UnsupportedOSError': 'Unsupported OS',
- }}
- try:
- stay_awake()
- clear_screen()
-
- # Check installed OS
- if os_is_unsupported(show_alert=True):
- print_warning('OS version not supported by this script')
- if not ask('Continue anyway? (NOT RECOMMENDED)'):
- abort()
-
- # Select AV software
- # NOTE: Truth tuple is (ESET, ESET_PUPS, MSE)
- av_options = [
- {'Name': 'ESET NOD32',
- 'Truths': (True, True, False),},
- {'Name': 'ESET NOD32 (no PUP/PUW scans)',
- 'Truths': (True, False, False),},
- {'Name': 'Microsoft Security Essentials',
- 'Disabled': global_vars['OS']['Version'] not in ['7'],
- 'Truths': (False, False, True),},
- ]
- actions = [
- {'Name': 'None', 'Letter': 'N'},
- {'Name': 'Quit', 'Letter': 'Q'},
- ]
- selection = menu_select(
- 'Please select an option to install',
- main_entries=av_options,
- action_entries=actions)
- if selection.isnumeric():
- index = int(selection) - 1
- answer_eset, answer_pups, answer_mse = av_options[index]['Truths']
- elif selection == 'Q':
- abort()
- else:
- answer_eset = False
- answer_pups = False
- answer_mse = False
-
- # Install LibreOffice?
- answer_libreoffice = ask('Install LibreOffice?')
-
- # Install software
- print_info('Installing Programs')
- install_vcredists()
- if answer_eset:
- install_eset_nod32_av(scan_pups=answer_pups)
- result = try_and_print(
- message='Ninite bundle...',
- function=install_ninite_bundle, cs='Started',
- mse=answer_mse, libreoffice=answer_libreoffice,
- other_results=other_results)
- try:
- for proc in result['Out']:
- # Wait for all processes to finish
- print_standard('Waiting for installations to finish...')
- proc.wait()
- except KeyboardInterrupt:
- pass
-
- # Scan for supported browsers
- print_info('Scanning for browsers')
- scan_for_browsers(skip_ie=True)
-
- # Install extensions
- print_info('Installing Extensions')
- try_and_print(message='Classic Shell skin...',
- function=install_classicstart_skin,
- other_results=other_results)
- try_and_print(message='Google Chrome extensions...',
- function=install_chrome_extensions)
- try_and_print(message='Mozilla Firefox extensions...',
- function=install_firefox_extensions,
- other_results=other_results)
-
- # Configure software
- print_info('Configuring programs')
- print_standard(' (if stuck press CTRL+c to cancel this step).')
- try:
- install_adblock()
- except KeyboardInterrupt:
- print_warning('Configuration interrupted.')
- print_standard('Please confirm all browsers have adblock installed.')
- if not ask('Continue to next step?'):
- abort()
- if global_vars['OS']['Version'] == '10':
- try_and_print(message='ClassicStart...',
- function=config_classicstart, cs='Done')
- try_and_print(message='Explorer (user)...',
- function=config_explorer_user, cs='Done')
-
- # Configure system
- print_info('Configuring system')
- if global_vars['OS']['Version'] == '10':
- try_and_print(message='Explorer (system)...',
- function=config_explorer_system, cs='Done')
- try_and_print(message='Disabling telemetry...',
- function=disable_windows_telemetry, cs='Done')
- try_and_print(message='Enabling RegBack...',
- function=enable_regback, cs='Done')
- try_and_print(message='Windows Updates...',
- function=config_windows_updates, cs='Done')
- try_and_print(message='Enabling System Restore...',
- function=enable_system_restore, cs='Done')
- try_and_print(message='Updating Clock...',
- function=update_clock, cs='Done')
-
- # Restart Explorer
- try_and_print(message='Restarting Explorer...',
- function=restart_explorer, cs='Done')
-
- # Summary
- print_info('Summary')
- try_and_print(message='Operating System:',
- function=show_os_name, ns='Unknown', silent_function=False)
- try_and_print(message='Activation:',
- function=show_os_activation, ns='Unknown', silent_function=False)
- if (not windows_is_activated()
- and global_vars['OS']['Version'] in ('8', '8.1', '10')):
- try_and_print(message='BIOS Activation:',
- function=activate_with_bios,
- other_results=other_results)
- try_and_print(message='Secure Boot Status:',
- function=check_secure_boot_status, other_results=other_results)
- try_and_print(message='Installed RAM:',
- function=show_installed_ram, ns='Unknown', silent_function=False)
- show_free_space()
- try_and_print(message='Installed Antivirus:',
- function=get_installed_antivirus, ns='Unknown',
- other_results=other_results, print_return=True)
-
- # Play audio, show devices, open Windows updates, and open Activation
- try_and_print(message='Opening Device Manager...',
- function=open_device_manager, cs='Started')
- try_and_print(message='Opening HWiNFO (Sensors)...',
- function=run_hwinfo_sensors, cs='Started', other_results=other_results)
- try_and_print(message='Opening SDI Origin...',
- function=open_snappy_driver_origin, cs='Started')
- try_and_print(message='Opening Windows Updates...',
- function=open_windows_updates, cs='Started')
- if not windows_is_activated():
- try_and_print(message='Opening Windows Activation...',
- function=open_windows_activation, cs='Started')
- sleep(3)
- try_and_print(message='Running XMPlay...',
- function=run_xmplay, cs='Started', other_results=other_results)
- try:
- check_secure_boot_status(show_alert=True)
- except:
- # Only trying to open alert message boxes
- pass
-
- # Done
- print_standard('\nDone.')
- pause('Press Enter to exit...')
- exit_script()
- except SystemExit:
- pass
- except:
- major_exception()
-
-# vim: sts=2 sw=2 ts=2
diff --git a/.bin/Scripts/post_d7.py b/.bin/Scripts/post_d7.py
deleted file mode 100644
index 2fa8f9f2..00000000
--- a/.bin/Scripts/post_d7.py
+++ /dev/null
@@ -1,55 +0,0 @@
-# Wizard Kit: Post-d7II items
-
-import os
-import sys
-
-# Init
-os.chdir(os.path.dirname(os.path.realpath(__file__)))
-sys.path.append(os.getcwd())
-from functions.browsers import *
-from functions.cleanup import *
-from functions.setup import *
-init_global_vars()
-os.system('title {}: Post-d7II Work'.format(KIT_NAME_FULL))
-set_log_file('Post-d7II Work.log')
-
-if __name__ == '__main__':
- try:
- stay_awake()
- clear_screen()
- print_info('{}: Post-d7II Work\n'.format(KIT_NAME_FULL))
- other_results = {
- 'Warning': {
- 'NotInstalledError': 'Not installed',
- 'NoProfilesError': 'No profiles found',
- }}
-
- # Scan for Firefox browsers
- print_info('Scanning for Firefox browsers')
- scan_for_browsers(just_firefox=True)
-
- # Install uBlock Origin
- print_info('Installing uBlock Origin')
- install_adblock(just_firefox=True)
-
- # Cleanup
- print_info('Cleanup')
- try_and_print(message='d7II...',
- function=cleanup_d7ii, cs='Done')
- try_and_print(message='{}...'.format(KIT_NAME_FULL),
- function=delete_empty_folders, cs='Done',
- folder_path=global_vars['ClientDir'])
-
- # Run speedtest
- popen_program(['start', '', 'https://fast.com'], shell=True)
-
- # Done
- print_standard('\nDone.')
- pause('Press Enter to exit...')
- exit_script()
- except SystemExit:
- pass
- except:
- major_exception()
-
-# vim: sts=2 sw=2 ts=2
diff --git a/.bin/Scripts/reset_browsers.py b/.bin/Scripts/reset_browsers.py
index 58f15f42..4130af5a 100644
--- a/.bin/Scripts/reset_browsers.py
+++ b/.bin/Scripts/reset_browsers.py
@@ -47,7 +47,7 @@ if __name__ == '__main__':
# Done
exit_script()
- except SystemExit:
- pass
+ except SystemExit as sys_exit:
+ exit_script(sys_exit.code)
except:
major_exception()
diff --git a/.bin/Scripts/safemode_enter.py b/.bin/Scripts/safemode_enter.py
index bc6d659d..de9ad119 100644
--- a/.bin/Scripts/safemode_enter.py
+++ b/.bin/Scripts/safemode_enter.py
@@ -31,8 +31,8 @@ if __name__ == '__main__':
pause('Press Enter to reboot...')
reboot()
exit_script()
- except SystemExit:
- pass
+ except SystemExit as sys_exit:
+ exit_script(sys_exit.code)
except:
major_exception()
diff --git a/.bin/Scripts/safemode_exit.py b/.bin/Scripts/safemode_exit.py
index bbbdbcf8..6c47b02d 100644
--- a/.bin/Scripts/safemode_exit.py
+++ b/.bin/Scripts/safemode_exit.py
@@ -31,8 +31,8 @@ if __name__ == '__main__':
pause('Press Enter to reboot...')
reboot()
exit_script()
- except SystemExit:
- pass
+ except SystemExit as sys_exit:
+ exit_script(sys_exit.code)
except:
major_exception()
diff --git a/.bin/Scripts/settings/cleanup.py b/.bin/Scripts/settings/cleanup.py
new file mode 100644
index 00000000..fd4a595b
--- /dev/null
+++ b/.bin/Scripts/settings/cleanup.py
@@ -0,0 +1,66 @@
+# Wizard Kit: Settings - Cleanup
+
+import re
+import psutil
+try:
+ import winreg
+except ModuleNotFoundError:
+ if psutil.WINDOWS:
+ raise
+
+# d7II
+D7_HKCR_CLEANUP = {
+ r'batfile\shell\!!RunWithParms': {'Recurse': True},
+ r'batfile\shell\{0001B4FD-9EA3-4D90-A79E-FD14BA3AB01D}': {'Recurse': True},
+ r'cmdfile\shell\!!RunWithParms': {'Recurse': True},
+ r'cmdfile\shell\{0001B4FD-9EA3-4D90-A79E-FD14BA3AB01D}': {'Recurse': True},
+ r'exefile\shell\!!RunWithParms': {'Recurse': True},
+ r'exefile\shell\ResourceHacker': {'Recurse': True},
+ r'regfile\shell\!!RunWithParms': {'Recurse': True},
+ r'regfile\shell\{0001B4FD-9EA3-4D90-A79E-FD14BA3AB01D}': {'Recurse': True},
+ }
+D7_HKCU_CLEANUP = {
+ r'Software\Malwarebytes': {'Recurse': False},
+ }
+D7_HKLM_CLEANUP = {
+ r'Software\Emsisoft': {'Recurse': False},
+ }
+
+# Regex
+DESKTOP_ITEMS = re.compile(
+ r'^(JRT|RKill|sc-cleaner|Transfer_Log)',
+ re.IGNORECASE,
+ )
+
+# Registry
+HKU = winreg.HKEY_USERS
+HKCR = winreg.HKEY_CLASSES_ROOT
+HKCU = winreg.HKEY_CURRENT_USER
+HKLM = winreg.HKEY_LOCAL_MACHINE
+UAC_DEFAULTS_WIN7 = {
+ r'Software\Microsoft\Windows\CurrentVersion\Policies\System': {
+ 'DWORD Items': {
+ 'ConsentPromptBehaviorAdmin': 5,
+ 'EnableLUA': 1,
+ 'PromptOnSecureDesktop': 1,
+ },
+ },
+ }
+UAC_DEFAULTS_WIN10 = {
+ r'Software\Microsoft\Windows\CurrentVersion\Policies\System': {
+ 'DWORD Items': {
+ 'ConsentPromptBehaviorAdmin': 5,
+ 'ConsentPromptBehaviorUser': 3,
+ 'EnableInstallerDetection': 1,
+ 'EnableLUA': 1,
+ 'EnableVirtualization': 1,
+ 'PromptOnSecureDesktop': 1,
+ },
+ },
+ }
+
+
+if __name__ == '__main__':
+ print("This file is not meant to be called directly.")
+
+# vim: sts=2 sw=2 ts=2
diff --git a/.bin/Scripts/settings/ddrescue.py b/.bin/Scripts/settings/ddrescue.py
index 675019ca..bc9bef93 100644
--- a/.bin/Scripts/settings/ddrescue.py
+++ b/.bin/Scripts/settings/ddrescue.py
@@ -5,7 +5,9 @@ import re
from collections import OrderedDict
# General
+MAP_DIR = '/Backups/Anaconda'
RECOMMENDED_FSTYPES = ['ext3', 'ext4', 'xfs']
+RECOMMENDED_MAP_FSTYPES = ['cifs', 'ext2', 'ext3', 'ext4', 'vfat', 'xfs']
USAGE = """ {script_name} clone [source [destination]]
{script_name} image [source [destination]]
(e.g. {script_name} clone /dev/sda /dev/sdb)
@@ -36,6 +38,12 @@ DDRESCUE_SETTINGS = {
'-vvvv': {'Enabled': True, 'Hidden': True, },
}
ETOC_REFRESH_RATE = 30 # in seconds
+REGEX_DDRESCUE_LOG = re.compile(
+ r'^\s*(?P\S+):\s+'
+ r'(?P\d+)\s+'
+ r'(?P[PTGMKB])i?B?',
+ re.IGNORECASE,
+ )
REGEX_REMAINING_TIME = re.compile(
r'remaining time:'
r'\s*((?P\d+)d)?'
diff --git a/.bin/Scripts/settings/launchers.py b/.bin/Scripts/settings/launchers.py
index 76dbd7d9..ca7ea636 100644
--- a/.bin/Scripts/settings/launchers.py
+++ b/.bin/Scripts/settings/launchers.py
@@ -2,46 +2,17 @@
LAUNCHERS = {
r'(Root)': {
- 'Activate Windows': {
- 'L_TYPE': 'PyScript',
- 'L_PATH': 'Scripts',
- 'L_ITEM': 'activate.py',
- 'L_ELEV': 'True',
- },
'd7II': {
'L_TYPE': 'Executable',
'L_PATH': 'd7II',
'L_ITEM': 'd7II.exe',
},
- 'New System Setup': {
+ 'System Setup': {
'L_TYPE': 'PyScript',
'L_PATH': 'Scripts',
- 'L_ITEM': 'new_system_setup.py',
+ 'L_ITEM': 'system_setup.py',
'L_ELEV': 'True',
},
- 'Post-d7II Work': {
- 'L_TYPE': 'PyScript',
- 'L_PATH': 'Scripts',
- 'L_ITEM': 'post_d7.py',
- 'L_ELEV': 'True',
- },
- 'System Checklist': {
- 'L_TYPE': 'PyScript',
- 'L_PATH': 'Scripts',
- 'L_ITEM': 'system_checklist.py',
- 'L_ELEV': 'True',
- },
- 'System Checklist (HW)': {
- 'L_TYPE': 'PyScript',
- 'L_PATH': 'Scripts',
- 'L_ITEM': 'system_checklist_hw.py',
- 'L_ELEV': 'True',
- },
- 'User Checklist': {
- 'L_TYPE': 'PyScript',
- 'L_PATH': 'Scripts',
- 'L_ITEM': 'user_checklist.py',
- },
},
r'.bin\Scripts\launchers_for_d7': {
'Browser Reset': {
@@ -50,20 +21,6 @@ LAUNCHERS = {
'L_ITEM': 'reset_browsers.py',
'L_ARGS': 'd7mode',
},
- 'Install SW Bundle': {
- 'L_TYPE': 'PyScript',
- 'L_PATH': 'Scripts',
- 'L_ITEM': 'install_sw_bundle.py',
- 'L_ARGS': 'd7mode',
- 'L_ELEV': 'True',
- },
- 'System Checklist': {
- 'L_TYPE': 'PyScript',
- 'L_PATH': 'Scripts',
- 'L_ITEM': 'system_checklist.py',
- 'L_ARGS': 'd7mode',
- 'L_ELEV': 'True',
- },
'System Diagnostics': {
'L_TYPE': 'PyScript',
'L_PATH': 'Scripts',
@@ -71,12 +28,6 @@ LAUNCHERS = {
'L_ARGS': 'd7mode',
'L_ELEV': 'True',
},
- 'User Checklist': {
- 'L_TYPE': 'PyScript',
- 'L_PATH': 'Scripts',
- 'L_ITEM': 'user_checklist.py',
- 'L_ARGS': 'd7mode',
- },
'Disable Windows Updates': {
'L_TYPE': 'PyScript',
'L_PATH': 'Scripts',
@@ -533,6 +484,12 @@ LAUNCHERS = {
},
},
r'Misc': {
+ 'Activate Windows': {
+ 'L_TYPE': 'PyScript',
+ 'L_PATH': 'Scripts',
+ 'L_ITEM': 'activate.py',
+ 'L_ELEV': 'True',
+ },
'Cleanup CBS Temp Files': {
'L_TYPE': 'PyScript',
'L_PATH': 'Scripts',
diff --git a/.bin/Scripts/settings/main.py b/.bin/Scripts/settings/main.py
index c104a45f..896d9c62 100644
--- a/.bin/Scripts/settings/main.py
+++ b/.bin/Scripts/settings/main.py
@@ -25,16 +25,13 @@ QUICKBOOKS_SERVER_IP='10.11.1.20'
# Time Zones
LINUX_TIME_ZONE='America/Los_Angeles' # See 'timedatectl list-timezones' for valid values
WINDOWS_TIME_ZONE='Pacific Standard Time' # See 'tzutil /l' for valid values
-# WiFi
-WIFI_SSID='1201Computers'
-WIFI_PASSWORD='justintime!'
# SERVER VARIABLES
## NOTE: Windows can only use one user per server. This means that if
## one server serves multiple shares then you have to use the same
## user/password for all of those shares.
BACKUP_SERVERS = [
- { 'IP': '10.11.1.20',
+ { 'IP': '10.120.1.15',
'Name': 'Anaconda',
'Mounted': False,
'Share': 'Backups',
@@ -43,18 +40,28 @@ BACKUP_SERVERS = [
'RW-User': 'backup',
'RW-Pass': '1201 loves computers!',
},
+ # DISABLED due to issues handling mounting a subdir
+ #{ 'IP': '10.120.1.23',
+ # 'Name': 'Server1201',
+ # 'Mounted': False,
+ # 'Share': r'Public\TEMP',
+ # 'User': 'cx',
+ # 'Pass': '',
+ # 'RW-User': 'it',
+ # 'RW-Pass': 'sorted',
+ #},
]
BENCHMARK_SERVER = {
'Name': 'Nextcloud',
- 'Short Url': 'https://1201north.ddns.net:8001/index.php/f/27892',
- 'Url': 'https://1201north.ddns.net:8001/public.php/webdav/Benchmarks',
- 'User': 'RAE7ajRk25CBnW6',
+ 'Short Url': 'https://nextcloud.1201.com/index.php/f/108024',
+ 'Url': 'https://1201.ddns.net:8001/public.php/webdav/Benchmarks',
+ 'User': 'QAx28ZgmPwCwGHc',
'Pass': '',
}
CRASH_SERVER = {
'Name': 'Nextcloud',
- 'Url': 'https://1201north.ddns.net:8001/public.php/webdav/WizardKit_Issues',
- 'User': 'LoQ97J3r6CFGT2T',
+ 'Url': 'https://1201.ddns.net:8001/public.php/webdav/Issues',
+ 'User': 'n9Ds76WizNyBw8Y',
'Pass': '',
}
OFFICE_SERVER = {
@@ -78,10 +85,10 @@ QUICKBOOKS_SERVER = {
'RW-Pass': '1201 loves computers!',
}
WINDOWS_SERVER = {
- 'IP': '10.11.1.20',
+ 'IP': '10.120.1.15',
'Name': 'Anaconda',
'Mounted': False,
- 'Share': r'Public\Windows',
+ 'Share': r'HH-Proliant\Windows',
'User': 'cx',
'Pass': 'cx',
'RW-User': 'backup',
diff --git a/.bin/Scripts/settings/osticket.py b/.bin/Scripts/settings/osticket.py
index 6360a579..dc30ced3 100644
--- a/.bin/Scripts/settings/osticket.py
+++ b/.bin/Scripts/settings/osticket.py
@@ -26,6 +26,22 @@ OSTICKET = {
'Ticket': 'ost_ticket',
},
}
+TEST_STATIONS = {
+ 'bender': 'Bender',
+ 'combine': 'Combine',
+ 'control': 'Control',
+ 'cortana': 'Cortana',
+ 'data': 'Data',
+ 'glados': 'GLaDOS',
+ 'locutus': 'Locutus',
+ 'lore': 'Lore',
+ 'sex-robot': 'Sex-Robot',
+ 'shodan': 'Shodan',
+ 'six': 'Six',
+ 'skynet': 'Skynet',
+ 'supremo': 'Supremo',
+ 'unicron': 'Unicron',
+ }
if __name__ == '__main__':
print("This file is not meant to be called directly.")
diff --git a/.bin/Scripts/settings/setup.py b/.bin/Scripts/settings/setup.py
index db30fe19..e3f504cc 100644
--- a/.bin/Scripts/settings/setup.py
+++ b/.bin/Scripts/settings/setup.py
@@ -1,13 +1,19 @@
-# Wizard Kit: Settings - Setup
+'''Wizard Kit: Settings - Setup'''
+# pylint: disable=bad-continuation,line-too-long
+# vim: sts=2 sw=2 ts=2
import os
-import winreg
+try:
+ import winreg
+ HKU = winreg.HKEY_USERS
+ HKCR = winreg.HKEY_CLASSES_ROOT
+ HKCU = winreg.HKEY_CURRENT_USER
+ HKLM = winreg.HKEY_LOCAL_MACHINE
+except ImportError:
+ if os.name != 'posix':
+ raise
# General
-HKU = winreg.HKEY_USERS
-HKCR = winreg.HKEY_CLASSES_ROOT
-HKCU = winreg.HKEY_CURRENT_USER
-HKLM = winreg.HKEY_LOCAL_MACHINE
OTHER_RESULTS = {
'Error': {
'CalledProcessError': 'Unknown Error',
@@ -63,10 +69,18 @@ SETTINGS_CLASSIC_START = {
}
# ESET
-SETTINGS_ESET = {
+SETTINGS_ESET_SYSTEM = {
+ r'Software\ESET\ESET Security\CurrentVersion\Config\Settings\LiveGrid': {
+ 'DWORD Items': {
+ 'LiveGridFeedbackEnabled': 1,
+ },
+ },
+ }
+SETTINGS_ESET_USER = {
r'Software\ESET\ESET Security\CurrentVersion\gui\UI_CONFIG': {
'DWORD Items': {
'FullScreenMode': 0,
+ 'ShowAlertStatus': 0x40000000,
'ShowDesktopAlert': 0,
'ShowSplash': 0,
},
@@ -109,6 +123,7 @@ SETTINGS_EXPLORER_SYSTEM = {
SETTINGS_EXPLORER_USER = {
# Desktop icons
r'Software\Microsoft\Windows\CurrentVersion\Explorer\HideDesktopIcons\ClassicStartMenu': {
+ 'Invalid modes': ['Cur'],
'DWORD Items': {
# This PC
'{20D04FE0-3AEA-1069-A2D8-08002B30309D}': 0,
@@ -117,6 +132,7 @@ SETTINGS_EXPLORER_USER = {
},
},
r'Software\Microsoft\Windows\CurrentVersion\Explorer\HideDesktopIcons\NewStartPanel': {
+ 'Invalid modes': ['Cur'],
'DWORD Items': {
# This PC
'{20D04FE0-3AEA-1069-A2D8-08002B30309D}': 0,
@@ -124,6 +140,15 @@ SETTINGS_EXPLORER_USER = {
'{59031a47-3f72-44a7-89c5-5595fe6b30ee}': 0,
},
},
+ # Desktop theme
+ r'Software\Microsoft\Windows\CurrentVersion\Themes\Personalize': {
+ 'Invalid modes': ['Cur'],
+ 'DWORD Items': {
+ # <= v1809 default
+ 'AppsUseLightTheme': 1,
+ 'SystemUsesLightTheme': 0,
+ },
+ },
# Disable features
r'Software\Microsoft\Windows\CurrentVersion\ContentDeliveryManager': {
'DWORD Items': {
@@ -136,25 +161,49 @@ SETTINGS_EXPLORER_USER = {
},
# File Explorer
r'Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced': {
+ 'Invalid modes': ['Cur'],
'DWORD Items': {
# Replace PowerShell with CMD in Win+X menu
'DontUsePowerShellOnWinX': 1,
# Change default Explorer view to "Computer"
'LaunchTo': 1,
+ },
+ },
+ r'SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Advanced': {
+ 'DWORD Items': {
# Launch Folder Windows in a Separate Process
'SeparateProcess': 1,
},
},
# Hide People bar
r'Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced\People': {
+ 'Invalid modes': ['Cur'],
'DWORD Items': {'PeopleBand': 0},
},
# Hide Search button / box
r'Software\Microsoft\Windows\CurrentVersion\Search': {
+ 'Invalid modes': ['Cur'],
'DWORD Items': {'SearchboxTaskbarMode': 1},
},
}
+# Fast Startup
+SETTINGS_FAST_STARTUP = {
+ # Disable Fast Startup
+ r'SOFTWARE\Policies\Microsoft\Windows\System': {
+ 'DWORD Items': {'HiberbootEnabled': 0},
+ },
+ }
+
+# LibreOffice
+LIBREOFFICE_XCU_DATA = '''
+
+- Impress MS PowerPoint 2007 XML
+- Calc MS Excel 2007 XML
+- MS Word 2007 XML
+
+'''
+
# Registry
SETTINGS_REGBACK = {
# Enable RegBack
@@ -201,5 +250,3 @@ SETTINGS_WINDOWS_UPDATES = {
if __name__ == '__main__':
print("This file is not meant to be called directly.")
-
-# vim: sts=2 sw=2 ts=2
diff --git a/.bin/Scripts/settings/sources.py b/.bin/Scripts/settings/sources.py
index 517add65..817441b5 100644
--- a/.bin/Scripts/settings/sources.py
+++ b/.bin/Scripts/settings/sources.py
@@ -1,4 +1,6 @@
-# Wizard Kit: Settings - Sources
+'''Wizard Kit: Settings - Sources'''
+# pylint: disable=line-too-long
+# vim: sts=2 sw=2 ts=2 tw=0
SOURCE_URLS = {
'Adobe Reader DC': 'http://ardownload.adobe.com/pub/adobe/reader/win/AcrobatDC/1901020098/AcroRdrDC1901020098_en_US.exe',
@@ -17,7 +19,7 @@ SOURCE_URLS = {
'ESET NOD32 AV': 'https://download.eset.com/com/eset/apps/home/eav/windows/latest/eav_nt64.exe',
'Everything32': 'https://www.voidtools.com/Everything-1.4.1.935.x86.en-US.zip',
'Everything64': 'https://www.voidtools.com/Everything-1.4.1.935.x64.en-US.zip',
- 'FastCopy': 'http://ftp.vector.co.jp/71/31/2323/FastCopy363_installer.exe',
+ 'FastCopy': 'https://fastcopy.jp/archive/FastCopy380_installer.exe',
'FurMark': 'https://geeks3d.com/dl/get/569',
'Firefox uBO': 'https://addons.mozilla.org/firefox/downloads/file/1709472/ublock_origin-1.18.6-an+fx.xpi',
'HitmanPro32': 'https://dl.surfright.nl/HitmanPro.exe',
@@ -26,6 +28,7 @@ SOURCE_URLS = {
'Intel SSD Toolbox': r'https://downloadmirror.intel.com/28593/eng/Intel%20SSD%20Toolbox%20-%20v3.5.9.exe',
'IOBit_Uninstaller': r'https://portableapps.com/redirect/?a=IObitUninstallerPortable&s=s&d=pa&f=IObitUninstallerPortable_7.5.0.7.paf.exe',
'KVRT': 'http://devbuilds.kaspersky-labs.com/devbuilds/KVRT/latest/full/KVRT.exe',
+ 'LibreOffice': 'https://download.documentfoundation.org/libreoffice/stable/6.2.4/win/x86_64/LibreOffice_6.2.4_Win_x64.msi',
'Linux Reader': 'https://www.diskinternals.com/download/Linux_Reader.exe',
'Macs Fan Control': 'https://www.crystalidea.com/downloads/macsfancontrol_setup.exe',
'NirCmd32': 'https://www.nirsoft.net/utils/nircmd.zip',
@@ -40,10 +43,11 @@ SOURCE_URLS = {
'SDIO Themes': 'http://snappy-driver-installer.org/downloads/SDIO_Themes.zip',
'SDIO Torrent': 'http://snappy-driver-installer.org/downloads/SDIO_Update.torrent',
'ShutUp10': 'https://dl5.oo-software.com/files/ooshutup10/OOSU10.exe',
+ 'smartmontools': 'https://700-105252244-gh.circle-artifacts.com/0/builds/smartmontools-win32-setup-7.1-r4914.exe',
'TDSSKiller': 'https://media.kaspersky.com/utilities/VirusUtilities/EN/tdsskiller.exe',
'TestDisk': 'https://www.cgsecurity.org/testdisk-7.1-WIP.win.zip',
- 'wimlib32': 'https://wimlib.net/downloads/wimlib-1.13.0-windows-i686-bin.zip',
- 'wimlib64': 'https://wimlib.net/downloads/wimlib-1.13.0-windows-x86_64-bin.zip',
+ 'wimlib32': 'https://wimlib.net/downloads/wimlib-1.13.1-windows-i686-bin.zip',
+ 'wimlib64': 'https://wimlib.net/downloads/wimlib-1.13.1-windows-x86_64-bin.zip',
'WinAIO Repair': 'http://www.tweaking.com/files/setups/tweaking.com_windows_repair_aio.zip',
'Winapp2': 'https://github.com/MoscaDotTo/Winapp2/archive/master.zip',
'WizTree': 'https://antibody-software.com/files/wiztree_3_28_portable.zip',
@@ -72,10 +76,18 @@ VCREDIST_SOURCES = {
'64': 'https://aka.ms/vs/15/release/vc_redist.x64.exe',
},
}
+NINITE_REGEX = {
+ 'base': ['7-Zip', 'VLC'],
+ 'standard': ['Google Chrome', 'Mozilla Firefox', 'SumatraPDF'],
+ 'standard7': ['Google Chrome', 'Mozilla Firefox', 'SumatraPDF'],
+ }
NINITE_SOURCES = {
'Bundles': {
- 'Legacy.exe': '.net4.7.2-7zip-chrome-firefox-sumatrapdf-vlc',
- 'Modern.exe': '.net4.7.2-7zip-chrome-classicstart-firefox-sumatrapdf-vlc',
+ 'base.exe': '.net4.7.2-7zip-vlc',
+ 'base-standard.exe': '.net4.7.2-7zip-chrome-classicstart-firefox-sumatrapdf-vlc',
+ 'base-standard7.exe': '.net4.7.2-7zip-chrome-firefox-sumatrapdf-vlc',
+ 'standard.exe': 'chrome-classicstart-firefox-sumatrapdf',
+ 'standard7.exe': 'chrome-firefox-sumatrapdf',
},
'Audio-Video': {
'AIMP.exe': 'aimp',
@@ -222,5 +234,3 @@ WINDOWS_UPDATE_SOURCES = {
if __name__ == '__main__':
print("This file is not meant to be called directly.")
-
-# vim: sts=2 sw=2 ts=2 tw=0
diff --git a/.bin/Scripts/settings/tools.py b/.bin/Scripts/settings/tools.py
index dd3812e1..a2471520 100644
--- a/.bin/Scripts/settings/tools.py
+++ b/.bin/Scripts/settings/tools.py
@@ -43,6 +43,9 @@ TOOLS = {
'SevenZip': {
'32': r'7-Zip\7za.exe',
'64': r'7-Zip\7za64.exe'},
+ 'smartctl': {
+ '32': r'smartmontools\smartctl.exe',
+ '64': r'smartmontools\smartctl64.exe'},
'TDSSKiller': {
'32': r'TDSSKiller\TDSSKiller.exe'},
'wimlib-imagex': {
diff --git a/.bin/Scripts/settings/ufd.py b/.bin/Scripts/settings/ufd.py
new file mode 100644
index 00000000..77b7f6df
--- /dev/null
+++ b/.bin/Scripts/settings/ufd.py
@@ -0,0 +1,143 @@
+'''Wizard Kit: Settings - UFD'''
+# pylint: disable=C0326,E0611
+# vim: sts=2 sw=2 ts=2
+
+from collections import OrderedDict
+from settings.main import KIT_NAME_FULL,KIT_NAME_SHORT
+
+# General
+DOCSTRING = '''WizardKit: Build UFD
+
+Usage:
+ build-ufd [options] --ufd-device PATH --linux PATH
+ [--linux-minimal PATH]
+ [--main-kit PATH]
+ [--winpe PATH]
+ [--eset PATH]
+ [--hdclone PATH]
+ [--extra-dir PATH]
+ build-ufd (-h | --help)
+
+Options:
+ -c PATH, --hdclone PATH
+ -d PATH, --linux-dgpu PATH
+ -e PATH, --extra-dir PATH
+ -k PATH, --main-kit PATH
+ -l PATH, --linux PATH
+ -m PATH, --linux-minimal PATH
+ -s PATH, --eset PATH
+ -u PATH, --ufd-device PATH
+ -w PATH, --winpe PATH
+
+ -h --help Show this page
+ -M --use-mbr Use real MBR instead of GPT w/ Protective MBR
+ -F --force Bypass all confirmation messages. USE WITH EXTREME CAUTION!
+ -U --update Don't format device, just update
+'''
+ISO_LABEL = '{}_LINUX'.format(KIT_NAME_SHORT)
+UFD_LABEL = '{}_UFD'.format(KIT_NAME_SHORT)
+UFD_SOURCES = OrderedDict({
+ 'Linux': {'Arg': '--linux', 'Type': 'ISO'},
+ 'Linux (dGPU)': {'Arg': '--linux-dgpu', 'Type': 'ISO'},
+ 'Linux (Minimal)': {'Arg': '--linux-minimal', 'Type': 'ISO'},
+ 'WinPE': {'Arg': '--winpe', 'Type': 'ISO'},
+ 'ESET SysRescue': {'Arg': '--eset', 'Type': 'IMG'},
+ 'HDClone': {'Arg': '--hdclone', 'Type': 'IMG'},
+ 'Main Kit': {'Arg': '--main-kit', 'Type': 'KIT'},
+ 'Extra Dir': {'Arg': '--extra-dir', 'Type': 'DIR'},
+ })
+
+# Definitions: Boot entries
+BOOT_ENTRIES = {
+ # Path to check: Comment to remove
+ '/arch_minimal': 'UFD-MINIMAL',
+ '/casper': 'UFD-ESET',
+ '/dgpu': 'UFD-DGPU',
+ '/kernel.map': 'UFD-HDCLONE',
+ '/sources/boot.wim': 'UFD-WINPE',
+ }
+BOOT_FILES = {
+ # Directory: extension
+ '/arch/boot/syslinux': 'cfg',
+ '/boot/grub/': 'cfg',
+ '/EFI/boot': 'conf',
+ }
+
+# Definitions: Sources and Destinations
+## NOTES: Paths are relative to the root of the ISO/UFD
+## Sources use rsync's trailing slash syntax
+ITEMS = {
+ 'ESET SysRescue': (
+ ('/boot/grub/', '/boot/grub/'),
+ ('/casper/', '/casper/'),
+ ('/EFI/boot/', '/EFI/ESET/'),
+ ),
+ 'Extra Dir': (
+ ('/', '/'),
+ ),
+ 'HDClone': (
+ ('/bootenv', '/'),
+ ('/kernel.map', '/'),
+ ('/EFI/boot/', '/EFI/HDClone/'),
+ ('/hdclone.iso', '/sources/'),
+ ),
+ 'Linux': (
+ ('/arch', '/'),
+ ('/isolinux', '/'),
+ ('/EFI/boot', '/EFI/'),
+ ('/EFI/memtest86', '/EFI/'),
+ ),
+ 'Linux (dGPU)': (
+ ('/arch/boot/x86_64/archiso.img', '/dgpu/'),
+ ('/arch/boot/x86_64/vmlinuz', '/dgpu/'),
+ ('/arch/pkglist.x86_64.txt', '/dgpu/'),
+ ('/arch/x86_64', '/dgpu/'),
+ ),
+ 'Linux (Minimal)': (
+ ('/arch/boot/x86_64/archiso.img', '/arch_minimal/'),
+ ('/arch/boot/x86_64/vmlinuz', '/arch_minimal/'),
+ ('/arch/pkglist.x86_64.txt', '/arch_minimal/'),
+ ('/arch/x86_64', '/arch_minimal/'),
+ ),
+ 'Main Kit': (
+ ('/', '/{}/'.format(KIT_NAME_FULL)),
+ ),
+ 'WinPE': (
+ ('/bootmgr', '/'),
+ ('/bootmgr.efi', '/'),
+ ('/en_us', '/'),
+ ('/Boot/', '/boot/'),
+ ('/EFI/Boot/', '/EFI/Microsoft/'),
+ ('/EFI/Microsoft/', '/EFI/Microsoft/'),
+ ('/Boot/BCD', '/sources/'),
+ ('/Boot/boot.sdi', '/sources/'),
+ ('/bootmgr', '/sources/'),
+ ('/sources/boot.wim', '/sources/'),
+ ),
+ }
+ITEMS_HIDDEN = (
+ # ESET
+ 'casper',
+ # HDClone
+ 'bootenv',
+ 'kernel.map',
+ # Linux (all versions)
+ 'arch',
+ 'arch_minimal',
+ 'dgpu',
+ 'EFI',
+ 'isolinux',
+ # Main Kit
+ '{}/.bin'.format(KIT_NAME_FULL),
+ '{}/.cbin'.format(KIT_NAME_FULL),
+ # WinPE
+ 'boot',
+ 'bootmgr',
+ 'bootmgr.efi',
+ 'en-us',
+ 'images',
+ 'sources',
+ )
+
+if __name__ == '__main__':
+ print("This file is not meant to be called directly.")
diff --git a/.bin/Scripts/settings/windows_builds.py b/.bin/Scripts/settings/windows_builds.py
index db538bf2..f7481294 100644
--- a/.bin/Scripts/settings/windows_builds.py
+++ b/.bin/Scripts/settings/windows_builds.py
@@ -1,8 +1,10 @@
-# Wizard Kit: Settings - Windows Builds
+'''Wizard Kit: Settings - Windows Builds'''
+# pylint: disable=bad-continuation,bad-whitespace
+# vim: sts=2 sw=2 ts=2
+## NOTE: Data from here: https://en.wikipedia.org/wiki/Windows_10_version_history
WINDOWS_BUILDS = {
# Build, Version, Release, Codename, Marketing Name, Notes
- '6000': ('Vista', 'RTM', 'Longhorn', None, 'unsupported'),
'6000': ('Vista', 'RTM', 'Longhorn', None, 'unsupported'),
'6001': ('Vista', 'SP1', 'Longhorn', None, 'unsupported'),
'6002': ('Vista', 'SP2', 'Longhorn', None, 'unsupported'),
@@ -202,15 +204,22 @@ WINDOWS_BUILDS = {
'18356': ('10', None, '19H1', None, 'preview build'),
'18358': ('10', None, '19H1', None, 'preview build'),
'18361': ('10', None, '19H1', None, 'preview build'),
+ '18362': ('10', 'v1903', '19H1', 'May 2019 Update', None),
'18836': ('10', None, '20H1', None, 'preview build'),
'18841': ('10', None, '20H1', None, 'preview build'),
'18845': ('10', None, '20H1', None, 'preview build'),
'18850': ('10', None, '20H1', None, 'preview build'),
'18855': ('10', None, '20H1', None, 'preview build'),
+ '18860': ('10', None, '20H1', None, 'preview build'),
+ '18865': ('10', None, '20H1', None, 'preview build'),
+ '18875': ('10', None, '20H1', None, 'preview build'),
+ '18885': ('10', None, '20H1', None, 'preview build'),
+ '18890': ('10', None, '20H1', None, 'preview build'),
+ '18894': ('10', None, '20H1', None, 'preview build'),
+ '18895': ('10', None, '20H1', None, 'preview build'),
+ '18898': ('10', None, '20H1', None, 'preview build'),
}
if __name__ == '__main__':
print("This file is not meant to be called directly.")
-
-# vim: sts=2 sw=2 ts=2
diff --git a/.bin/Scripts/sfc_scan.py b/.bin/Scripts/sfc_scan.py
index 884694f5..ec85836a 100644
--- a/.bin/Scripts/sfc_scan.py
+++ b/.bin/Scripts/sfc_scan.py
@@ -32,8 +32,8 @@ if __name__ == '__main__':
print_standard('\nDone.')
pause('Press Enter to exit...')
exit_script()
- except SystemExit:
- pass
+ except SystemExit as sys_exit:
+ exit_script(sys_exit.code)
except:
major_exception()
diff --git a/.bin/Scripts/system_checklist.py b/.bin/Scripts/system_checklist.py
deleted file mode 100644
index 1088cf5d..00000000
--- a/.bin/Scripts/system_checklist.py
+++ /dev/null
@@ -1,160 +0,0 @@
-# Wizard Kit: System Checklist
-
-import os
-import sys
-
-# Init
-sys.path.append(os.path.dirname(os.path.realpath(__file__)))
-from functions.activation import *
-from functions.cleanup import *
-from functions.info import *
-from functions.product_keys import *
-from functions.setup import *
-from functions.sw_diags import *
-from functions.windows_updates import *
-init_global_vars()
-os.system('title {}: System Checklist Tool'.format(KIT_NAME_FULL))
-set_log_file('System Checklist.log')
-D7_MODE = 'd7mode' in sys.argv
-
-if __name__ == '__main__':
- try:
- stay_awake()
- clear_screen()
- print_info('{}: System Checklist Tool\n'.format(KIT_NAME_FULL))
- ticket_number = get_ticket_number()
- other_results = {
- 'Error': {
- 'BIOSKeyNotFoundError': 'BIOS key not found',
- 'CalledProcessError': 'Unknown Error',
- 'FileNotFoundError': 'File not found',
- 'GenericError': 'Unknown Error',
- 'SecureBootDisabledError': 'Disabled',
- },
- 'Warning': {
- 'OSInstalledLegacyError': 'OS installed Legacy',
- 'SecureBootNotAvailError': 'Not available',
- 'SecureBootUnknownError': 'Unknown',
- }}
- if ENABLED_TICKET_NUMBERS:
- print_info('Starting System Checklist for Ticket #{}\n'.format(
- ticket_number))
-
- # Configure
- print_info('Configure')
- if global_vars['OS']['Version'] == '10':
- try_and_print(message='Explorer...',
- function=config_explorer_system, cs='Done')
- try_and_print(message='Disabling telemetry...',
- function=disable_windows_telemetry, cs='Done')
- try_and_print(message='Enabling RegBack...',
- function=enable_regback, cs='Done')
- try_and_print(message='Windows Updates...',
- function=config_windows_updates, cs='Done')
- try_and_print(message='Enabling BSoD mini dumps...',
- function=enable_mini_dumps, cs='Done')
- try_and_print(message='Enabling System Restore...',
- function=enable_system_restore, cs='Done')
- try_and_print(message='Create System Restore point...',
- function=create_system_restore_point, cs='Done')
- try_and_print(message='Enabling Windows Updates...',
- function=enable_windows_updates, cs='Done', silent=True)
- try_and_print(message='Updating Clock...',
- function=update_clock, cs='Done')
-
- # Restart Explorer
- try_and_print(message='Restarting Explorer...',
- function=restart_explorer, cs='Done')
-
- # Cleanup
- print_info('Cleanup')
- try_and_print(message='AdwCleaner...',
- function=cleanup_adwcleaner, cs='Done', other_results=other_results)
- try_and_print(message='Desktop...',
- function=cleanup_desktop, cs='Done')
- try_and_print(message='Emsisoft a2cmd...',
- function=cleanup_emsisoft, cs='Done')
- try_and_print(message='Registry Backup(s)...',
- function=cleanup_regbackups, cs='Done')
- try_and_print(message='{}...'.format(KIT_NAME_FULL),
- function=delete_empty_folders, cs='Done',
- folder_path=global_vars['ClientDir'])
-
- # Export system info
- if not D7_MODE:
- print_info('Backup System Information')
- try_and_print(message='AIDA64 reports...',
- function=run_aida64, cs='Done', other_results=other_results)
- try_and_print(message='File listing...',
- function=backup_file_list, cs='Done', other_results=other_results)
- try_and_print(message='Power plans...',
- function=backup_power_plans, cs='Done')
- try_and_print(message='Product Keys...', other_results=other_results,
- function=run_produkey, cs='Done')
- try_and_print(message='Registry...',
- function=backup_registry, cs='Done', other_results=other_results)
-
- # User data
- print_info('User Data')
- show_user_data_summary()
-
- # Summary
- print_info('Summary')
- try_and_print(message='Operating System:',
- function=show_os_name, ns='Unknown', silent_function=False)
- try_and_print(message='Activation:',
- function=show_os_activation, ns='Unknown', silent_function=False)
- if (not windows_is_activated()
- and global_vars['OS']['Version'] in ('8', '8.1', '10')):
- try_and_print(message='BIOS Activation:',
- function=activate_with_bios,
- other_results=other_results)
- try_and_print(message='Secure Boot Status:',
- function=check_secure_boot_status, other_results=other_results)
- try_and_print(message='Installed RAM:',
- function=show_installed_ram, ns='Unknown', silent_function=False)
- show_free_space()
- try_and_print(message='Installed Antivirus:',
- function=get_installed_antivirus, ns='Unknown',
- other_results=other_results, print_return=True)
- try_and_print(message='Installed Office:',
- function=get_installed_office, ns='Unknown',
- other_results=other_results, print_return=True)
- if D7_MODE:
- try_and_print(message='Product Keys:',
- function=get_product_keys, ns='Unknown', print_return=True)
-
- # Play audio, show devices, open Windows updates, and open Activation
- try_and_print(message='Opening Device Manager...',
- function=open_device_manager, cs='Started')
- try_and_print(message='Opening HWiNFO (Sensors)...',
- function=run_hwinfo_sensors, cs='Started', other_results=other_results)
- try_and_print(message='Opening Windows Updates...',
- function=open_windows_updates, cs='Started')
- if not windows_is_activated():
- try_and_print(message='Opening Windows Activation...',
- function=open_windows_activation, cs='Started')
- sleep(3)
- try_and_print(message='Running XMPlay...',
- function=run_xmplay, cs='Started', other_results=other_results)
- try:
- check_secure_boot_status(show_alert=True)
- except Exception:
- # Only trying to open alert message boxes
- pass
-
- # Done
- print_standard('\nDone.')
- pause('Press Enter exit...')
- if D7_MODE:
- show_alert_box(
- message='Please run the Post-d7II script after ending the session.',
- title='{} Notice'.format(KIT_NAME_FULL),
- )
- exit_script()
- except SystemExit:
- pass
- except:
- major_exception()
-
-# vim: sts=2 sw=2 ts=2
diff --git a/.bin/Scripts/system_checklist_hw.py b/.bin/Scripts/system_checklist_hw.py
deleted file mode 100644
index 1edb0e96..00000000
--- a/.bin/Scripts/system_checklist_hw.py
+++ /dev/null
@@ -1,122 +0,0 @@
-# Wizard Kit: System HW Checklist
-
-import os
-import sys
-
-# Init
-sys.path.append(os.path.dirname(os.path.realpath(__file__)))
-from functions.activation import *
-from functions.cleanup import *
-from functions.info import *
-from functions.product_keys import *
-from functions.setup import *
-from functions.sw_diags import *
-init_global_vars()
-os.system('title {}: System HW Checklist Tool'.format(KIT_NAME_FULL))
-set_log_file('System HW Checklist.log')
-
-if __name__ == '__main__':
- try:
- stay_awake()
- clear_screen()
- print_info('{}: System HW Checklist Tool\n'.format(KIT_NAME_FULL))
- ticket_number = get_ticket_number()
- other_results = {
- 'Error': {
- 'BIOSKeyNotFoundError': 'BIOS key not found',
- 'CalledProcessError': 'Unknown Error',
- 'FileNotFoundError': 'File not found',
- 'GenericError': 'Unknown Error',
- 'SecureBootDisabledError': 'Disabled',
- },
- 'Warning': {
- 'OSInstalledLegacyError': 'OS installed Legacy',
- 'SecureBootNotAvailError': 'Not available',
- 'SecureBootUnknownError': 'Unknown',
- }}
- if ENABLED_TICKET_NUMBERS:
- print_info('Starting System Checklist for Ticket #{}\n'.format(
- ticket_number))
-
- # Configure
- print_info('Configure')
- if global_vars['OS']['Version'] == '10':
- try_and_print(message='Enabling RegBack...',
- function=enable_regback, cs='Done')
- try_and_print(message='Enabling BSoD mini dumps...',
- function=enable_mini_dumps, cs='Done')
- try_and_print(message='Enabling System Restore...',
- function=enable_system_restore, cs='Done')
- try_and_print(message='Create System Restore point...',
- function=create_system_restore_point, cs='Done')
-
- # Export system info
- print_info('Backup System Information')
- try_and_print(message='AIDA64 reports...',
- function=run_aida64, cs='Done', other_results=other_results)
- try_and_print(message='File listing...',
- function=backup_file_list, cs='Done', other_results=other_results)
- try_and_print(message='Power plans...',
- function=backup_power_plans, cs='Done')
- try_and_print(message='Product Keys...', other_results=other_results,
- function=run_produkey, cs='Done')
- try_and_print(message='Registry...',
- function=backup_registry, cs='Done', other_results=other_results)
-
- # Cleanup
- print_info('Cleanup')
- try_and_print(message='{}...'.format(KIT_NAME_FULL),
- function=delete_empty_folders, cs='Done',
- folder_path=global_vars['ClientDir'])
-
- # User data
- print_info('User Data')
- show_user_data_summary()
-
- # Summary
- print_info('Summary')
- try_and_print(message='Operating System:',
- function=show_os_name, ns='Unknown', silent_function=False)
- try_and_print(message='Activation:',
- function=show_os_activation, ns='Unknown', silent_function=False)
- try_and_print(message='Secure Boot Status:',
- function=check_secure_boot_status, other_results=other_results)
- try_and_print(message='Installed RAM:',
- function=show_installed_ram, ns='Unknown', silent_function=False)
- show_free_space()
- try_and_print(message='Installed Antivirus:',
- function=get_installed_antivirus, ns='Unknown',
- other_results=other_results, print_return=True)
- try_and_print(message='Installed Office:',
- function=get_installed_office, ns='Unknown',
- other_results=other_results, print_return=True)
-
- # Play audio, show devices, open Windows updates, and open Activation
- try_and_print(message='Opening Device Manager...',
- function=open_device_manager, cs='Started')
- try_and_print(message='Opening HWiNFO (Sensors)...',
- function=run_hwinfo_sensors, cs='Started', other_results=other_results)
- try_and_print(message='Opening Windows Updates...',
- function=open_windows_updates, cs='Started')
- if not windows_is_activated():
- try_and_print(message='Opening Windows Activation...',
- function=open_windows_activation, cs='Started')
- sleep(3)
- try_and_print(message='Running XMPlay...',
- function=run_xmplay, cs='Started', other_results=other_results)
- try:
- check_secure_boot_status(show_alert=True)
- except Exception:
- # Only trying to open alert message boxes
- pass
-
- # Done
- print_standard('\nDone.')
- pause('Press Enter exit...')
- exit_script()
- except SystemExit:
- pass
- except:
- major_exception()
-
-# vim: sts=2 sw=2 ts=2
diff --git a/.bin/Scripts/system_diagnostics.py b/.bin/Scripts/system_diagnostics.py
index 2e717ed5..74e92dd8 100644
--- a/.bin/Scripts/system_diagnostics.py
+++ b/.bin/Scripts/system_diagnostics.py
@@ -123,21 +123,22 @@ if __name__ == '__main__':
result = try_and_print(
message='CHKDSK ({SYSTEMDRIVE})...'.format(**global_vars['Env']),
function=run_chkdsk, other_results=other_results)
- system_ok &= check_result(result, other_results)
+ system_ok = system_ok and check_result(result, other_results)
result = try_and_print(message='SFC scan...',
function=run_sfc_scan, other_results=other_results)
- system_ok &= check_result(result, other_results)
+ system_ok = system_ok and check_result(result, other_results)
if D7_MODE:
result = try_and_print(message='DISM RestoreHealth...',
function=run_dism, other_results=other_results, repair=True)
if global_vars['OS']['Version'] in ('8', '8.1', '10'):
- system_ok &= check_result(result, other_results)
+ system_ok = system_ok and check_result(result, other_results)
else:
try_and_print(message='DISM CheckHealth...',
function=run_dism, other_results=other_results, repair=False)
if D7_MODE:
# Archive all browsers for all users
+ print_standard(' ')
archive_all_users()
else:
# Scan for supported browsers
@@ -149,24 +150,25 @@ if __name__ == '__main__':
for k, v in sorted(BLEACH_BIT_CLEANERS.items()):
try_and_print(message='{}...'.format(k),
function=run_bleachbit,
- cs='Done', other_results=other_results,
+ cs='SUCCESS', other_results=other_results,
cleaners=v, preview=bool(not D7_MODE))
+ print_standard(' ')
# Export system info
- print_info('Backup System Information')
- try_and_print(message='AIDA64 reports...',
- function=run_aida64, cs='Done', other_results=other_results)
if not D7_MODE:
+ print_info('Backup System Information')
+ try_and_print(message='AIDA64 reports...',
+ function=run_aida64, cs='SUCCESS', other_results=other_results)
backup_browsers()
- try_and_print(message='File listing...',
- function=backup_file_list, cs='Done', other_results=other_results)
- try_and_print(message='Power plans...',
- function=backup_power_plans, cs='Done')
- try_and_print(message='Product Keys...',
- function=run_produkey, cs='Done', other_results=other_results)
- try_and_print(message='Registry...',
- function=backup_registry, cs='Done', other_results=other_results,
- overwrite=True)
+ try_and_print(message='File listing...',
+ function=backup_file_list, cs='SUCCESS', other_results=other_results)
+ try_and_print(message='Power plans...',
+ function=backup_power_plans, cs='SUCCESS')
+ try_and_print(message='Product Keys...',
+ function=run_produkey, cs='SUCCESS', other_results=other_results)
+ try_and_print(message='Registry...',
+ function=backup_registry, cs='SUCCESS', other_results=other_results,
+ overwrite=True)
# Summary
if not D7_MODE:
@@ -202,8 +204,8 @@ if __name__ == '__main__':
print_standard('\nDone.')
pause('Press Enter to exit...')
exit_script()
- except SystemExit:
- pass
+ except SystemExit as sys_exit:
+ exit_script(sys_exit.code)
except:
major_exception()
diff --git a/.bin/Scripts/system_setup.py b/.bin/Scripts/system_setup.py
new file mode 100644
index 00000000..9e871f73
--- /dev/null
+++ b/.bin/Scripts/system_setup.py
@@ -0,0 +1,394 @@
+'''Wizard Kit: System Setup'''
+# pylint: disable=wildcard-import,wrong-import-position
+# vim: sts=2 sw=2 ts=2
+
+import os
+import sys
+
+# Init
+sys.path.append(os.path.dirname(os.path.realpath(__file__)))
+from collections import OrderedDict
+from functions.activation import *
+from functions.browsers import *
+from functions.cleanup import *
+from functions.info import *
+from functions.product_keys import *
+from functions.setup import *
+from functions.sw_diags import *
+from functions.windows_updates import *
+init_global_vars()
+os.system('title {}: System Setup'.format(KIT_NAME_FULL))
+set_log_file('System Setup.log')
+
+
+# STATIC VARIABLES
+# pylint: disable=bad-whitespace,line-too-long
+OTHER_RESULTS = {
+ 'Error': {
+ 'BIOSKeyNotFoundError': 'BIOS KEY NOT FOUND',
+ 'CalledProcessError': 'UNKNOWN ERROR',
+ 'FileNotFoundError': 'FILE NOT FOUND',
+ 'GenericError': 'UNKNOWN ERROR',
+ 'Not4KAlignedError': 'FALSE',
+ 'SecureBootDisabledError': 'DISABLED',
+ 'WindowsUnsupportedError': 'UNSUPPORTED',
+ },
+ 'Warning': {
+ 'GenericRepair': 'REPAIRED',
+ 'NoProfilesError': 'NO PROFILES FOUND',
+ 'NotInstalledError': 'NOT INSTALLED',
+ 'OSInstalledLegacyError': 'OS INSTALLED LEGACY',
+ 'SecureBootNotAvailError': 'NOT AVAILABLE',
+ 'SecureBootUnknownError': 'UNKNOWN',
+ 'UnsupportedOSError': 'UNSUPPORTED OS',
+ 'WindowsOutdatedError': 'OUTDATED',
+ },
+ }
+SETUP_ACTIONS = OrderedDict({
+ # Install software
+ 'Installing Programs': {'Info': True},
+ 'VCR': {'New': True, 'Fab': True, 'Cur': True, 'HW': False, 'Function': install_vcredists, 'Just run': True,},
+ 'ESET NOD32 AV': {'New': True, 'Fab': True, 'Cur': True, 'HW': False, 'Function': install_eset_nod32_av, 'If answer': 'ESET', 'KWArgs': {'msp': False},},
+ 'LibreOffice': {'New': True, 'Fab': True, 'Cur': True, 'HW': False, 'Function': install_libreoffice,
+ 'If answer': 'LibreOffice', 'KWArgs': {'quickstart': False, 'register_mso_types': True, 'use_mso_formats': True, 'vcredist': False},
+ },
+ 'Ninite bundle': {'New': True, 'Fab': True, 'Cur': True, 'HW': False, 'Function': install_ninite_bundle, 'KWArgs': {'cs': 'STARTED'},},
+
+ # Browsers
+ 'Scanning for browsers': {'Info': True},
+ 'Scan': {'New': True, 'Fab': True, 'Cur': True, 'HW': False, 'Function': scan_for_browsers, 'Just run': True, 'KWArgs': {'skip_ie': True},},
+ 'Backing up browsers': {'Info': True},
+ 'Backup browsers': {'New': False, 'Fab': True, 'Cur': True, 'HW': False, 'Function': backup_browsers, 'Just run': True,},
+
+ # Install extensions
+ 'Installing Extensions': {'Info': True},
+ 'Classic Shell skin': {'New': True, 'Fab': True, 'Cur': False, 'HW': False, 'Function': install_classicstart_skin, 'Win10 only': True,},
+ 'Chrome extensions': {'New': True, 'Fab': True, 'Cur': True, 'HW': False, 'Function': install_chrome_extensions,},
+ 'Firefox extensions': {'New': True, 'Fab': True, 'Cur': True, 'HW': False, 'Function': install_firefox_extensions,},
+
+ # Configure software'
+ 'Configuring Programs': {'Info': True},
+ 'Browser add-ons': {'New': True, 'Fab': True, 'Cur': True, 'HW': False, 'Function': install_adblock, 'Just run': True,
+ 'Pause': 'Please enable uBlock Origin for all browsers',
+ },
+ 'Classic Start': {'New': True, 'Fab': True, 'Cur': False, 'HW': False, 'Function': config_classicstart, 'Win10 only': True,},
+ 'Config Windows Updates': {'New': True, 'Fab': True, 'Cur': True, 'HW': True, 'Function': config_windows_updates, 'Win10 only': True,},
+ 'Enable System Restore': {'New': True, 'Fab': True, 'Cur': True, 'HW': True, 'Function': enable_system_restore,},
+ 'Create System Restore': {'New': True, 'Fab': True, 'Cur': True, 'HW': True, 'Function': create_system_restore_point,},
+ 'Disable Fast Startup': {'New': True, 'Fab': True, 'Cur': True, 'HW': False, 'Function': disable_fast_startup, 'If answer': 'Fast-Hiber', 'Win10 only': True,},
+ 'Disable telemetry': {'New': True, 'Fab': True, 'Cur': True, 'HW': False, 'Function': disable_windows_telemetry, 'Win10 only': True,},
+ 'Enable BSoD mini dumps': {'New': True, 'Fab': True, 'Cur': True, 'HW': True, 'Function': enable_mini_dumps,},
+ 'Enable Hibernation': {'New': True, 'Fab': True, 'Cur': True, 'HW': False, 'Function': enable_hibernation, 'If answer': 'Fast-Hiber', 'Win10 only': True,},
+ 'Enable RegBack': {'New': True, 'Fab': True, 'Cur': True, 'HW': True, 'Function': enable_regback, 'Win10 only': True,},
+ 'Enable Windows Updates': {'New': True, 'Fab': True, 'Cur': True, 'HW': True, 'Function': enable_windows_updates, 'KWArgs': {'silent': True},},
+ 'Explorer (system)': {'New': True, 'Fab': True, 'Cur': True, 'HW': False, 'Function': config_explorer_system, 'Win10 only': True,},
+ 'Explorer (user)': {'New': True, 'Fab': True, 'Cur': True, 'HW': False, 'Function': config_explorer_user, 'Win10 only': True,},
+ 'Restart Explorer': {'New': True, 'Fab': True, 'Cur': True, 'HW': False, 'Function': restart_explorer,},
+ 'Update Clock': {'New': True, 'Fab': True, 'Cur': True, 'HW': False, 'Function': update_clock,},
+
+ # Cleanup
+ 'Cleaning up': {'Info': True},
+ 'AdwCleaner': {'New': True, 'Fab': True, 'Cur': True, 'HW': False, 'Function': cleanup_adwcleaner,},
+ 'd7II': {'New': True, 'Fab': True, 'Cur': True, 'HW': False, 'Function': cleanup_d7ii,},
+ 'Desktop': {'New': True, 'Fab': True, 'Cur': True, 'HW': False, 'Function': cleanup_desktop,},
+ 'Emsisoft s2cmd': {'New': True, 'Fab': True, 'Cur': True, 'HW': False, 'Function': cleanup_emsisoft,},
+ 'Registry Backup(s)': {'New': True, 'Fab': True, 'Cur': True, 'HW': False, 'Function': cleanup_regbackups,},
+ 'KIT_NAME_FULL': {'New': True, 'Fab': True, 'Cur': True, 'HW': True, 'Function': delete_empty_folders,},
+
+ # System Info
+ 'Exporting system info': {'Info': True},
+ 'AIDA64 Report': {'New': True, 'Fab': True, 'Cur': True, 'HW': False, 'Function': run_aida64,},
+ 'File listing': {'New': True, 'Fab': True, 'Cur': True, 'HW': False, 'Function': backup_file_list,},
+ 'Power plans': {'New': True, 'Fab': True, 'Cur': True, 'HW': True, 'Function': backup_power_plans,},
+ 'Product Keys': {'New': True, 'Fab': True, 'Cur': True, 'HW': True, 'Function': run_produkey,},
+ 'Registry': {'New': True, 'Fab': True, 'Cur': True, 'HW': True, 'Function': backup_registry,},
+
+ # Show Summary
+ 'Summary': {'Info': True},
+ 'Operating System': {'New': True, 'Fab': True, 'Cur': True, 'HW': True, 'Function': show_os_name, 'KWArgs': {'ns': 'UNKNOWN', 'silent_function': False},},
+ 'Activation': {'New': True, 'Fab': True, 'Cur': True, 'HW': True, 'Function': show_os_activation, 'KWArgs': {'ns': 'UNKNOWN', 'silent_function': False},},
+ 'BIOS Activation': {'New': True, 'Fab': True, 'Cur': True, 'HW': False, 'Function': activate_with_bios, 'If not activated': True,},
+ 'Secure Boot': {'New': True, 'Fab': True, 'Cur': True, 'HW': True, 'Function': check_secure_boot_status, 'KWArgs': {'show_alert': False},},
+ 'Installed RAM': {'New': True, 'Fab': True, 'Cur': True, 'HW': True, 'Function': show_installed_ram, 'KWArgs': {'ns': 'UNKNOWN', 'silent_function': False},},
+ 'Temp size': {'New': False, 'Fab': False, 'Cur': True, 'HW': False, 'Function': show_temp_files_size, 'KWArgs': {'ns': 'UNKNOWN', 'silent_function': False},},
+ 'Show free space': {'New': True, 'Fab': True, 'Cur': True, 'HW': True, 'Function': show_free_space, 'Just run': True,},
+ 'Installed AV': {'New': True, 'Fab': True, 'Cur': True, 'HW': True, 'Function': get_installed_antivirus, 'KWArgs': {'ns': 'UNKNOWN', 'print_return': True},},
+ 'Installed Office': {'New': True, 'Fab': True, 'Cur': True, 'HW': False, 'Function': get_installed_office, 'KWArgs': {'ns': 'UNKNOWN', 'print_return': True},},
+ 'Partitions 4K aligned': {'New': True, 'Fab': True, 'Cur': True, 'HW': True, 'Function': check_4k_alignment, 'KWArgs': {'cs': 'TRUE', 'ns': 'FALSE'},},
+
+ # Open things
+ 'Opening Programs': {'Info': True},
+ 'Device Manager': {'New': True, 'Fab': True, 'Cur': True, 'HW': True, 'Function': open_device_manager, 'KWArgs': {'cs': 'STARTED'},},
+ 'HWiNFO sensors': {'New': True, 'Fab': True, 'Cur': True, 'HW': True, 'Function': run_hwinfo_sensors, 'KWArgs': {'cs': 'STARTED'},},
+ 'Snappy': {'New': True, 'Fab': True, 'Cur': True, 'HW': True, 'Function': open_snappy_driver_origin, 'KWArgs': {'cs': 'STARTED'},},
+ 'Speed test': {'New': True, 'Fab': True, 'Cur': True, 'HW': True, 'Function': open_speedtest, 'KWArgs': {'cs': 'STARTED'},},
+ 'Windows Updates': {'New': True, 'Fab': True, 'Cur': True, 'HW': False, 'Function': open_windows_updates, 'KWArgs': {'cs': 'STARTED'},},
+ 'Windows Activation': {'New': True, 'Fab': True, 'Cur': True, 'HW': False, 'Function': open_windows_activation, 'If not activated': True, 'KWArgs': {'cs': 'STARTED'},},
+ 'Sleep': {'New': True, 'Fab': True, 'Cur': True, 'HW': True, 'Function': sleep, 'Just run': True, 'KWArgs': {'seconds': 3},},
+ 'XMPlay': {'New': True, 'Fab': True, 'Cur': True, 'HW': True, 'Function': run_xmplay, 'KWArgs': {'cs': 'STARTED'},},
+ })
+SETUP_ACTION_KEYS = (
+ 'Function',
+ 'If not activated',
+ 'Info',
+ 'Just run',
+ 'KWArgs',
+ 'Pause',
+ )
+SETUP_QUESTIONS = {
+ # AV
+ 'ESET': {'New': None, 'Fab': None, 'Cur': None, 'HW': False},
+ 'MSE': {'New': None, 'Fab': None, 'Cur': None, 'HW': False, 'Ninite': True},
+
+ # Fast Startup / Hibernation
+ 'Fast-Hiber': {'New': None, 'Fab': None, 'Cur': None, 'HW': False},
+
+ # LibreOffice
+ 'LibreOffice': {'New': None, 'Fab': None, 'Cur': None, 'HW': False, 'Ninite': True},
+
+ # Ninite
+ 'Base': {'New': True, 'Fab': True, 'Cur': True, 'HW': False, 'Ninite': True},
+ 'Missing': {'New': False, 'Fab': True, 'Cur': False, 'HW': False, 'Ninite': True},
+ 'Standard': {'New': True, 'Fab': True, 'Cur': False, 'HW': False, 'Ninite': True},
+ }
+# pylint: enable=bad-whitespace,line-too-long
+
+
+# Functions
+def check_os_and_abort():
+ """Check OS and prompt to abort if not supported."""
+ result = try_and_print(
+ message='OS support status...',
+ function=check_os_support_status,
+ cs='GOOD',
+ )
+ if not result['CS'] and 'Unsupported' in result['Error']:
+ print_warning('OS version not supported by this script')
+ if not ask('Continue anyway? (NOT RECOMMENDED)'):
+ abort()
+
+
+def get_actions(setup_mode, answers):
+ """Get actions to perform based on setup_mode, returns OrderedDict."""
+ actions = OrderedDict({})
+ for _key, _val in SETUP_ACTIONS.items():
+ _action = {}
+ _if_answer = _val.get('If answer', False)
+ _win10_only = _val.get('Win10 only', False)
+
+ # Set enabled status
+ _enabled = _val.get(setup_mode, False)
+ if _if_answer:
+ _enabled = _enabled and answers[_if_answer]
+ if _win10_only:
+ _enabled = _enabled and global_vars['OS']['Version'] == '10'
+ _action['Enabled'] = _enabled
+
+ # Set other keys
+ for _sub_key in SETUP_ACTION_KEYS:
+ _action[_sub_key] = _val.get(_sub_key, None)
+
+ # Fix KWArgs
+ if _action.get('KWArgs', {}) is None:
+ _action['KWArgs'] = {}
+
+ # Handle "special" actions
+ if _key == 'KIT_NAME_FULL':
+ # Cleanup WK folders
+ _key = KIT_NAME_FULL
+ _action['KWArgs'] = {'folder_path': global_vars['ClientDir']}
+ elif _key == 'Ninite bundle':
+ # Add install_ninite_bundle() kwargs
+ _action['KWArgs'].update({
+ kw.lower(): kv for kw, kv in answers.items()
+ if SETUP_QUESTIONS.get(kw, {}).get('Ninite', False)
+ })
+ elif _key == 'Explorer (user)':
+ # Explorer settings (user)
+ _action['KWArgs'] = {'setup_mode': setup_mode}
+
+ # Add to dict
+ actions[_key] = _action
+
+ return actions
+
+
+def get_answers(setup_mode):
+ """Get setup answers based on setup_mode and user input, returns dict."""
+ answers = {k: v.get(setup_mode, False) for k, v in SETUP_QUESTIONS.items()}
+
+ # Answer setup questions as needed
+ if answers['ESET'] is None or answers['MSE'] is None:
+ answers.update(get_av_selection())
+
+ if answers['LibreOffice'] is None:
+ answers['LibreOffice'] = ask('Install LibreOffice?')
+
+ if answers['Fast-Hiber'] is None:
+ if global_vars['OS']['Version'] == '10':
+ # SSD check
+ if drive_is_rotational(global_vars['Env']['SYSTEMDRIVE']):
+ answers['Fast-Hiber'] = True
+ else:
+ print_standard(' ')
+ print_standard('Disable Fast Startup and enable Hibernation?')
+ print_standard(' Recommended for SSDs, optional for HDDs')
+ answers['Fast-Hiber'] = ask(' Proceed?')
+ else:
+ answers['Fast-Hiber'] = False
+
+ return answers
+
+
+def get_av_selection():
+ """Get AV selection."""
+ av_answers = {
+ 'ESET': False,
+ 'MSE': False,
+ }
+ av_options = [
+ {'Name': 'ESET NOD32 AV'},
+ {
+ 'Name': 'Microsoft Security Essentials',
+ 'Disabled': global_vars['OS']['Version'] not in ['7'],
+ },
+ ]
+ actions = [
+ {'Name': 'None', 'Letter': 'N'},
+ {'Name': 'Quit', 'Letter': 'Q'},
+ ]
+
+ # Show menu
+ selection = menu_select(
+ 'Please select an option to install',
+ main_entries=av_options,
+ action_entries=actions)
+ if selection.isnumeric():
+ index = int(selection) - 1
+ if 'ESET' in av_options[index]['Name']:
+ av_answers['ESET'] = True
+ av_answers['MSE'] = False
+ elif 'Microsoft' in av_options[index]['Name']:
+ av_answers['ESET'] = False
+ av_answers['MSE'] = True
+ elif selection == 'Q':
+ abort()
+
+ # ESET settings
+ if av_answers['ESET'] and ask(' Use MSP settings (ITS/VIP)?'):
+ # NOTE: There's probably a better way than updating a static var...
+ SETUP_ACTIONS['ESET NOD32 AV']['KWArgs']['msp'] = True
+
+ return av_answers
+
+
+def get_mode():
+ """Get mode via menu_select, returns str."""
+ setup_mode = None
+ mode_options = [
+ {'Name': 'New', 'Display Name': 'New / Clean install (no data)'},
+ {'Name': 'Fab', 'Display Name': 'Clean install with data migration'},
+ {'Name': 'Cur', 'Display Name': 'Original OS (post-d7II or overinstall)'},
+ {'Name': 'HW', 'Display Name': 'Hardware service (i.e. no software work)'},
+ ]
+ actions = [
+ {'Name': 'Quit', 'Letter': 'Q'},
+ ]
+
+ # Get selection
+ selection = menu_select(
+ 'Please select a setup mode',
+ main_entries=mode_options,
+ action_entries=actions)
+ if selection.isnumeric():
+ index = int(selection) - 1
+ setup_mode = mode_options[index]['Name']
+ elif selection == 'Q':
+ abort()
+
+ return setup_mode
+
+
+def main():
+ """Main function."""
+ stay_awake()
+ clear_screen()
+
+ # Check installed OS
+ check_os_and_abort()
+
+ # Get setup mode
+ setup_mode = get_mode()
+
+ # Get answers to setup questions
+ answers = get_answers(setup_mode)
+
+ # Get actions to perform
+ actions = get_actions(setup_mode, answers)
+
+ # Perform actions
+ for action, values in actions.items():
+ kwargs = values.get('KWArgs', {})
+
+ # Print info lines
+ if values.get('Info', False):
+ print_info(action)
+ continue
+
+ # Print disabled actions
+ if not values.get('Enabled', False):
+ show_data(
+ message='{}...'.format(action),
+ data='DISABLED',
+ warning=True,
+ )
+ continue
+
+ # Check Windows activation if requested
+ if values.get('If not activated', False) and windows_is_activated():
+ # Skip
+ continue
+
+ # Run function
+ if values.get('Just run', False):
+ values['Function'](**kwargs)
+ else:
+ result = try_and_print(
+ message='{}...'.format(action),
+ function=values['Function'],
+ other_results=OTHER_RESULTS,
+ **kwargs)
+
+ # Wait for Ninite proc(s)
+ if action == 'Ninite bundle':
+ print_standard('Waiting for installations to finish...')
+ try:
+ for proc in result['Out']:
+ proc.wait()
+ except KeyboardInterrupt:
+ pass
+
+ # Pause
+ if values.get('Pause', False):
+ print_standard(values['Pause'])
+ pause()
+
+ # Show alert box for SecureBoot issues
+ try:
+ check_secure_boot_status(show_alert=True)
+ except Exception: # pylint: disable=broad-except
+ # Ignoring exceptions since we just want to show the popup
+ pass
+
+ # Done
+ pause('Press Enter to exit... ')
+
+
+if __name__ == '__main__':
+ try:
+ main()
+ exit_script()
+ except SystemExit as sys_exit:
+ exit_script(sys_exit.code)
+ except: # pylint: disable=bare-except
+ major_exception()
diff --git a/.bin/Scripts/transferred_keys.py b/.bin/Scripts/transferred_keys.py
index 6dab114d..216f2046 100644
--- a/.bin/Scripts/transferred_keys.py
+++ b/.bin/Scripts/transferred_keys.py
@@ -21,8 +21,8 @@ if __name__ == '__main__':
# Done
print_standard('\nDone.')
exit_script()
- except SystemExit:
- pass
+ except SystemExit as sys_exit:
+ exit_script(sys_exit.code)
except:
major_exception()
diff --git a/.bin/Scripts/update_kit.py b/.bin/Scripts/update_kit.py
index 13520d5c..086535a4 100644
--- a/.bin/Scripts/update_kit.py
+++ b/.bin/Scripts/update_kit.py
@@ -60,6 +60,8 @@ if __name__ == '__main__':
print_info(' Installers')
try_and_print(message='Adobe Reader DC...', function=update_adobe_reader_dc, other_results=other_results, width=40)
try_and_print(message='ESET Configs...', function=update_eset_config, other_results=other_results, width=40)
+ try_and_print(message='ESET NOD32...', function=update_eset_nod32, other_results=other_results, width=40)
+ try_and_print(message='LibreOffice...', function=update_libreoffice, other_results=other_results, width=40)
try_and_print(message='Macs Fan Control...', function=update_macs_fan_control, other_results=other_results, width=40)
try_and_print(message='MS Office...', function=update_office, other_results=other_results, width=40)
try_and_print(message='Visual C++ Runtimes...', function=update_vcredists, other_results=other_results, width=40)
@@ -75,6 +77,7 @@ if __name__ == '__main__':
try_and_print(message='Firefox Extensions...', function=update_firefox_ublock_origin, other_results=other_results, width=40)
try_and_print(message='PuTTY...', function=update_putty, other_results=other_results, width=40)
try_and_print(message='ShutUp10...', function=update_shutup10, other_results=other_results, width=40)
+ try_and_print(message='smartmontools...', function=update_smartmontools, other_results=other_results, width=40)
try_and_print(message='Notepad++...', function=update_notepadplusplus, other_results=other_results, width=40)
try_and_print(message='WizTree...', function=update_wiztree, other_results=other_results, width=40)
try_and_print(message='XMPlay...', function=update_xmplay, other_results=other_results, width=40)
@@ -126,22 +129,12 @@ if __name__ == '__main__':
section=section, name=name, options=options,
other_results=other_results, width=40)
- # Rename "Copy WizardKit.cmd" (if necessary)
- source = r'{}\Scripts\Copy WizardKit.cmd'.format(global_vars['BinDir'])
- dest = r'{}\Copy {}.cmd'.format(global_vars['BaseDir'], KIT_NAME_FULL)
- if os.path.exists(source):
- try:
- shutil.move(source, dest)
- except Exception:
- print_error(' Failed to rename "{}.cmd" to "{}.cmd"'.format(
- 'Copy WizardKit', KIT_NAME_FULL))
-
# Done
print_standard('\nDone.')
pause("Press Enter to exit...")
exit_script()
- except SystemExit:
- pass
+ except SystemExit as sys_exit:
+ exit_script(sys_exit.code)
except:
major_exception()
diff --git a/.bin/Scripts/user_checklist.py b/.bin/Scripts/user_checklist.py
deleted file mode 100644
index 30a78730..00000000
--- a/.bin/Scripts/user_checklist.py
+++ /dev/null
@@ -1,101 +0,0 @@
-# Wizard Kit: User Checklist
-
-import os
-import sys
-
-# Init
-sys.path.append(os.path.dirname(os.path.realpath(__file__)))
-from functions.browsers import *
-from functions.cleanup import *
-from functions.setup import *
-init_global_vars()
-os.system('title {}: User Checklist Tool'.format(KIT_NAME_FULL))
-set_log_file('User Checklist ({USERNAME}).log'.format(**global_vars['Env']))
-D7_MODE = 'd7mode' in sys.argv
-
-if __name__ == '__main__':
- try:
- stay_awake()
- clear_screen()
- print_info('{}: User Checklist\n'.format(KIT_NAME_FULL))
- other_results = {
- 'Warning': {
- 'NotInstalledError': 'Not installed',
- 'NoProfilesError': 'No profiles found',
- }}
- #answer_config_browsers = ask('Install adblock?')
- answer_config_browsers = True
- if answer_config_browsers:
- if D7_MODE:
- # This is handled by another script option in d7ii
- answer_reset_browsers = False
- else:
- answer_reset_browsers = ask(
- 'Reset browsers to safe defaults first?')
- if global_vars['OS']['Version'] == '10':
- answer_config_classicshell = True
- answer_config_explorer_user = True
-
- # Cleanup
- print_info('Cleanup')
- try_and_print(message='Desktop...',
- function=cleanup_desktop, cs='Done')
-
- # Scan for supported browsers
- print_info('Scanning for browsers')
- scan_for_browsers(skip_ie=True)
-
- # Homepages
- if not D7_MODE:
- print_info('Current homepages')
- list_homepages()
-
- # Backup
- if not D7_MODE:
- # Done during system_diagnostics
- print_info('Backing up browsers')
- backup_browsers()
-
- # Reset
- if answer_config_browsers and answer_reset_browsers:
- print_info('Resetting browsers')
- reset_browsers()
-
- # Configure
- print_info('Configuring programs')
- if answer_config_browsers:
- install_adblock()
- if global_vars['OS']['Version'] == '10':
- if answer_config_classicshell:
- try_and_print(message='ClassicStart...',
- function=config_classicstart, cs='Done')
- if answer_config_explorer_user:
- try_and_print(message='Explorer...',
- function=config_explorer_user, cs='Done')
- if (not answer_config_browsers
- and not answer_config_classicshell
- and not answer_config_explorer_user):
- print_warning(' Skipped')
- else:
- if not answer_config_browsers:
- print_warning(' Skipped')
-
- # Restart Explorer
- try_and_print(message='Restarting Explorer...',
- function=restart_explorer, cs='Done')
-
- # Run speedtest
- if not D7_MODE:
- popen_program(['start', '', 'https://fast.com'], shell=True)
-
- # Done
- if not D7_MODE:
- print_standard('\nDone.')
- pause('Press Enter to exit...')
- exit_script()
- except SystemExit:
- pass
- except:
- major_exception()
-
-# vim: sts=2 sw=2 ts=2
diff --git a/.bin/Scripts/user_data_transfer.py b/.bin/Scripts/user_data_transfer.py
index e63e0d7d..60b3c464 100644
--- a/.bin/Scripts/user_data_transfer.py
+++ b/.bin/Scripts/user_data_transfer.py
@@ -59,8 +59,8 @@ if __name__ == '__main__':
print_standard('\nDone.')
pause("Press Enter to exit...")
exit_script()
- except SystemExit:
- pass
+ except SystemExit as sys_exit:
+ exit_script(sys_exit.code)
except:
major_exception()
diff --git a/.bin/Scripts/windows_updates.py b/.bin/Scripts/windows_updates.py
index a9856cd0..9332e706 100644
--- a/.bin/Scripts/windows_updates.py
+++ b/.bin/Scripts/windows_updates.py
@@ -43,8 +43,8 @@ if __name__ == '__main__':
print_standard('Please reboot and try again.')
pause('Press Enter to exit... ')
exit_script(1)
- except SystemExit:
- pass
+ except SystemExit as sys_exit:
+ exit_script(sys_exit.code)
except:
major_exception()
diff --git a/.bin/Scripts/winpe_root_menu.py b/.bin/Scripts/winpe_root_menu.py
index a9555e07..94669609 100644
--- a/.bin/Scripts/winpe_root_menu.py
+++ b/.bin/Scripts/winpe_root_menu.py
@@ -15,8 +15,8 @@ set_log_file('WinPE.log')
if __name__ == '__main__':
try:
menu_root()
- except SystemExit:
- pass
+ except SystemExit as sys_exit:
+ exit_script(sys_exit.code)
except:
major_exception()
diff --git a/.bin/_Drivers/SDIO/sdi.cfg b/.bin/_Drivers/SDIO/sdi.cfg
index d1bd67fb..45b0e7c2 100644
--- a/.bin/_Drivers/SDIO/sdi.cfg
+++ b/.bin/_Drivers/SDIO/sdi.cfg
@@ -21,4 +21,4 @@
-uplimit:1
-connections:0
--expertmode -norestorepnt -showdrpnames2 -onlyupdates -preservecfg -novirusalerts
\ No newline at end of file
+-expertmode -showdrpnames2 -onlyupdates -preservecfg -novirusalerts
diff --git a/.bin/d7ii/3rd Party Tools/Python_Check.cmd b/.bin/d7ii/3rd Party Tools/Python_Check.cmd
new file mode 100644
index 00000000..aa4e7394
--- /dev/null
+++ b/.bin/d7ii/3rd Party Tools/Python_Check.cmd
@@ -0,0 +1,30 @@
+:: Python compatibility check
+@echo off
+
+setlocal
+pushd "%~dp0\..\.."
+set "bin=%cd%"
+set "python=%bin%\Python\x32\python.exe"
+
+rem Verify Python can run
+"%python%" --version >nul || goto ErrorPythonUnsupported
+goto Done
+
+:ErrorPythonUnsupported
+rem The Windows installation lacks Windows update KB2999226 needed to run Python
+echo.
+echo ERROR: Failed to run Python, try installing Windows update KB2999226.
+echo NOTE: That update is from October 2015 so this system is SEVERELY outdated
+echo.
+echo Please stop Auto Mode, exit this script, install the update, and try again.
+echo.
+echo Press Enter to exit...
+pause>nul
+if exist "%bin%\..\Installers\Extras\Windows Updates" (
+ start "" "explorer.exe"
+ start "" "explorer.exe" "%bin%\..\Installers\Extras\Windows Updates"
+)
+
+:Done
+popd
+endlocal
diff --git a/.bin/d7ii/Config/AltText.ini b/.bin/d7ii/Config/AltText.ini
index b58b6c23..0ce2c640 100644
--- a/.bin/d7ii/Config/AltText.ini
+++ b/.bin/d7ii/Config/AltText.ini
@@ -5,7 +5,7 @@ Autoruns (Verify and Log)=Manages Startup Items
Google Chrome Software Removal Tool=Remove add-ons, extensions, toolbars, and other software that may interfere with the operation of Google Chrome.
VipreRescueScanner (Deep Scan)=Virus scanner (Designed for both the Malware Removal and the Offline Operations tab)
VipreRescueScanner (Quick Scan)=Virus scanner (Designed for both the Malware Removal and the Offline Operations tab)
-=Install/Upgrade MBAM
+=Python Check
[ReportDesc]
Autoruns=Examined Windows startup items and removed unnecessary entries.
Autoruns_Copy=Examined Windows startup items and removed unnecessary entries.
@@ -36,4 +36,4 @@ VipreRescueScanner (Quick Scan)=Ran virus scans (Vipre)
22=Repaired the Windows Update services responsible for Windows Update functionality.
38=Performed repair routines to ensure the Winsock is operating properly.
83=Examined internet speed/bandwidth.
-=Malwarebytes installed successfully.
+=Python compatibility check
diff --git a/.bin/d7ii/Config/CustomApps/Disable Windows Updates.cfg b/.bin/d7ii/Config/CustomApps/Disable Windows Updates.cfg
index 8b47cecc..6d110bb5 100644
--- a/.bin/d7ii/Config/CustomApps/Disable Windows Updates.cfg
+++ b/.bin/d7ii/Config/CustomApps/Disable Windows Updates.cfg
@@ -1,5 +1,5 @@
[Config]
-LastEditDate=8/30/2018 10:49:46 AM
+LastEditDate=5/6/2019 6:09:55 PM
PostRunApp=
AppParms=.bin\Scripts\launchers_for_d7\Disable Windows Updates.cmd
UseFTPServer=0
@@ -9,7 +9,7 @@ AppWait=1
EmailBeforeExecution=0
PriorAlert=0
ServiceWait=0
-AppMsgBox=1
+AppMsgBox=0
AppRandomize=0
SaveConfigAfter=0
MoveSnatchReports=0
diff --git a/.bin/d7ii/Config/CustomApps/Python Check.cfg b/.bin/d7ii/Config/CustomApps/Python Check.cfg
new file mode 100644
index 00000000..5b12c7a5
--- /dev/null
+++ b/.bin/d7ii/Config/CustomApps/Python Check.cfg
@@ -0,0 +1,32 @@
+[Config]
+LastEditDate=5/6/2019 6:48:27 PM
+PostRunApp=
+AppDesc=Python Check
+App=Python_Check.cmd
+UseFTPServer=0
+AlwaysAttemptDownload=0
+DLafterXdays=5
+AppWait=0
+EmailBeforeExecution=0
+PriorAlert=0
+ServiceWait=0
+AppMsgBox=0
+AppWaitTime=30
+AppRandomize=0
+SaveConfigAfter=0
+MoveSnatchReports=0
+SnatchReportsToMalwareLogs=1
+RunInCMD=0
+SendEnter=0
+RunWithSystemAccess=0
+IsDLInstaller=0
+LogVerbiage=Python compatibility check
+32=1
+64=1
+XP=1
+Vista=1
+7=1
+8=1
+Servers=1
+NonDirectURLs=0
+AutoFlag=0
diff --git a/.bin/d7ii/Config/Profiles/Default.cfg b/.bin/d7ii/Config/Profiles/Default.cfg
index 161e77e5..ba51d4e8 100644
--- a/.bin/d7ii/Config/Profiles/Default.cfg
+++ b/.bin/d7ii/Config/Profiles/Default.cfg
@@ -782,6 +782,7 @@ WizardKit System Diagnostics=1
1=1
RKill (Auto)=1
Disable Windows Updates=1
+Python Check=1
[Malware3]
ComboFix=0
ComboFix (Uninstall)=0
diff --git a/.bin/d7ii/Config/SortOrder/MalwareBox2.cfg b/.bin/d7ii/Config/SortOrder/MalwareBox2.cfg
index 3ef28f76..f26c90a5 100644
--- a/.bin/d7ii/Config/SortOrder/MalwareBox2.cfg
+++ b/.bin/d7ii/Config/SortOrder/MalwareBox2.cfg
@@ -1 +1 @@
-Disable Windows Updates|98|RKill (Auto)|Kaspersky TDSSKiller (Silent)|WizardKit System Diagnostics|34|Emsisoft a2cmd Deep Scan|HitmanPro|1|98|
+Python Check|Disable Windows Updates|98|RKill (Auto)|Kaspersky TDSSKiller (Silent)|WizardKit System Diagnostics|34|Emsisoft a2cmd Deep Scan|HitmanPro|1|98|
diff --git a/.bin/d7ii/Config/SortOrder/MalwareBox3.cfg b/.bin/d7ii/Config/SortOrder/MalwareBox3.cfg
index 75da8a9d..72196949 100644
--- a/.bin/d7ii/Config/SortOrder/MalwareBox3.cfg
+++ b/.bin/d7ii/Config/SortOrder/MalwareBox3.cfg
@@ -1 +1 @@
-Malwarebytes Download|Malwarebytes Install|Malwarebytes Scan|Malwarebytes Uninstall|AdwCleaner (Updated)|IObit Uninstaller|Install SW Bundle|WizardKit Browser Reset|WizardKit User Checklist|WizardKit System Checklist|Bitdefender Rootkit Remover|
+Malwarebytes Download|Malwarebytes Install|Malwarebytes Scan|Malwarebytes Uninstall|AdwCleaner (Updated)|IObit Uninstaller|Bitdefender Rootkit Remover|
diff --git a/.cbin/_include/AIDA64/full.rpf b/.cbin/_include/AIDA64/full.rpf
index 28baab65..8d7df2ad 100644
--- a/.cbin/_include/AIDA64/full.rpf
+++ b/.cbin/_include/AIDA64/full.rpf
@@ -92,7 +92,6 @@ InfoPage="Config;Control Panel"
InfoPage="Config;Recycle Bin"
InfoPage="Config;System Files"
InfoPage="Config;System Folders"
-InfoPage="Config;Event Logs"
InfoPage="Database;Database Software"
InfoPage="Database;BDE Drivers"
InfoPage="Database;ODBC Drivers"
diff --git a/.cbin/_include/ESETConfigs/eset-config-no-pup.xml b/.cbin/_include/ESETConfigs/eset-config-msp.xml
similarity index 90%
rename from .cbin/_include/ESETConfigs/eset-config-no-pup.xml
rename to .cbin/_include/ESETConfigs/eset-config-msp.xml
index ac4e010e..36d01521 100644
--- a/.cbin/_include/ESETConfigs/eset-config-no-pup.xml
+++ b/.cbin/_include/ESETConfigs/eset-config-msp.xml
@@ -1,6 +1,31 @@
-
+
+ -
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
@@ -11,7 +36,7 @@
-
+
@@ -125,6 +150,10 @@
+ -
+
+
+
-
@@ -145,10 +174,6 @@
- -
-
-
-
-
@@ -238,6 +263,7 @@
+
@@ -255,11 +281,19 @@
- -
+
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+ -
+
-
+
-
@@ -269,10 +303,10 @@
-
-
-
-
+
+
+
+
@@ -335,6 +369,9 @@
-
+
-
+
+
-
@@ -394,28 +431,7 @@
- -
-
-
-
-
-
- -
-
-
-
- -
-
-
-
- -
-
-
-
- -
-
-
-
-
+
-
@@ -471,7 +487,6 @@
-
-
@@ -507,59 +522,23 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
-
-
+
@@ -568,24 +547,10 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
@@ -642,7 +607,7 @@
-
+
@@ -669,28 +634,6 @@
- -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
@@ -729,14 +672,9 @@
-
-
+
- -
-
-
-
-
-
@@ -768,6 +706,7 @@
-
-
+
@@ -784,14 +723,14 @@
-
-
-
-
-
-
+
+
+
-
-
-
-
+
+
+
-
@@ -942,7 +881,7 @@
-
+
@@ -1462,7 +1401,7 @@
-
+
@@ -1633,36 +1572,6 @@
- -
-
-
-
-
-
- -
-
-
-
- -
-
-
-
- -
-
-
-
- -
-
-
-
- -
-
-
-
- -
-
-
-
-
diff --git a/.cbin/_include/ESETConfigs/eset-config.xml b/.cbin/_include/ESETConfigs/eset-config.xml
index 31804d40..772c6a03 100644
--- a/.cbin/_include/ESETConfigs/eset-config.xml
+++ b/.cbin/_include/ESETConfigs/eset-config.xml
@@ -1,6 +1,31 @@
-
+
+ -
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
@@ -11,7 +36,7 @@
-
+
@@ -125,6 +150,10 @@
+ -
+
+
+
-
@@ -145,10 +174,6 @@
- -
-
-
-
-
@@ -238,6 +263,7 @@
+
@@ -255,11 +281,19 @@
- -
+
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+ -
+
-
+
-
@@ -269,10 +303,10 @@
-
-
-
-
+
+
+
+
@@ -335,6 +369,9 @@
-
+
-
+
+
-
@@ -394,28 +431,7 @@
- -
-
-
-
-
-
- -
-
-
-
- -
-
-
-
- -
-
-
-
- -
-
-
-
-
+
-
@@ -471,7 +487,6 @@
-
-
@@ -507,59 +522,23 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
-
-
+
@@ -568,24 +547,10 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
@@ -596,8 +561,8 @@
-
-
+
+
@@ -669,28 +634,6 @@
- -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
@@ -732,11 +675,6 @@
- -
-
-
-
-
-
@@ -768,6 +706,7 @@
-
-
+
@@ -784,14 +723,14 @@
-
-
-
-
-
-
+
+
+
-
-
-
-
+
+
+
-
@@ -942,7 +881,7 @@
-
+
@@ -1462,7 +1401,7 @@
-
+
@@ -1633,36 +1572,6 @@
- -
-
-
-
-
-
- -
-
-
-
- -
-
-
-
- -
-
-
-
- -
-
-
-
- -
-
-
-
- -
-
-
-
-
diff --git a/.linux_items/include/EFI/boot/icons/1201_mac-dgpu.png b/.linux_items/include/EFI/boot/icons/dgpu.png
similarity index 100%
rename from .linux_items/include/EFI/boot/icons/1201_mac-dgpu.png
rename to .linux_items/include/EFI/boot/icons/dgpu.png
diff --git a/.linux_items/include/EFI/boot/refind.conf b/.linux_items/include/EFI/boot/refind.conf
index e7dcbfb6..34a638c1 100644
--- a/.linux_items/include/EFI/boot/refind.conf
+++ b/.linux_items/include/EFI/boot/refind.conf
@@ -19,6 +19,7 @@ menuentry "MemTest86" {
icon /EFI/boot/icons/wk_memtest.png
loader /EFI/memtest86/memtestx64.efi
}
+
menuentry "Linux" {
icon /EFI/boot/icons/wk_arch.png
loader /arch/boot/x86_64/vmlinuz
@@ -26,30 +27,42 @@ menuentry "Linux" {
initrd /arch/boot/amd_ucode.img
initrd /arch/boot/x86_64/archiso.img
options "archisobasedir=arch archisolabel=%ARCHISO_LABEL% copytoram loglevel=3"
- submenuentry "Linux (i3)" {
- add_options "i3"
- }
submenuentry "Linux (CLI)" {
- add_options "loglevel=4 nomodeset nox"
+ add_options "nox"
}
+ #UFD-MINIMAL#submenuentry "Linux (Minimal)" {
+ #UFD-MINIMAL# loader /arch_minimal/vmlinuz
+ #UFD-MINIMAL# initrd
+ #UFD-MINIMAL# initrd /arch/boot/intel_ucode.img
+ #UFD-MINIMAL# initrd /arch/boot/amd_ucode.img
+ #UFD-MINIMAL# initrd /arch_minimal/archiso.img
+ #UFD-MINIMAL# options
+ #UFD-MINIMAL# options "archisobasedir=arch_minimal archisolabel=%ARCHISO_LABEL% copytoram loglevel=3"
+ #UFD-MINIMAL#}
}
+
#UFD-WINPE#menuentry "WindowsPE" {
#UFD-WINPE# ostype windows
#UFD-WINPE# icon /EFI/boot/icons/wk_win.png
#UFD-WINPE# loader /EFI/microsoft/bootx64.efi
#UFD-WINPE#}
-#UFD#menuentry "ESET SysRescue Live" {
-#UFD# icon /EFI/boot/icons/1201_eset.png
-#UFD# loader /EFI/ESET/grubx64.efi
-#UFD#}
-#UFD#menuentry "HDClone" {
-#UFD# icon /EFI/boot/icons/1201_hdclone.png
-#UFD# loader /EFI/HDClone/bootx64.efi
-#UFD#}
-#UFD#menuentry "Mac dGPU Disable Tool" {
-#UFD# icon /EFI/boot/icons/1201_mac-dgpu.png
-#UFD# loader /dgpu/boot/x86_64/vmlinuz
-#UFD# initrd /dgpu/boot/intel_ucode.img
-#UFD# initrd /dgpu/boot/x86_64/archiso.img
-#UFD# options "archisobasedir=dgpu archisolabel=1201_UFD nomodeset"
-#UFD#}
+
+#UFD-ESET#menuentry "ESET SysRescue Live" {
+#UFD-ESET# icon /EFI/boot/icons/1201_eset.png
+#UFD-ESET# loader /EFI/ESET/grubx64.efi
+#UFD-ESET#}
+
+#UFD-HDCLONE#menuentry "HDClone" {
+#UFD-HDCLONE# icon /EFI/boot/icons/1201_hdclone.png
+#UFD-HDCLONE# loader /EFI/HDClone/bootx64.efi
+#UFD-HDCLONE#}
+
+#UFD-DGPU#menuentry "Mac dGPU Disable Tool" {
+#UFD-DGPU# icon /EFI/boot/icons/dgpu.png
+#UFD-DGPU# loader /dgpu/vmlinuz
+#UFD-DGPU# initrd /arch/boot/intel_ucode.img
+#UFD-DGPU# initrd /arch/boot/amd_ucode.img
+#UFD-DGPU# initrd /dgpu/archiso.img
+#UFD-DGPU# options "archisobasedir=dgpu archisolabel=%ARCHISO_LABEL% nomodeset"
+#UFD-DGPU#}
+
diff --git a/.linux_items/include/airootfs/etc/adjtime b/.linux_items/include/airootfs/etc/adjtime
new file mode 100644
index 00000000..df526cf2
--- /dev/null
+++ b/.linux_items/include/airootfs/etc/adjtime
@@ -0,0 +1,3 @@
+0.0 0 0
+0
+LOCAL
diff --git a/.linux_items/include/airootfs/etc/skel/.aliases b/.linux_items/include/airootfs/etc/skel/.aliases
index d6486258..b0068be3 100644
--- a/.linux_items/include/airootfs/etc/skel/.aliases
+++ b/.linux_items/include/airootfs/etc/skel/.aliases
@@ -34,5 +34,5 @@ alias srsz='sudo rsync -avhzPS --stats --exclude-from="$HOME/.rsync_exclusions"'
alias testdisk='sudo testdisk'
alias umount='sudo umount'
alias unmount='sudo umount'
-alias wkclone='sudo ddrescue-tui clone'
-alias wkimage='sudo ddrescue-tui image'
+alias wkclone='ddrescue-tui clone'
+alias wkimage='ddrescue-tui image'
diff --git a/.linux_items/include/airootfs/etc/skel/.tmux.conf b/.linux_items/include/airootfs/etc/skel/.tmux.conf
index a3712835..c82d4600 100644
--- a/.linux_items/include/airootfs/etc/skel/.tmux.conf
+++ b/.linux_items/include/airootfs/etc/skel/.tmux.conf
@@ -1,5 +1,5 @@
set -g status off
-set -g pane-active-border-fg white
+set -g pane-active-border-style fg=white
# Window names
set -g set-titles on
diff --git a/.linux_items/include/airootfs/etc/skel/.update_network b/.linux_items/include/airootfs/etc/skel/.update_network
index e7119a37..fb3ec990 100755
--- a/.linux_items/include/airootfs/etc/skel/.update_network
+++ b/.linux_items/include/airootfs/etc/skel/.update_network
@@ -1,23 +1,22 @@
-## .update_network ##
#!/bin/env bash
#
-## Connect to network and update hostname
+## Setup network and update hostname
-# Connect
-connect-to-network
-sleep 2s
+# Wait for WiFi
+sleep 1s
+# Set hostname
IP="$(ip a show scope global \
| grep inet \
| head -1 \
| sed -r 's#.*inet ([0-9]+.[0-9]+.[0-9]+.[0-9]+.)/.*#\1#')"
-HOSTNAME="$(dig +noall +answer +short -x "$IP" \
- | grep -v ';' \
- | head -1 \
- | sed 's/\.$//')"
-
-# Set hostname
-if [[ "${HOSTNAME:+x}" ]]; then
- sudo hostnamectl set-hostname "${HOSTNAME}"
+if [[ "${IP:+x}" ]]; then
+ NEW_HOSTNAME="$(dig +noall +answer +short -x "$IP" \
+ | grep -v ';' \
+ | head -1 \
+ | sed 's/\.$//')"
+fi
+if [[ "${NEW_HOSTNAME:+x}" ]]; then
+ sudo hostnamectl set-hostname "${NEW_HOSTNAME}"
fi
diff --git a/.linux_items/include/syslinux/wk_head.cfg b/.linux_items/include/syslinux/wk_head.cfg
index d2f1ee9f..2d57c98b 100644
--- a/.linux_items/include/syslinux/wk_head.cfg
+++ b/.linux_items/include/syslinux/wk_head.cfg
@@ -1,7 +1,7 @@
SERIAL 0 38400
UI boot/syslinux/vesamenu.c32
MENU TITLE _______
-MENU BACKGROUND syslinux.png
+MENU BACKGROUND syslinux.jpg
MENU WIDTH 80
MENU MARGIN 10
diff --git a/.linux_items/include/syslinux/wk_pxe.cfg b/.linux_items/include/syslinux/wk_pxe.cfg
index 10112666..20bdf3dd 100644
--- a/.linux_items/include/syslinux/wk_pxe.cfg
+++ b/.linux_items/include/syslinux/wk_pxe.cfg
@@ -1,5 +1,5 @@
INCLUDE boot/syslinux/wk_head.cfg
-MENU BACKGROUND pxelinux.png
+MENU BACKGROUND pxelinux.jpg
INCLUDE boot/syslinux/wk_pxe_linux.cfg
#UFD-WINPE#INCLUDE boot/syslinux/wk_pxe_winpe.cfg
diff --git a/.linux_items/include/syslinux/wk_sys.cfg b/.linux_items/include/syslinux/wk_sys.cfg
index 442ec2a3..f756e525 100644
--- a/.linux_items/include/syslinux/wk_sys.cfg
+++ b/.linux_items/include/syslinux/wk_sys.cfg
@@ -2,7 +2,7 @@ INCLUDE boot/syslinux/wk_head.cfg
INCLUDE boot/syslinux/wk_sys_linux.cfg
#UFD-WINPE#INCLUDE boot/syslinux/wk_sys_winpe.cfg
-#UFD#INCLUDE boot/syslinux/1201_hdclone.cfg
-#UFD#INCLUDE boot/syslinux/1201_eset.cfg
+#UFD-HDCLONE#INCLUDE boot/syslinux/1201_hdclone.cfg
+#UFD-ESET#INCLUDE boot/syslinux/1201_eset.cfg
#DISABLED_UPSTREAM_BUG#INCLUDE boot/syslinux/wk_hdt.cfg
INCLUDE boot/syslinux/wk_tail.cfg
diff --git a/.linux_items/include/syslinux/wk_sys_linux.cfg b/.linux_items/include/syslinux/wk_sys_linux.cfg
index 9c229249..b6a9370c 100644
--- a/.linux_items/include/syslinux/wk_sys_linux.cfg
+++ b/.linux_items/include/syslinux/wk_sys_linux.cfg
@@ -8,16 +8,6 @@ LINUX boot/x86_64/vmlinuz
INITRD boot/intel_ucode.img,boot/amd_ucode.img,boot/x86_64/archiso.img
APPEND archisobasedir=%INSTALL_DIR% archisolabel=%ARCHISO_LABEL% copytoram loglevel=3
-LABEL wk_sys_linux_extras
-TEXT HELP
-Show extra Linux options
-ENDTEXT
-MENU LABEL Linux (i3)
-LINUX boot/x86_64/vmlinuz
-INITRD boot/intel_ucode.img,boot/amd_ucode.img,boot/x86_64/archiso.img
-APPEND archisobasedir=%INSTALL_DIR% archisolabel=%ARCHISO_LABEL% copytoram loglevel=3 i3
-SYSAPPEND 3
-
LABEL wk_linux_cli
TEXT HELP
A live Linux environment (CLI)
@@ -26,5 +16,17 @@ ENDTEXT
MENU LABEL Linux (CLI)
LINUX boot/x86_64/vmlinuz
INITRD boot/intel_ucode.img,boot/amd_ucode.img,boot/x86_64/archiso.img
-APPEND archisobasedir=%INSTALL_DIR% archisolabel=%ARCHISO_LABEL% copytoram nox nomodeset
+APPEND archisobasedir=%INSTALL_DIR% archisolabel=%ARCHISO_LABEL% copytoram nox
SYSAPPEND 3
+
+#UFD-MINIMAL#LABEL wk_linux_minimal
+#UFD-MINIMAL#TEXT HELP
+#UFD-MINIMAL#A live Linux environment (Minimal)
+#UFD-MINIMAL# * HW diagnostics, file-based backups, data recovery, etc
+#UFD-MINIMAL#ENDTEXT
+#UFD-MINIMAL#MENU LABEL Linux (Minimal)
+#UFD-MINIMAL#LINUX ../arch_minimal/vmlinuz
+#UFD-MINIMAL#INITRD boot/intel_ucode.img,boot/amd_ucode.img,../arch_minimal/archiso.img
+#UFD-MINIMAL#APPEND archisobasedir=arch_minimal archisolabel=%ARCHISO_LABEL% copytoram loglevel=3
+#UFD-MINIMAL#SYSAPPEND 3
+
diff --git a/.linux_items/include_x/airootfs/etc/skel/.Xresources b/.linux_items/include_x/airootfs/etc/skel/.Xresources
index 8e303276..d659b735 100755
--- a/.linux_items/include_x/airootfs/etc/skel/.Xresources
+++ b/.linux_items/include_x/airootfs/etc/skel/.Xresources
@@ -23,7 +23,7 @@ URxvt*externalBorder: 0
!URxvt.colorUL: #87afd7
URxvt.geometry: 92x16
URxvt.internalBorder: 8
-URxvt.shading: 7
+URxvt.shading: 10
URxvt.transparent: true
! Base16 Isotope
diff --git a/.linux_items/include_x/airootfs/etc/skel/.config/rofi/config b/.linux_items/include_x/airootfs/etc/skel/.config/rofi/config
index 5c27c752..fd8bc24c 100644
--- a/.linux_items/include_x/airootfs/etc/skel/.config/rofi/config
+++ b/.linux_items/include_x/airootfs/etc/skel/.config/rofi/config
@@ -7,5 +7,7 @@ rofi.color-normal: argb:d02d3036, #d8d8d8, argb:d02d3036, #2d3036, #d64937
rofi.color-active: argb:d0222222, #d64937, argb:d0222222, #d64937, #d8d8d8
rofi.color-urgent: argb:d0888888, #d8d8d8, argb:d0888888, #888888, #d64937
+rofi.font: Noto Sans 12
+
rofi.separator-style: solid
rofi.hide-scrollbar: true
diff --git a/.linux_items/include_x/airootfs/etc/skel/.config/systemd/user/timers.target.wants/update-conky.timer b/.linux_items/include_x/airootfs/etc/skel/.config/systemd/user/timers.target.wants/update-conky.timer
new file mode 120000
index 00000000..dc3ece34
--- /dev/null
+++ b/.linux_items/include_x/airootfs/etc/skel/.config/systemd/user/timers.target.wants/update-conky.timer
@@ -0,0 +1 @@
+../update-conky.timer
\ No newline at end of file
diff --git a/.linux_items/include_x/airootfs/etc/skel/.config/systemd/user/update-conky.service b/.linux_items/include_x/airootfs/etc/skel/.config/systemd/user/update-conky.service
new file mode 100644
index 00000000..d2048e93
--- /dev/null
+++ b/.linux_items/include_x/airootfs/etc/skel/.config/systemd/user/update-conky.service
@@ -0,0 +1,6 @@
+[Unit]
+Description=Conky config update service
+
+[Service]
+Type=oneshot
+ExecStart=%h/.update_conky
diff --git a/.linux_items/include_x/airootfs/etc/skel/.config/systemd/user/update-conky.timer b/.linux_items/include_x/airootfs/etc/skel/.config/systemd/user/update-conky.timer
new file mode 100644
index 00000000..c742a10a
--- /dev/null
+++ b/.linux_items/include_x/airootfs/etc/skel/.config/systemd/user/update-conky.timer
@@ -0,0 +1,10 @@
+[Unit]
+Description=Conky config update timer
+
+[Timer]
+OnBootSec=5s
+OnUnitActiveSec=30s
+Unit=update-conky.service
+
+[Install]
+WantedBy=timers.target
diff --git a/.linux_items/include_x/airootfs/etc/skel/.conkyrc b/.linux_items/include_x/airootfs/etc/skel/.conkyrc_base
similarity index 100%
rename from .linux_items/include_x/airootfs/etc/skel/.conkyrc
rename to .linux_items/include_x/airootfs/etc/skel/.conkyrc_base
diff --git a/.linux_items/include_x/airootfs/etc/skel/.update_conky b/.linux_items/include_x/airootfs/etc/skel/.update_conky
index 79801d8b..0e45e13d 100755
--- a/.linux_items/include_x/airootfs/etc/skel/.update_conky
+++ b/.linux_items/include_x/airootfs/etc/skel/.update_conky
@@ -1,18 +1,24 @@
#!/bin/bash
-IF_LIST=($(ip l | egrep '^[0-9]+:\s+(eth|en|wl)' | sed -r 's/^[0-9]+:\s+(\w+):.*/\1/' | sort))
+IF_LIST=($(ip l \
+ | egrep '^[0-9]+:\s+(eth|en|wl)' \
+ | sed -r 's/^[0-9]+:\s+(\w+):.*/\1/' \
+ | sort))
+
+# Reset conkyrc to default
+rm "${HOME}/.conkyrc"
+cp "${HOME}/.conkyrc_base" "${HOME}/.conkyrc"
# Add interfaces to conkyrc
-if fgrep '#Network' $HOME/.conkyrc; then
- for i in "${IF_LIST[@]}"; do
- if [[ "${i:0:1}" == "e" ]]; then
- sed -i -r "s/#Network/Wired:\${alignr}\${addr $i}\n#Network/" $HOME/.conkyrc
- else
- sed -i -r "s/#Network/Wireless:\${alignr}\${addr $i}\n#Network/" $HOME/.conkyrc
- fi
- done
+for i in "${IF_LIST[@]}"; do
+ if [[ "${i:0:1}" == "e" ]]; then
+ sed -i -r "s/#Network/Wired:\${alignr}\${addr $i}\n#Network/" $HOME/.conkyrc
+ else
+ sed -i -r "s/#Network/Wireless:\${alignr}\${addr $i}\n#Network/" $HOME/.conkyrc
+ fi
+done
- # Remove '#Network' line to prevent duplicating lines if this script is re-run
- sed -i -r "s/#Network//" $HOME/.conkyrc
-fi
+# Remove '#Network' line to prevent duplicating lines if this script is re-run
+sed -i -r "s/#Network//" $HOME/.conkyrc
+# vim: sts=2 sw=2 ts=2
diff --git a/.linux_items/include_x/airootfs/etc/skel/.update_x b/.linux_items/include_x/airootfs/etc/skel/.update_x
index 650d3162..06611081 100755
--- a/.linux_items/include_x/airootfs/etc/skel/.update_x
+++ b/.linux_items/include_x/airootfs/etc/skel/.update_x
@@ -4,6 +4,7 @@
REGEX_XRANDR='^.* ([0-9]+)x([0-9]+)\+[0-9]+\+[0-9]+.* ([0-9]+)mm x ([0-9]+)mm.*$'
REGEX_URXVT='(URxvt.geometry:\s+).*'
+TEST_STATION_WALLPAPERS='/usr/share/wallpaper/test-stations'
# Get screen data
xrandr_str="$(xrandr | grep mm | head -1)"
@@ -32,10 +33,10 @@ offset_urxvt="24"
# Update settings if necessary
if [[ "${dpi}" -ge 192 ]]; then
# Conky
- sed -i 's/minimum_size 180 0/minimum_size 360 0/' "${HOME}/.conkyrc"
- sed -i 's/maximum_width 180/maximum_width 360/' "${HOME}/.conkyrc"
- sed -i 's/gap_x 20/gap_x 40/' "${HOME}/.conkyrc"
- sed -i 's/gap_y 24/gap_y 48/' "${HOME}/.conkyrc"
+ sed -i 's/minimum_size 180 0/minimum_size 360 0/' "${HOME}/.conkyrc_base"
+ sed -i 's/maximum_width 180/maximum_width 360/' "${HOME}/.conkyrc_base"
+ sed -i 's/gap_x 20/gap_x 40/' "${HOME}/.conkyrc_base"
+ sed -i 's/gap_y 24/gap_y 48/' "${HOME}/.conkyrc_base"
# Fonts
sed -i 's/!Xft.dpi: 192/Xft.dpi: 192/' "${HOME}/.Xresources"
@@ -47,6 +48,9 @@ if [[ "${dpi}" -ge 192 ]]; then
# i3
sed -i -r 's/(height\s+) 26/\1 52/' "${HOME}/.config/i3/config"
+ # Rofi
+ sed -i -r 's/Noto Sans 12/Noto Sans 24/' "${HOME}/.config/rofi/config"
+
# Tint2
sed -i 's/panel_size = 100% 30/panel_size = 100% 60/' \
"${HOME}/.config/tint2/tint2rc"
@@ -67,13 +71,29 @@ fi
urxvt_geometry="${width_urxvt}x${height_urxvt}+${offset_urxvt}+${offset_urxvt}"
sed -i -r "s/${REGEX_URXVT}/\1${urxvt_geometry}/" "${HOME}/.Xresources"
+# Update conky
+$HOME/.update_conky
+
# Update X
xset s off
xset -dpms
xrdb -merge $HOME/.Xresources
+# Set wallpaper
+_hostname="$(hostnamectl --static | sed 's/.1201.com//')"
+_ip="$(ip a show scope global \
+ | grep inet \
+ | head -1 \
+ | sed -r 's#.*inet ([0-9]+.[0-9]+.[0-9]+.[0-9]+.)/.*#\1#')"
+if [[ -e "$TEST_STATION_WALLPAPERS/${_hostname:+x}" ]]; then
+ feh --bg-fill "$TEST_STATION_WALLPAPERS/${_hostname:+x}"
+elif [[ -e "$TEST_STATION_WALLPAPERS/${_ip:+x}" ]]; then
+ feh --bg-fill "$TEST_STATION_WALLPAPERS/${_ip:+x}"
+else
+ feh --bg-fill "$HOME/.wallpaper"
+fi
+
# Start common desktop apps
-feh --bg-fill "$HOME/.wallpaper"
compton --backend xrender --xrender-sync --xrender-sync-fence &
sleep 1s
x0vncserver -display :0 -passwordfile $HOME/.vnc/passwd -AlwaysShared &
diff --git a/.linux_items/include_x/airootfs/etc/skel/.zlogin b/.linux_items/include_x/airootfs/etc/skel/.zlogin
index 775ac320..8505b95a 100644
--- a/.linux_items/include_x/airootfs/etc/skel/.zlogin
+++ b/.linux_items/include_x/airootfs/etc/skel/.zlogin
@@ -12,9 +12,6 @@ if [ "$(fgconsole 2>/dev/null)" -eq "1" ]; then
sed -i -r 's/openbox-session/i3/' ~/.xinitrc
fi
- # Update Conky
- $HOME/.update_conky
-
# Start X or HW-diags
if ! fgrep -q "nox" /proc/cmdline; then
# Kill Xorg after 30 seconds if it doesn't fully initialize
diff --git a/.linux_items/include_x/airootfs/usr/share/wallpapers/test-stations/10.120.1.30 b/.linux_items/include_x/airootfs/usr/share/wallpapers/test-stations/10.120.1.30
new file mode 120000
index 00000000..e7e8c5aa
--- /dev/null
+++ b/.linux_items/include_x/airootfs/usr/share/wallpapers/test-stations/10.120.1.30
@@ -0,0 +1 @@
+bender
\ No newline at end of file
diff --git a/.linux_items/include_x/airootfs/usr/share/wallpapers/test-stations/10.120.1.31 b/.linux_items/include_x/airootfs/usr/share/wallpapers/test-stations/10.120.1.31
new file mode 120000
index 00000000..80059e2b
--- /dev/null
+++ b/.linux_items/include_x/airootfs/usr/share/wallpapers/test-stations/10.120.1.31
@@ -0,0 +1 @@
+cortana
\ No newline at end of file
diff --git a/.linux_items/include_x/airootfs/usr/share/wallpapers/test-stations/10.120.1.32 b/.linux_items/include_x/airootfs/usr/share/wallpapers/test-stations/10.120.1.32
new file mode 120000
index 00000000..0cf4a743
--- /dev/null
+++ b/.linux_items/include_x/airootfs/usr/share/wallpapers/test-stations/10.120.1.32
@@ -0,0 +1 @@
+glados
\ No newline at end of file
diff --git a/.linux_items/include_x/airootfs/usr/share/wallpapers/test-stations/10.120.1.33 b/.linux_items/include_x/airootfs/usr/share/wallpapers/test-stations/10.120.1.33
new file mode 120000
index 00000000..859a8a22
--- /dev/null
+++ b/.linux_items/include_x/airootfs/usr/share/wallpapers/test-stations/10.120.1.33
@@ -0,0 +1 @@
+shodan
\ No newline at end of file
diff --git a/.linux_items/include_x/airootfs/usr/share/wallpapers/test-stations/10.120.1.34 b/.linux_items/include_x/airootfs/usr/share/wallpapers/test-stations/10.120.1.34
new file mode 120000
index 00000000..2656ea46
--- /dev/null
+++ b/.linux_items/include_x/airootfs/usr/share/wallpapers/test-stations/10.120.1.34
@@ -0,0 +1 @@
+skynet
\ No newline at end of file
diff --git a/.linux_items/include_x/airootfs/usr/share/wallpapers/test-stations/10.120.1.35 b/.linux_items/include_x/airootfs/usr/share/wallpapers/test-stations/10.120.1.35
new file mode 120000
index 00000000..fc6bb73b
--- /dev/null
+++ b/.linux_items/include_x/airootfs/usr/share/wallpapers/test-stations/10.120.1.35
@@ -0,0 +1 @@
+sex-robot
\ No newline at end of file
diff --git a/.linux_items/include_x/airootfs/usr/share/wallpapers/test-stations/10.120.1.36 b/.linux_items/include_x/airootfs/usr/share/wallpapers/test-stations/10.120.1.36
new file mode 120000
index 00000000..221efe41
--- /dev/null
+++ b/.linux_items/include_x/airootfs/usr/share/wallpapers/test-stations/10.120.1.36
@@ -0,0 +1 @@
+combine
\ No newline at end of file
diff --git a/.linux_items/include_x/airootfs/usr/share/wallpapers/test-stations/10.120.1.37 b/.linux_items/include_x/airootfs/usr/share/wallpapers/test-stations/10.120.1.37
new file mode 120000
index 00000000..6c400f05
--- /dev/null
+++ b/.linux_items/include_x/airootfs/usr/share/wallpapers/test-stations/10.120.1.37
@@ -0,0 +1 @@
+locutus
\ No newline at end of file
diff --git a/.linux_items/include_x/airootfs/usr/share/wallpapers/test-stations/10.120.1.38 b/.linux_items/include_x/airootfs/usr/share/wallpapers/test-stations/10.120.1.38
new file mode 120000
index 00000000..64c56a36
--- /dev/null
+++ b/.linux_items/include_x/airootfs/usr/share/wallpapers/test-stations/10.120.1.38
@@ -0,0 +1 @@
+six
\ No newline at end of file
diff --git a/.linux_items/include_x/airootfs/usr/share/wallpapers/test-stations/10.120.1.39 b/.linux_items/include_x/airootfs/usr/share/wallpapers/test-stations/10.120.1.39
new file mode 120000
index 00000000..45f6d8e7
--- /dev/null
+++ b/.linux_items/include_x/airootfs/usr/share/wallpapers/test-stations/10.120.1.39
@@ -0,0 +1 @@
+Data
\ No newline at end of file
diff --git a/.linux_items/include_x/airootfs/usr/share/wallpapers/test-stations/10.120.1.40 b/.linux_items/include_x/airootfs/usr/share/wallpapers/test-stations/10.120.1.40
new file mode 120000
index 00000000..b69e57d2
--- /dev/null
+++ b/.linux_items/include_x/airootfs/usr/share/wallpapers/test-stations/10.120.1.40
@@ -0,0 +1 @@
+Control
\ No newline at end of file
diff --git a/.linux_items/include_x/airootfs/usr/share/wallpapers/test-stations/10.120.1.41 b/.linux_items/include_x/airootfs/usr/share/wallpapers/test-stations/10.120.1.41
new file mode 120000
index 00000000..0e2e8212
--- /dev/null
+++ b/.linux_items/include_x/airootfs/usr/share/wallpapers/test-stations/10.120.1.41
@@ -0,0 +1 @@
+Supremo
\ No newline at end of file
diff --git a/.linux_items/include_x/airootfs/usr/share/wallpapers/test-stations/10.120.1.42 b/.linux_items/include_x/airootfs/usr/share/wallpapers/test-stations/10.120.1.42
new file mode 120000
index 00000000..6f65f708
--- /dev/null
+++ b/.linux_items/include_x/airootfs/usr/share/wallpapers/test-stations/10.120.1.42
@@ -0,0 +1 @@
+Unicron
\ No newline at end of file
diff --git a/.linux_items/include_x/airootfs/usr/share/wallpapers/test-stations/10.120.1.43 b/.linux_items/include_x/airootfs/usr/share/wallpapers/test-stations/10.120.1.43
new file mode 120000
index 00000000..ec4183e6
--- /dev/null
+++ b/.linux_items/include_x/airootfs/usr/share/wallpapers/test-stations/10.120.1.43
@@ -0,0 +1 @@
+Lore
\ No newline at end of file
diff --git a/.linux_items/include_x/airootfs/usr/share/wallpapers/test-stations/Control b/.linux_items/include_x/airootfs/usr/share/wallpapers/test-stations/Control
new file mode 100644
index 00000000..22a30dd6
Binary files /dev/null and b/.linux_items/include_x/airootfs/usr/share/wallpapers/test-stations/Control differ
diff --git a/.linux_items/include_x/airootfs/usr/share/wallpapers/test-stations/Data b/.linux_items/include_x/airootfs/usr/share/wallpapers/test-stations/Data
new file mode 100644
index 00000000..0f41842a
Binary files /dev/null and b/.linux_items/include_x/airootfs/usr/share/wallpapers/test-stations/Data differ
diff --git a/.linux_items/include_x/airootfs/usr/share/wallpapers/test-stations/Lore b/.linux_items/include_x/airootfs/usr/share/wallpapers/test-stations/Lore
new file mode 100644
index 00000000..710f9359
Binary files /dev/null and b/.linux_items/include_x/airootfs/usr/share/wallpapers/test-stations/Lore differ
diff --git a/.linux_items/include_x/airootfs/usr/share/wallpapers/test-stations/Supremo b/.linux_items/include_x/airootfs/usr/share/wallpapers/test-stations/Supremo
new file mode 100644
index 00000000..4006cb32
Binary files /dev/null and b/.linux_items/include_x/airootfs/usr/share/wallpapers/test-stations/Supremo differ
diff --git a/.linux_items/include_x/airootfs/usr/share/wallpapers/test-stations/Unicron b/.linux_items/include_x/airootfs/usr/share/wallpapers/test-stations/Unicron
new file mode 100644
index 00000000..4089bb81
Binary files /dev/null and b/.linux_items/include_x/airootfs/usr/share/wallpapers/test-stations/Unicron differ
diff --git a/.linux_items/include_x/airootfs/usr/share/wallpapers/test-stations/bender b/.linux_items/include_x/airootfs/usr/share/wallpapers/test-stations/bender
new file mode 100644
index 00000000..2b39c767
Binary files /dev/null and b/.linux_items/include_x/airootfs/usr/share/wallpapers/test-stations/bender differ
diff --git a/.linux_items/include_x/airootfs/usr/share/wallpapers/test-stations/combine b/.linux_items/include_x/airootfs/usr/share/wallpapers/test-stations/combine
new file mode 100644
index 00000000..8a8b0b76
Binary files /dev/null and b/.linux_items/include_x/airootfs/usr/share/wallpapers/test-stations/combine differ
diff --git a/.linux_items/include_x/airootfs/usr/share/wallpapers/test-stations/cortana b/.linux_items/include_x/airootfs/usr/share/wallpapers/test-stations/cortana
new file mode 100644
index 00000000..01dfd980
Binary files /dev/null and b/.linux_items/include_x/airootfs/usr/share/wallpapers/test-stations/cortana differ
diff --git a/.linux_items/include_x/airootfs/usr/share/wallpapers/test-stations/glados b/.linux_items/include_x/airootfs/usr/share/wallpapers/test-stations/glados
new file mode 100644
index 00000000..661195b8
Binary files /dev/null and b/.linux_items/include_x/airootfs/usr/share/wallpapers/test-stations/glados differ
diff --git a/.linux_items/include_x/airootfs/usr/share/wallpapers/test-stations/locutus b/.linux_items/include_x/airootfs/usr/share/wallpapers/test-stations/locutus
new file mode 100644
index 00000000..01be685d
Binary files /dev/null and b/.linux_items/include_x/airootfs/usr/share/wallpapers/test-stations/locutus differ
diff --git a/.linux_items/include_x/airootfs/usr/share/wallpapers/test-stations/sex-robot b/.linux_items/include_x/airootfs/usr/share/wallpapers/test-stations/sex-robot
new file mode 100644
index 00000000..ed63559d
Binary files /dev/null and b/.linux_items/include_x/airootfs/usr/share/wallpapers/test-stations/sex-robot differ
diff --git a/.linux_items/include_x/airootfs/usr/share/wallpapers/test-stations/shodan b/.linux_items/include_x/airootfs/usr/share/wallpapers/test-stations/shodan
new file mode 100644
index 00000000..c781fb2e
Binary files /dev/null and b/.linux_items/include_x/airootfs/usr/share/wallpapers/test-stations/shodan differ
diff --git a/.linux_items/include_x/airootfs/usr/share/wallpapers/test-stations/six b/.linux_items/include_x/airootfs/usr/share/wallpapers/test-stations/six
new file mode 100644
index 00000000..a32bf534
Binary files /dev/null and b/.linux_items/include_x/airootfs/usr/share/wallpapers/test-stations/six differ
diff --git a/.linux_items/include_x/airootfs/usr/share/wallpapers/test-stations/skynet b/.linux_items/include_x/airootfs/usr/share/wallpapers/test-stations/skynet
new file mode 100644
index 00000000..b4d6cd17
Binary files /dev/null and b/.linux_items/include_x/airootfs/usr/share/wallpapers/test-stations/skynet differ
diff --git a/.linux_items/known_networks b/.linux_items/known_networks
new file mode 100644
index 00000000..08b60f1e
--- /dev/null
+++ b/.linux_items/known_networks
@@ -0,0 +1,4 @@
+#Put WiFi network info here
+#'WiFi SSID': 'WiFi Password'
+'1201computersXI': 'wifipassword'
+'1201computersXI-5g': 'wifipassword'
diff --git a/.linux_items/packages/dependencies b/.linux_items/packages/dependencies
index 4558e9eb..5600fec3 100644
--- a/.linux_items/packages/dependencies
+++ b/.linux_items/packages/dependencies
@@ -21,6 +21,7 @@ ntfs-3g
openssh
p7zip
pango
+perl-rename
progsreiserfs
refind-efi
rsync
diff --git a/.linux_items/packages/live_add b/.linux_items/packages/live_add
index 5d28f9f9..5000edcf 100644
--- a/.linux_items/packages/live_add
+++ b/.linux_items/packages/live_add
@@ -16,6 +16,7 @@ e2fsprogs
hexedit
hfsprogs
htop
+iwd
ldmtool
ldns
lha
@@ -32,9 +33,11 @@ networkmanager
p7zip
progsreiserfs
python
+python-docopt
python-gnuplot
python-mysql-connector
python-psutil
+python-pytz
python-requests
reiserfsprogs
rfkill
diff --git a/.linux_items/packages/live_remove b/.linux_items/packages/live_remove
index 9feb3c02..2e1ffbe7 100644
--- a/.linux_items/packages/live_remove
+++ b/.linux_items/packages/live_remove
@@ -14,6 +14,7 @@ rp-pppoe
smartmontools
speedtouch
testdisk
+wpa_actiond
vim-minimal
vpnc
wvdial
diff --git a/Build Kit.cmd b/Build Kit.cmd
index 58272a45..982c90c8 100644
--- a/Build Kit.cmd
+++ b/Build Kit.cmd
@@ -14,7 +14,7 @@ robocopy /e .bin OUT_KIT\.bin
robocopy /e .cbin OUT_KIT\.cbin
copy LICENSE.txt OUT_KIT\LICENSE.txt
copy README.md OUT_KIT\README.md
-copy Images\ConEmu.png OUT_KIT\.bin\ConEmu\
+copy Images\ConEmu.jpg OUT_KIT\.bin\ConEmu\
mkdir OUT_KIT\.cbin >nul 2>&1
attrib +h OUT_KIT\.bin >nul 2>&1
attrib +h OUT_KIT\.cbin >nul 2>&1
diff --git a/Build Linux b/Build Linux
index 8ed965b5..6f709a77 100755
--- a/Build Linux
+++ b/Build Linux
@@ -40,7 +40,7 @@ function ask() {
fi
done
}
-
+
function cleanup() {
for d in "$TEMP_DIR" "$LIVE_DIR"; do
if [[ -d "$d" ]]; then
@@ -116,7 +116,7 @@ function copy_live_env() {
rmdir "$LIVE_DIR/airootfs/etc/udev" --ignore-fail-on-non-empty
rm "$LIVE_DIR/isolinux"/*.cfg
rm "$LIVE_DIR/syslinux"/*.cfg "$LIVE_DIR/syslinux"/*.png
-
+
# Add items
rsync -aI "$ROOT_DIR/.linux_items/include/" "$LIVE_DIR/"
if [[ "${1:-}" != "--minimal" ]]; then
@@ -155,17 +155,17 @@ function update_live_env() {
# Boot config (legacy)
mkdir -p "$LIVE_DIR/arch"
- cp "$ROOT_DIR/Images/Pxelinux.png" "$LIVE_DIR/arch/pxelinux.png"
- cp "$ROOT_DIR/Images/Syslinux.png" "$LIVE_DIR/arch/syslinux.png"
+ cp "$ROOT_DIR/Images/Pxelinux.jpg" "$LIVE_DIR/arch/pxelinux.jpg"
+ cp "$ROOT_DIR/Images/Syslinux.jpg" "$LIVE_DIR/arch/syslinux.jpg"
sed -i -r "s/_+/$KIT_NAME_FULL/" "$LIVE_DIR/syslinux/wk_head.cfg"
mkdir -p "$TEMP_DIR" 2>/dev/null
curl -Lo "$TEMP_DIR/wimboot.zip" "http://git.ipxe.org/releases/wimboot/wimboot-latest.zip"
- 7z e "$TEMP_DIR/wimboot.zip" -o"$LIVE_DIR/arch/boot" 'wimboot*/LICENSE.txt' 'wimboot*/README.txt' 'wimboot*/wimboot'
+ 7z e -aoa "$TEMP_DIR/wimboot.zip" -o"$LIVE_DIR/arch/boot" 'wimboot*/LICENSE.txt' 'wimboot*/README.txt' 'wimboot*/wimboot'
# Boot config (UEFI)
mkdir -p "$LIVE_DIR/EFI/boot"
cp "/usr/share/refind/refind_x64.efi" "$LIVE_DIR/EFI/boot/bootx64.efi"
- cp "$ROOT_DIR/Images/rEFInd.png" "$LIVE_DIR/EFI/boot/rEFInd.png"
+ cp "$ROOT_DIR/Images/rEFInd.jpg" "$LIVE_DIR/EFI/boot/rEFInd.jpg"
rsync -aI "/usr/share/refind/drivers_x64/" "$LIVE_DIR/EFI/boot/drivers_x64/"
rsync -aI "/usr/share/refind/icons/" "$LIVE_DIR/EFI/boot/icons/" --exclude "/usr/share/refind/icons/svg"
sed -i "s/%ARCHISO_LABEL%/${label}/" "$LIVE_DIR/EFI/boot/refind.conf"
@@ -177,9 +177,9 @@ function update_live_env() {
mkdir -p "$LIVE_DIR/EFI/memtest86/Benchmark"
mkdir -p "$TEMP_DIR/memtest86"
curl -Lo "$TEMP_DIR/memtest86/memtest86-usb.zip" "https://www.memtest86.com/downloads/memtest86-usb.zip"
- 7z e "$TEMP_DIR/memtest86/memtest86-usb.zip" -o"$TEMP_DIR/memtest86" "memtest86-usb.img"
- 7z e "$TEMP_DIR/memtest86/memtest86-usb.img" -o"$TEMP_DIR/memtest86" "MemTest86.img"
- 7z x "$TEMP_DIR/memtest86/MemTest86.img" -o"$TEMP_DIR/memtest86"
+ 7z e -aoa "$TEMP_DIR/memtest86/memtest86-usb.zip" -o"$TEMP_DIR/memtest86" "memtest86-usb.img"
+ 7z e -aoa "$TEMP_DIR/memtest86/memtest86-usb.img" -o"$TEMP_DIR/memtest86" "MemTest86.img"
+ 7z x -aoa "$TEMP_DIR/memtest86/MemTest86.img" -o"$TEMP_DIR/memtest86"
rm "$TEMP_DIR/memtest86/EFI/BOOT/BOOTIA32.efi"
mv "$TEMP_DIR/memtest86/EFI/BOOT/BOOTX64.efi" "$LIVE_DIR/EFI/memtest86/memtestx64.efi"
mv "$TEMP_DIR/memtest86/EFI/BOOT"/* "$LIVE_DIR/EFI/memtest86"/
@@ -195,7 +195,7 @@ function update_live_env() {
# Hostname
echo "$hostname" > "$LIVE_DIR/airootfs/etc/hostname"
echo "127.0.1.1 $hostname.localdomain $hostname" >> "$LIVE_DIR/airootfs/etc/hosts"
-
+
# Live packages
while read -r p; do
sed -i "/$p/d" "$LIVE_DIR/packages.x86_64"
@@ -215,7 +215,7 @@ function update_live_env() {
sed -i -r 's/^(.*mirrorlist.*)$/#NOPE#\1/' "$LIVE_DIR/airootfs/root/customize_airootfs.sh"
echo "curl -o '/etc/pacman.d/mirrorlist' '$MIRRORLIST_SOURCE'" >> "$LIVE_DIR/airootfs/root/customize_airootfs.sh"
echo "sed -i 's/#Server/Server/g' /etc/pacman.d/mirrorlist" >> "$LIVE_DIR/airootfs/root/customize_airootfs.sh"
-
+
# MOTD
sed -i -r "s/_+/$KIT_NAME_FULL Linux Environment/" "$LIVE_DIR/airootfs/etc/motd"
@@ -223,7 +223,7 @@ function update_live_env() {
git clone --depth=1 https://github.com/robbyrussell/oh-my-zsh.git "$SKEL_DIR/.oh-my-zsh"
rm -Rf "$SKEL_DIR/.oh-my-zsh/.git"
curl -o "$SKEL_DIR/.oh-my-zsh/themes/lean.zsh-theme" https://raw.githubusercontent.com/miekg/lean/master/prompt_lean_setup
-
+
if [[ "${1:-}" != "--minimal" ]]; then
# Openbox theme
git clone --depth=1 https://github.com/addy-dclxvi/Openbox-Theme-Collections.git "$TEMP_DIR/ob-themes"
@@ -238,7 +238,7 @@ function update_live_env() {
# Shutdown stall fix
echo "sed -i -r 's/^.*(DefaultTimeoutStartSec)=.*$/\1=15s/' /etc/systemd/system.conf" >> "$LIVE_DIR/airootfs/root/customize_airootfs.sh"
echo "sed -i -r 's/^.*(DefaultTimeoutStopSec)=.*$/\1=15s/' /etc/systemd/system.conf" >> "$LIVE_DIR/airootfs/root/customize_airootfs.sh"
-
+
# SSH
mkdir -p "$SKEL_DIR/.ssh"
ssh-keygen -b 4096 -C "$username@$hostname" -N "" -f "$SKEL_DIR/.ssh/id_rsa"
@@ -247,7 +247,7 @@ function update_live_env() {
sed -i -r '/.*PermitRootLogin.*/d' "$LIVE_DIR/airootfs/root/customize_airootfs.sh"
echo "sed -i -r '/.*PermitRootLogin.*/d' /etc/ssh/sshd_config" >> "$LIVE_DIR/airootfs/root/customize_airootfs.sh"
cp "$ROOT_DIR/.linux_items/authorized_keys" "$SKEL_DIR/.ssh/authorized_keys"
-
+
# Root user
echo "echo 'root:$ROOT_PASSWORD' | chpasswd" >> "$LIVE_DIR/airootfs/root/customize_airootfs.sh"
@@ -279,8 +279,12 @@ function update_live_env() {
# Wallpaper
mkdir -p "$LIVE_DIR/airootfs/usr/share/wallpaper"
- cp "$ROOT_DIR/Images/Linux.png" "$LIVE_DIR/airootfs/usr/share/wallpaper/burned.in"
+ cp "$ROOT_DIR/Images/Linux.jpg" "$LIVE_DIR/airootfs/usr/share/wallpaper/burned.in"
fi
+
+ # WiFi
+ cp "$ROOT_DIR/.linux_items/known_networks" "$LIVE_DIR/airootfs/root/known_networks"
+ echo "add-known-networks --user=$username" >> "$LIVE_DIR/airootfs/root/customize_airootfs.sh"
}
function update_repo() {
@@ -335,7 +339,7 @@ function build_iso() {
echo "Aborted."
exit 1
fi
-
+
# Set permissions
echo "Setting permissions..."
chown root:root "$LIVE_DIR" -R
@@ -350,7 +354,7 @@ function build_iso() {
fi
done
done
-
+
# Build ISO
prefix="${KIT_NAME_SHORT}-Linux"
label="${KIT_NAME_SHORT}_LINUX"
@@ -365,13 +369,44 @@ function build_iso() {
chown $REAL_USER:$REAL_USER "$OUT_DIR" -R
}
+function build_all() {
+ if [[ "$EUID" -eq 0 ]]; then
+ echo "This section not meant to be run as root."
+ echo "Aborted."
+ exit 1
+ fi
+
+ # Prep for build (full)
+ cleanup
+ fix_kit_permissions
+ install_deps
+ load_settings --edit
+ update_repo
+ copy_live_env
+ update_live_env
+ # Rerun script as root to start Archiso build process
+ run_elevated "$(realpath "$0")" --build-iso
+ # Cleanup
+ mv -nv "$LIVE_DIR" "${LIVE_DIR}.full"
+ perl-rename -v "s/(${KIT_NAME_SHORT}-Linux)-(${DATE}.*)/\1-Full-\2/" "$OUT_DIR"/*
+
+ # Prep for build (minimal)
+ copy_live_env --minimal
+ update_live_env --minimal
+ # Rerun script as root to start Archiso build process
+ run_elevated "$(realpath "$0")" --build-iso
+ # Cleanup
+ mv -nv "$LIVE_DIR" "${LIVE_DIR}.minimal"
+ perl-rename -v "s/(${KIT_NAME_SHORT}-Linux)-(${DATE}.*)/\1-Minimal-\2/" "$OUT_DIR"/*
+}
+
function build_full() {
if [[ "$EUID" -eq 0 ]]; then
echo "This section not meant to be run as root."
echo "Aborted."
exit 1
fi
-
+
# Prep for build
cleanup
fix_kit_permissions
@@ -386,6 +421,11 @@ function build_full() {
# Check input
case ${1:-} in
+ -a|--build-all)
+ build_all
+ echo Done
+ ;;
+
-b|--build-full)
build_full
echo Done
@@ -413,7 +453,7 @@ case ${1:-} in
build_iso
echo Done
;;
-
+
-p|--prep-live-env)
load_settings --edit
copy_live_env
@@ -430,7 +470,8 @@ case ${1:-} in
echo "Usage: $(basename "$0") [OPTIONS]"
echo ""
echo "Options:"
- echo " -b --build-full Perform all tasks and build iso"
+ echo " -a --build-all Perform all tasks to build all isos"
+ echo " -b --build-full Perform all tasks to build the full iso"
echo " -h --help Show usage"
echo ""
echo "Advanced options:"
diff --git a/Images/ConEmu.jpg b/Images/ConEmu.jpg
new file mode 100644
index 00000000..2d8ef42b
Binary files /dev/null and b/Images/ConEmu.jpg differ
diff --git a/Images/ConEmu.png b/Images/ConEmu.png
deleted file mode 100644
index c5bdb72e..00000000
Binary files a/Images/ConEmu.png and /dev/null differ
diff --git a/Images/Linux.jpg b/Images/Linux.jpg
new file mode 100644
index 00000000..92d2778d
Binary files /dev/null and b/Images/Linux.jpg differ
diff --git a/Images/Linux.png b/Images/Linux.png
deleted file mode 100644
index 7fcf0056..00000000
Binary files a/Images/Linux.png and /dev/null differ
diff --git a/Images/Pxelinux.jpg b/Images/Pxelinux.jpg
new file mode 100644
index 00000000..1247bff9
Binary files /dev/null and b/Images/Pxelinux.jpg differ
diff --git a/Images/Pxelinux.png b/Images/Pxelinux.png
deleted file mode 100644
index f3a6a6d9..00000000
Binary files a/Images/Pxelinux.png and /dev/null differ
diff --git a/Images/Syslinux.jpg b/Images/Syslinux.jpg
new file mode 100644
index 00000000..1247bff9
Binary files /dev/null and b/Images/Syslinux.jpg differ
diff --git a/Images/Syslinux.png b/Images/Syslinux.png
deleted file mode 100644
index de82aa33..00000000
Binary files a/Images/Syslinux.png and /dev/null differ
diff --git a/Images/WinPE.jpg b/Images/WinPE.jpg
index 5bc27ca2..5ad51d84 100644
Binary files a/Images/WinPE.jpg and b/Images/WinPE.jpg differ
diff --git a/Images/rEFInd.png b/Images/rEFInd.png
index 7e8e2fe5..d5fb1742 100644
Binary files a/Images/rEFInd.png and b/Images/rEFInd.png differ