feat(recovery): close host 112 guest readiness

This commit is contained in:
ogt
2026-07-11 19:58:15 +08:00
parent 69efe9aab3
commit 23751a7fc3
15 changed files with 1024 additions and 17 deletions

View File

@@ -0,0 +1,19 @@
[Unit]
Description=AWOOOI host 112 guest readiness and bounded recovery
After=network-online.target
Wants=network-online.target
[Service]
Type=oneshot
ExecStart=/usr/local/sbin/awoooi-host112-guest-readiness --apply
TimeoutStartSec=300
User=root
Group=root
NoNewPrivileges=true
PrivateTmp=true
ProtectHome=true
ProtectKernelTunables=true
ProtectKernelModules=true
ProtectControlGroups=true
RestrictSUIDSGID=true
LockPersonality=true

View File

@@ -0,0 +1,12 @@
[Unit]
Description=Run AWOOOI host 112 guest recovery after boot and continuously
[Timer]
OnBootSec=20s
OnUnitInactiveSec=60s
AccuracySec=5s
Persistent=true
Unit=awoooi-host112-guest-recovery.service
[Install]
WantedBy=timers.target

View File

@@ -0,0 +1,184 @@
#!/usr/bin/env bash
# Host 112 guest readiness and bounded recovery executor.
set -uo pipefail
MODE="check"
INDEXER_RETRY_AFTER_SECONDS="${HOST112_INDEXER_RETRY_AFTER_SECONDS:-210}"
INDEXER_RETRY_COOLDOWN_SECONDS="${HOST112_INDEXER_RETRY_COOLDOWN_SECONDS:-600}"
INDEXER_START_TIMEOUT_SECONDS="${HOST112_INDEXER_START_TIMEOUT_SECONDS:-240}"
STATE_DIR="${HOST112_RECOVERY_STATE_DIR:-/var/lib/awoooi-host112-recovery}"
RETRY_MARKER="${HOST112_INDEXER_RETRY_MARKER:-/run/awoooi-host112-indexer-retry.epoch}"
usage() {
cat <<'USAGE'
Usage: host112-guest-readiness.sh [--check|--apply]
--check emits a bounded no-secret guest readiness row.
--apply performs only allowlisted idempotent recovery for graphical.target,
LightDM, open-vm-tools and a cooldown-guarded Wazuh Indexer start retry.
USAGE
}
while [ "$#" -gt 0 ]; do
case "$1" in
--check) MODE="check" ;;
--apply) MODE="apply" ;;
-h|--help) usage; exit 0 ;;
*) echo "BLOCKER unknown_argument=$1" >&2; exit 64 ;;
esac
shift
done
actions=()
unit_active() {
local unit="$1" state
state="$(systemctl is-active "$unit" 2>/dev/null || true)"
printf '%s' "${state:-unknown}"
}
unit_enabled() {
local unit="$1" state
state="$(systemctl is-enabled "$unit" 2>/dev/null || true)"
printf '%s' "${state:-unknown}"
}
unit_loaded() {
[ "$(systemctl show "$1" -p LoadState --value 2>/dev/null || true)" = "loaded" ]
}
record_action() {
actions+=("$1")
}
start_if_inactive() {
local unit="$1" action="$2" state
state="$(unit_active "$unit")"
if [ "$state" = "active" ] || [ "$state" = "activating" ]; then
return 0
fi
if systemctl start "$unit"; then
record_action "$action"
else
record_action "${action}_failed"
fi
}
if [ "$MODE" = "apply" ]; then
if [ "${EUID:-$(id -u)}" -ne 0 ]; then
echo "BLOCKER host112_apply_requires_root" >&2
exit 77
fi
current_default="$(systemctl get-default 2>/dev/null || true)"
if [ "$current_default" != "graphical.target" ]; then
if systemctl set-default graphical.target >/dev/null; then
record_action "set_default_graphical_target"
else
record_action "set_default_graphical_target_failed"
fi
fi
start_if_inactive graphical.target start_graphical_target
start_if_inactive open-vm-tools.service start_vmware_tools
start_if_inactive lightdm.service start_lightdm
uptime_for_retry="$(awk '{print int($1)}' /proc/uptime 2>/dev/null || echo 0)"
indexer_state="$(unit_active wazuh-indexer.service)"
if unit_loaded wazuh-indexer.service \
&& [ "$indexer_state" != "active" ] \
&& [ "$indexer_state" != "activating" ] \
&& [ "$uptime_for_retry" -ge "$INDEXER_RETRY_AFTER_SECONDS" ]; then
now_epoch="$(date +%s)"
last_retry_epoch=0
if [ -r "$RETRY_MARKER" ]; then
read -r last_retry_epoch <"$RETRY_MARKER" || last_retry_epoch=0
fi
if ! [[ "$last_retry_epoch" =~ ^[0-9]+$ ]]; then
last_retry_epoch=0
fi
if [ $((now_epoch - last_retry_epoch)) -ge "$INDEXER_RETRY_COOLDOWN_SECONDS" ]; then
printf '%s\n' "$now_epoch" >"$RETRY_MARKER"
systemctl reset-failed wazuh-indexer.service >/dev/null 2>&1 || true
if timeout "$INDEXER_START_TIMEOUT_SECONDS" systemctl start wazuh-indexer.service; then
record_action "retry_wazuh_indexer"
else
record_action "retry_wazuh_indexer_failed"
fi
else
record_action "wazuh_indexer_retry_cooldown"
fi
fi
fi
boot_id="$(cat /proc/sys/kernel/random/boot_id 2>/dev/null || echo unknown)"
uptime_seconds="$(awk '{print int($1)}' /proc/uptime 2>/dev/null || echo unknown)"
systemd_state="$(systemctl is-system-running 2>/dev/null || true)"
systemd_state="${systemd_state:-unknown}"
default_target="$(systemctl get-default 2>/dev/null || true)"
default_target="${default_target:-unknown}"
graphical_target="$(unit_active graphical.target)"
display_manager="$(unit_active display-manager.service)"
lightdm="$(unit_active lightdm.service)"
vmware_tools="$(unit_active open-vm-tools.service)"
wazuh_indexer="$(unit_active wazuh-indexer.service)"
wazuh_manager="$(unit_active wazuh-manager.service)"
wazuh_dashboard="$(unit_active wazuh-dashboard.service)"
filebeat="$(unit_active filebeat.service)"
startup_enabled="$(unit_enabled awoooi-host112-guest-recovery.timer)"
startup_active="$(unit_active awoooi-host112-guest-recovery.timer)"
xorg="inactive"
if pgrep -x Xorg >/dev/null 2>&1 || pgrep -x Xwayland >/dev/null 2>&1; then
xorg="active"
fi
console_ready=0
if [ "$default_target" = "graphical.target" ] \
&& [ "$graphical_target" = "active" ] \
&& [ "$display_manager" = "active" ] \
&& [ "$lightdm" = "active" ] \
&& [ "$vmware_tools" = "active" ] \
&& [ "$xorg" = "active" ]; then
console_ready=1
fi
services_ready=0
if [ "$wazuh_indexer" = "active" ] \
&& [ "$wazuh_manager" = "active" ] \
&& [ "$wazuh_dashboard" = "active" ] \
&& [ "$filebeat" = "active" ]; then
services_ready=1
fi
recovery_timer_ready=0
if [ "$startup_enabled" = "enabled" ] && [ "$startup_active" = "active" ]; then
recovery_timer_ready=1
fi
guest_ready=0
if [ "$console_ready" -eq 1 ] \
&& [ "$services_ready" -eq 1 ] \
&& [ "$recovery_timer_ready" -eq 1 ] \
&& [ "$systemd_state" = "running" ]; then
guest_ready=1
fi
action_text="none"
if [ "${#actions[@]}" -gt 0 ]; then
action_text="$(IFS=,; printf '%s' "${actions[*]}")"
fi
readback="boot_id=$boot_id uptime_seconds=$uptime_seconds systemd_state=$systemd_state startup_enabled=$startup_enabled startup_active=$startup_active default_target=$default_target graphical_target=$graphical_target display_manager=$display_manager lightdm=$lightdm vmware_tools=$vmware_tools xorg=$xorg wazuh_indexer=$wazuh_indexer wazuh_manager=$wazuh_manager wazuh_dashboard=$wazuh_dashboard filebeat=$filebeat console_ready=$console_ready services_ready=$services_ready recovery_timer_ready=$recovery_timer_ready guest_ready=$guest_ready action_count=${#actions[@]} actions=$action_text"
printf '%s\n' "$readback"
if [ "$MODE" = "apply" ]; then
install -d -m 0750 "$STATE_DIR"
tmp_readback="${STATE_DIR}/last-readback.txt.tmp.$$"
printf 'generated_at=%s mode=%s %s\n' "$(date --iso-8601=seconds)" "$MODE" "$readback" >"$tmp_readback"
chmod 0640 "$tmp_readback"
mv "$tmp_readback" "${STATE_DIR}/last-readback.txt"
fi
[ "$guest_ready" -eq 1 ]

View File

@@ -0,0 +1,183 @@
#!/usr/bin/env bash
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
MODE="check"
ROLLBACK_DIR=""
TARGET_USER="${HOST112_TARGET_USER:-kali}"
CONTROL_SOURCE_ADDRESS="${HOST112_CONTROL_SOURCE_ADDRESS:-192.168.0.110}"
CONTROL_PUBLIC_KEY_PATH="${HOST112_CONTROL_PUBLIC_KEY_PATH:-${SCRIPT_DIR}/control.pub}"
READINESS_SOURCE="${SCRIPT_DIR}/host112-guest-readiness.sh"
SERVICE_SOURCE="${SCRIPT_DIR}/awoooi-host112-guest-recovery.service"
TIMER_SOURCE="${SCRIPT_DIR}/awoooi-host112-guest-recovery.timer"
READINESS_TARGET="/usr/local/sbin/awoooi-host112-guest-readiness"
INSTALLER_TARGET="/usr/local/sbin/awoooi-install-host112-guest-recovery"
SERVICE_TARGET="/etc/systemd/system/awoooi-host112-guest-recovery.service"
TIMER_TARGET="/etc/systemd/system/awoooi-host112-guest-recovery.timer"
SUDOERS_TARGET="/etc/sudoers.d/awoooi-host112-agent99"
STATE_ROOT="/var/lib/awoooi-host112-recovery"
usage() {
cat <<'USAGE'
Usage:
install-host112-guest-recovery.sh --check
install-host112-guest-recovery.sh --apply
install-host112-guest-recovery.sh --rollback BACKUP_DIR
Apply installs the bounded host-112 recovery timer, an exact-command sudo rule,
and a forced-command readback key for host 110. It never reboots the host.
USAGE
}
while [ "$#" -gt 0 ]; do
case "$1" in
--check) MODE="check" ;;
--apply) MODE="apply" ;;
--rollback)
MODE="rollback"
shift
ROLLBACK_DIR="${1:-}"
;;
-h|--help) usage; exit 0 ;;
*) echo "UNKNOWN_ARG=$1" >&2; usage >&2; exit 64 ;;
esac
shift
done
check() {
echo "AWOOOI_HOST112_GUEST_RECOVERY_INSTALLER=1"
echo "MODE=check"
for path in "$READINESS_TARGET" "$INSTALLER_TARGET" "$SERVICE_TARGET" "$TIMER_TARGET" "$SUDOERS_TARGET"; do
if [ -f "$path" ]; then
echo "TARGET path=$path present=1 sha256=$(sha256sum "$path" | awk '{print $1}')"
else
echo "TARGET path=$path present=0 sha256=missing"
fi
done
echo "TIMER_ENABLED=$(systemctl is-enabled awoooi-host112-guest-recovery.timer 2>/dev/null || true)"
echo "TIMER_ACTIVE=$(systemctl is-active awoooi-host112-guest-recovery.timer 2>/dev/null || true)"
if [ -x "$READINESS_TARGET" ]; then
"$READINESS_TARGET" --check || true
fi
}
require_root() {
if [ "${EUID:-$(id -u)}" -ne 0 ]; then
echo "BLOCKER host112_installer_requires_root" >&2
exit 77
fi
}
backup_path() {
local path="$1" backup_dir="$2" relative
if [ -e "$path" ]; then
relative="${path#/}"
install -d "${backup_dir}/rootfs/$(dirname "$relative")"
cp -a "$path" "${backup_dir}/rootfs/${relative}"
printf 'present\t%s\n' "$path" >>"${backup_dir}/manifest.tsv"
else
printf 'missing\t%s\n' "$path" >>"${backup_dir}/manifest.tsv"
fi
}
if [ "$MODE" = "check" ]; then
check
exit 0
fi
require_root
if [ "$MODE" = "rollback" ]; then
case "$ROLLBACK_DIR" in
"$STATE_ROOT"/backups/*) ;;
*) echo "BLOCKER invalid_host112_rollback_dir" >&2; exit 64 ;;
esac
[ -f "$ROLLBACK_DIR/manifest.tsv" ] || { echo "BLOCKER rollback_manifest_missing" >&2; exit 66; }
systemctl disable --now awoooi-host112-guest-recovery.timer >/dev/null 2>&1 || true
while IFS=$'\t' read -r state path; do
[ -n "$path" ] || continue
if [ "$state" = "present" ]; then
install -d "$(dirname "$path")"
cp -a "$ROLLBACK_DIR/rootfs/${path#/}" "$path"
else
rm -f "$path"
fi
done <"$ROLLBACK_DIR/manifest.tsv"
systemctl daemon-reload
if [ -f "$ROLLBACK_DIR/timer_was_enabled" ]; then
systemctl enable awoooi-host112-guest-recovery.timer >/dev/null
fi
if [ -f "$ROLLBACK_DIR/timer_was_active" ]; then
systemctl start awoooi-host112-guest-recovery.timer
fi
echo "AWOOOI_HOST112_GUEST_RECOVERY_INSTALLER=1"
echo "MODE=rollback"
echo "ROLLBACK_APPLIED=1"
check
exit 0
fi
for source in "$READINESS_SOURCE" "$SERVICE_SOURCE" "$TIMER_SOURCE" "$CONTROL_PUBLIC_KEY_PATH"; do
[ -f "$source" ] || { echo "BLOCKER source_missing=$source" >&2; exit 66; }
done
user_home="$(getent passwd "$TARGET_USER" | cut -d: -f6)"
user_group="$(id -gn "$TARGET_USER")"
[ -n "$user_home" ] || { echo "BLOCKER target_user_home_missing" >&2; exit 66; }
auth_dir="${user_home}/.ssh"
auth_file="${auth_dir}/authorized_keys"
read -r key_type key_blob _ <"$CONTROL_PUBLIC_KEY_PATH"
case "$key_type" in
ssh-ed25519|ssh-rsa|ecdsa-sha2-*) ;;
*) echo "BLOCKER unsupported_control_public_key_type" >&2; exit 65 ;;
esac
[[ "$key_blob" =~ ^[A-Za-z0-9+/=]+$ ]] || { echo "BLOCKER invalid_control_public_key_blob" >&2; exit 65; }
key_fingerprint="$(ssh-keygen -lf "$CONTROL_PUBLIC_KEY_PATH" | awk '{print $2}')"
run_id="host112-guest-recovery-$(date +%Y%m%dT%H%M%S%z)-$$"
backup_dir="${STATE_ROOT}/backups/${run_id}"
install -d -m 0750 "$backup_dir"
: >"${backup_dir}/manifest.tsv"
for path in "$READINESS_TARGET" "$INSTALLER_TARGET" "$SERVICE_TARGET" "$TIMER_TARGET" "$SUDOERS_TARGET" "$auth_file"; do
backup_path "$path" "$backup_dir"
done
systemctl is-enabled awoooi-host112-guest-recovery.timer >/dev/null 2>&1 && touch "$backup_dir/timer_was_enabled" || true
systemctl is-active awoooi-host112-guest-recovery.timer >/dev/null 2>&1 && touch "$backup_dir/timer_was_active" || true
install -m 0755 "$READINESS_SOURCE" "$READINESS_TARGET"
install -m 0755 "${SCRIPT_DIR}/install-host112-guest-recovery.sh" "$INSTALLER_TARGET"
install -m 0644 "$SERVICE_SOURCE" "$SERVICE_TARGET"
install -m 0644 "$TIMER_SOURCE" "$TIMER_TARGET"
sudoers_tmp="$(mktemp)"
trap 'rm -f "$sudoers_tmp"' EXIT
printf '%s ALL=(root) NOPASSWD: %s --apply\n' "$TARGET_USER" "$READINESS_TARGET" >"$sudoers_tmp"
visudo -cf "$sudoers_tmp" >/dev/null
install -m 0440 "$sudoers_tmp" "$SUDOERS_TARGET"
install -d -m 0700 -o "$TARGET_USER" -g "$user_group" "$auth_dir"
if [ ! -f "$auth_file" ]; then
install -m 0600 -o "$TARGET_USER" -g "$user_group" /dev/null "$auth_file"
fi
auth_tmp="$(mktemp "${auth_file}.tmp.XXXXXX")"
awk -v blob="$key_blob" 'index($0, blob) == 0 && index($0, "awoooi-host112-probe-110") == 0' "$auth_file" >"$auth_tmp"
printf 'from="%s",restrict,command="%s --check" %s %s awoooi-host112-probe-110\n' \
"$CONTROL_SOURCE_ADDRESS" "$READINESS_TARGET" "$key_type" "$key_blob" >>"$auth_tmp"
chown "$TARGET_USER:$user_group" "$auth_tmp"
chmod 0600 "$auth_tmp"
mv "$auth_tmp" "$auth_file"
systemctl daemon-reload
systemctl enable --now awoooi-host112-guest-recovery.timer >/dev/null
systemctl start awoooi-host112-guest-recovery.service
echo "AWOOOI_HOST112_GUEST_RECOVERY_INSTALLER=1"
echo "MODE=apply"
echo "RUN_ID=$run_id"
echo "BACKUP_DIR=$backup_dir"
echo "CONTROL_KEY_FINGERPRINT=$key_fingerprint"
echo "REBOOT_PERFORMED=0"
echo "SECRET_READ=0"
echo "RESTRICTED_CONTROL_KEY_INSTALLED=1"
check

View File

@@ -22,7 +22,7 @@ HOST_SPECS=(
"99=192.168.0.99:vmware-host-autostart"
"110=wooo@192.168.0.110:awoooi-startup-110.service"
"111=ooo@192.168.0.111:com.momo.ollama111-allow-proxy"
"112=192.168.0.112:vm-host-boot"
"112=kali@192.168.0.112:awoooi-host112-guest-recovery.timer"
"120=wooo@192.168.0.120:k3s.service"
"121=wooo@192.168.0.121:k3s.service"
"188=ollama@192.168.0.188:awoooi-startup.service"
@@ -94,14 +94,19 @@ emit_boot_row() {
local systemd_state="$7"
local enabled="$8"
local active="$9"
local details="${10:-}"
printf 'HOST_BOOT alias=%s target=%s startup_unit=%s reachable=%s boot_id=%s uptime_seconds=%s systemd_state=%s startup_enabled=%s startup_active=%s\n' \
printf 'HOST_BOOT alias=%s target=%s startup_unit=%s reachable=%s boot_id=%s uptime_seconds=%s systemd_state=%s startup_enabled=%s startup_active=%s' \
"$alias" "$target" "$unit" "$reachable" \
"$(escape_value "${boot_id:-unknown}")" \
"$(escape_value "${uptime_seconds:-unknown}")" \
"$(escape_value "${systemd_state:-unknown}")" \
"$(escape_value "${enabled:-unknown}")" \
"$(escape_value "${active:-unknown}")"
if [[ -n "$details" ]]; then
printf ' %s' "$details"
fi
printf '\n'
}
probe_local_host() {
@@ -204,6 +209,39 @@ Write-Output ("boot_id=windows_{0} uptime_seconds={1} systemd_state=windows_ssh
"${systemd_state:-windows_ssh}" "${enabled:-unknown}" "${active:-unknown}"
}
probe_host112_guest() {
local alias="$1"
local target="$2"
local unit="$3"
local output boot_id uptime_seconds systemd_state enabled active
local key value details=""
output="$(
run_with_timeout "$SSH_COMMAND_TIMEOUT_SECONDS" \
ssh "${SSH_OPTS[@]}" "$target" ignored-by-forced-command 2>/dev/null
)"
[[ -n "$output" ]] || return 1
boot_id="$(sed -n 's/.*boot_id=\([^ ]*\).*/\1/p' <<<"$output" | tail -n 1)"
uptime_seconds="$(sed -n 's/.*uptime_seconds=\([^ ]*\).*/\1/p' <<<"$output" | tail -n 1)"
systemd_state="$(sed -n 's/.*systemd_state=\([^ ]*\).*/\1/p' <<<"$output" | tail -n 1)"
enabled="$(sed -n 's/.*startup_enabled=\([^ ]*\).*/\1/p' <<<"$output" | tail -n 1)"
active="$(sed -n 's/.*startup_active=\([^ ]*\).*/\1/p' <<<"$output" | tail -n 1)"
[[ -n "$boot_id" && "$uptime_seconds" =~ ^[0-9]+$ ]] || return 1
for key in \
default_target graphical_target display_manager lightdm vmware_tools xorg \
wazuh_indexer wazuh_manager wazuh_dashboard filebeat console_ready \
services_ready recovery_timer_ready guest_ready action_count actions; do
value="$(sed -n "s/.*${key}=\\([^ ]*\\).*/\\1/p" <<<"$output" | tail -n 1)"
value="$(escape_value "${value:-unknown}")"
details+="${details:+ }${key}=${value}"
done
emit_boot_row "$alias" "$target" "$unit" 1 "$boot_id" "$uptime_seconds" \
"${systemd_state:-unknown}" "${enabled:-unknown}" "${active:-unknown}" "$details"
}
probe_host() {
local alias="$1"
local target="$2"
@@ -221,6 +259,10 @@ probe_host() {
return 0
fi
if [[ "$alias" == "112" ]] && probe_host112_guest "$alias" "$target" "$unit"; then
return 0
fi
if [[ "$target" != *@* ]]; then
if probe_node_exporter "$alias" "$target" "$unit"; then
return 0

View File

@@ -519,6 +519,7 @@ import json, sys
payload = json.load(open(sys.argv[1], encoding="utf-8"))
windows99 = payload.get("windows99_vmware_autostart") or {}
collector = payload.get("windows99_vmware_verify_collector") or {}
host112 = (payload.get("host_boot_detection") or {}).get("host112_guest_readiness") or {}
def label(value: object) -> str:
@@ -534,6 +535,10 @@ def gauge(name: str, value: bool) -> None:
print(f'{name}{{scope="windows99"}} {1 if value else 0}')
def host112_gauge(name: str, value: bool) -> None:
print(f'{name}{{scope="host112"}} {1 if value else 0}')
def int_value(value: object, default: int = -1) -> int:
try:
return int(str(value), 0)
@@ -613,6 +618,17 @@ if collector_present:
f'{{scope="windows99",status="{label(collector_status)}",'
f'safe_next_step="{label(collector_safe_next_step)}"}} 1'
)
host112_gauge(
"awoooi_host112_guest_readback_present",
host112.get("readback_present") is True,
)
host112_gauge("awoooi_host112_console_ready", host112.get("console_ready") is True)
host112_gauge("awoooi_host112_services_ready", host112.get("services_ready") is True)
host112_gauge(
"awoooi_host112_recovery_timer_ready",
host112.get("recovery_timer_ready") is True,
)
host112_gauge("awoooi_host112_guest_ready", host112.get("guest_ready") is True)
PY
)"
active_blocker_metrics="$(python3 - "$scorecard_file" "$TARGET_MINUTES" <<'PY'
@@ -701,6 +717,16 @@ awoooi_public_route_unreachable_without_external_l1_fallback{scope="public_route
# HELP awoooi_public_maintenance_edge_fallback_ready Whether live edge Nginx maintenance fallback config is installed.
# TYPE awoooi_public_maintenance_edge_fallback_ready gauge
awoooi_public_maintenance_edge_fallback_ready{scope="public_routes"} $public_edge_fallback_ready
# HELP awoooi_host112_guest_readback_present Whether host 112 returned its forced-command guest readiness row.
# TYPE awoooi_host112_guest_readback_present gauge
# HELP awoooi_host112_console_ready Whether host 112 graphical target, LightDM, Xorg and VMware Tools are ready.
# TYPE awoooi_host112_console_ready gauge
# HELP awoooi_host112_services_ready Whether the host 112 Wazuh stack and Filebeat are ready.
# TYPE awoooi_host112_services_ready gauge
# HELP awoooi_host112_recovery_timer_ready Whether host 112 bounded recovery timer is enabled and active.
# TYPE awoooi_host112_recovery_timer_ready gauge
# HELP awoooi_host112_guest_ready Whether host 112 guest, console, services and recovery timer are fully ready.
# TYPE awoooi_host112_guest_ready gauge
# HELP awoooi_windows99_vmware_readback_present Whether Windows99 VMware verifier stdout was collected.
# TYPE awoooi_windows99_vmware_readback_present gauge
# HELP awoooi_windows99_vmware_verify_ready Whether Windows99 VMware autostart verifier is fully green.

View File

@@ -155,6 +155,7 @@ def parse_windows99_vmware_readback(text: str) -> dict[str, Any]:
kv = parse_kv(text)
vmx_present: dict[str, bool] = {}
vm_power: dict[str, dict[str, Any]] = {}
vm_processes: dict[str, list[dict[str, Any]]] = {}
services: dict[str, dict[str, Any]] = {}
policies: dict[str, dict[str, Any]] = {}
task: dict[str, Any] = {}
@@ -177,6 +178,24 @@ def parse_windows99_vmware_readback(text: str) -> dict[str, Any]:
"source": match.group(4) or "vmrun",
}
continue
match = re.match(
r"^VM_PROCESS alias=(\S+) present=([01]) process_id=(\S+) "
r"session_id=(\S+) owner=(\S+) interactive_session=([01]) "
r"ui_truth=(\S+)$",
line,
)
if match:
vm_processes.setdefault(match.group(1), []).append(
{
"present": match.group(2) == "1",
"process_id": match.group(3),
"session_id": match.group(4),
"owner": match.group(5),
"interactive_session": match.group(6) == "1",
"ui_truth": match.group(7),
}
)
continue
match = re.match(
r"^VMWARE_SERVICE name=(\S+) present=([01]) status=(\S+) "
r"startup_type=(\S+) ok=([01])$",
@@ -258,6 +277,15 @@ def parse_windows99_vmware_readback(text: str) -> dict[str, Any]:
for alias in required_aliases
if not vm_power.get(alias, {}).get("running")
)
ui_session_isolated_aliases = sorted(
alias
for alias, rows in vm_processes.items()
if any(
row.get("present") is True
and row.get("interactive_session") is not True
for row in rows
)
)
service_blockers = sorted(
name
for name in ("VMAuthdService", "VMnetDHCP")
@@ -328,6 +356,13 @@ def parse_windows99_vmware_readback(text: str) -> dict[str, Any]:
"vmware_services": services,
"windows_update_policy": policies,
"vm_power": vm_power,
"vm_processes": vm_processes,
"ui_session_isolated_aliases": ui_session_isolated_aliases,
"operator_power_truth": (
"trust_vmx_process_and_guest_readiness_not_interactive_vmware_ui"
if ui_session_isolated_aliases
else "vmware_ui_and_runtime_share_interactive_session"
),
"blockers": blockers,
}
@@ -745,6 +780,35 @@ def source_controls() -> dict[str, bool]:
"host_boot_probe_source_present": source_file(
"scripts/reboot-recovery/reboot-auto-recovery-host-probe.sh"
).exists(),
"host_112_guest_readiness_source_present": file_contains(
source_file("scripts/reboot-recovery/host112-guest-readiness.sh"),
"console_ready=",
"services_ready=",
"recovery_timer_ready=",
"guest_ready=",
),
"host_112_guest_recovery_service_source_present": file_contains(
source_file(
"scripts/reboot-recovery/awoooi-host112-guest-recovery.service"
),
"ExecStart=/usr/local/sbin/awoooi-host112-guest-readiness --apply",
"TimeoutStartSec=300",
),
"host_112_guest_recovery_timer_source_present": file_contains(
source_file(
"scripts/reboot-recovery/awoooi-host112-guest-recovery.timer"
),
"OnBootSec=20s",
"OnUnitInactiveSec=60s",
),
"host_112_guest_recovery_installer_source_present": file_contains(
source_file(
"scripts/reboot-recovery/install-host112-guest-recovery.sh"
),
"--rollback",
"restrict,command=",
"visudo -cf",
),
"reboot_event_detector_source_present": source_file(
"scripts/reboot-recovery/reboot-event-detector.py"
).exists(),
@@ -1419,6 +1483,11 @@ def choose_safe_next_step(
"restore_docker_stats_textfile_exporter_then_collect_sanitized_host_"
"pressure_no_restart_no_secret_read"
)
if any(blocker.startswith("host112_") for blocker in blockers):
return (
"run_host112_guest_recovery_controlled_apply_then_verify_forced_command_"
"readback_and_rerun_reboot_scorecard_no_host_reboot"
)
if "windows99_remote_execution_channel_unavailable" in blockers:
return (
"restore_windows99_no_secret_management_channel_or_collect_local_console_"
@@ -1494,6 +1563,9 @@ def build_required_checks(payload: dict[str, Any]) -> dict[str, bool]:
host_boot_detection = payload.get("host_boot_detection")
if not isinstance(host_boot_detection, dict):
host_boot_detection = {}
host112_guest = host_boot_detection.get("host112_guest_readiness")
if not isinstance(host112_guest, dict):
host112_guest = {}
post_reboot_readiness = payload.get("post_reboot_readiness")
if not isinstance(post_reboot_readiness, dict):
post_reboot_readiness = {}
@@ -1522,6 +1594,34 @@ def build_required_checks(payload: dict[str, Any]) -> dict[str, bool]:
"required_hosts_reachable": not strings(
host_boot_detection.get("unreachable_hosts")
),
"host112_guest_readback_present": (
isinstance(host_boot_detection.get("host112_guest_readiness"), dict)
and host_boot_detection.get("host112_guest_readiness", {}).get(
"readback_present"
)
is True
),
"host112_console_ready": (
isinstance(host_boot_detection.get("host112_guest_readiness"), dict)
and host_boot_detection.get("host112_guest_readiness", {}).get(
"console_ready"
)
is True
),
"host112_services_ready": (
isinstance(host_boot_detection.get("host112_guest_readiness"), dict)
and host_boot_detection.get("host112_guest_readiness", {}).get(
"services_ready"
)
is True
),
"host112_guest_ready": (
isinstance(host_boot_detection.get("host112_guest_readiness"), dict)
and host_boot_detection.get("host112_guest_readiness", {}).get(
"guest_ready"
)
is True
),
"windows99_vmware_autostart_ready": (
windows99.get("verify_ready") is True
),
@@ -1583,6 +1683,11 @@ def reboot_sop_current_phase(active_blockers: list[str], can_claim: bool) -> str
"windows99_console_clipboard_unreliable",
"windows99_console_focus_unreliable",
"windows99_console_verify_output_truncated",
"host112_guest_readback_missing",
"host112_console_not_ready",
"host112_services_not_ready",
"host112_recovery_timer_not_ready",
"host112_system_state_not_running",
}
if any(blocker in host_boot_blockers for blocker in active_blockers):
return "host_boot_detection_blocked"
@@ -1627,6 +1732,11 @@ def reboot_sop_primary_blocker(active_blockers: list[str]) -> str:
"all_required_hosts_not_in_10_minute_reboot_window",
"host_boot_observation_older_than_target_window",
"host_uptime_unknown",
"host112_guest_readback_missing",
"host112_console_not_ready",
"host112_services_not_ready",
"host112_recovery_timer_not_ready",
"host112_system_state_not_running",
"windows99_remote_execution_channel_unavailable",
"windows99_vmware_autostart_readback_missing",
"windows99_vmrun_missing",
@@ -1774,7 +1884,34 @@ def active_blocker_action_row(
"force_push_or_ref_delete",
]
if blocker.startswith("windows99_"):
if blocker.startswith("host112_"):
category = "host112_guest_recovery"
owner_lane = "agent99_windows99_and_host112_guest"
severity = "critical"
next_safe_action = (
"run_sudo_n_usr_local_sbin_awoooi_host112_guest_readiness_apply_"
"then_verify_forced_command_readback_no_host_reboot"
)
post_verifier = (
"bash scripts/reboot-recovery/reboot-auto-recovery-host-probe.sh "
"then_rerun_reboot_auto_recovery_slo_scorecard"
)
evidence_inputs = [
"host_boot_detection.host112_guest_readiness",
"host112_guest_recovery_journal",
"host112_last_readback",
]
controlled_apply_mode = "host112_allowlisted_guest_recovery_with_cooldown"
forbidden_actions = [
"host_reboot",
"vm_power_change",
"vm_reset",
"database_write_or_restore",
"secret_value_read",
"firewall_change",
"force_push_or_ref_delete",
]
elif blocker.startswith("windows99_"):
category = "windows99_vmware_autostart"
owner_lane = "windows99_console_or_no_secret_management_channel"
next_safe_action = (
@@ -1985,6 +2122,9 @@ def enrich_machine_readback(payload: dict[str, Any]) -> dict[str, Any]:
host_boot_detection = payload.get("host_boot_detection")
if not isinstance(host_boot_detection, dict):
host_boot_detection = {}
host112_guest = host_boot_detection.get("host112_guest_readiness")
if not isinstance(host112_guest, dict):
host112_guest = {}
post_reboot_readiness = payload.get("post_reboot_readiness")
if not isinstance(post_reboot_readiness, dict):
post_reboot_readiness = {}
@@ -2082,6 +2222,13 @@ def enrich_machine_readback(payload: dict[str, Any]) -> dict[str, Any]:
"unknown_uptime_host_count": len(
strings(host_boot_detection.get("unknown_uptime_hosts"))
),
"host112_guest_readback_present": host112_guest.get("readback_present") is True,
"host112_console_ready": host112_guest.get("console_ready") is True,
"host112_services_ready": host112_guest.get("services_ready") is True,
"host112_recovery_timer_ready": (
host112_guest.get("recovery_timer_ready") is True
),
"host112_guest_ready": host112_guest.get("guest_ready") is True,
"post_start_blocked": int_value(post_reboot_readiness.get("post_start_blocked")),
"service_green": post_reboot_readiness.get("service_green") is True,
"product_data_green": post_reboot_readiness.get("product_data_green") is True,
@@ -2259,6 +2406,11 @@ def enrich_machine_readback(payload: dict[str, Any]) -> dict[str, Any]:
"blocked_by_fresh_reboot_window_only": blocked_by_fresh_reboot_window_only,
"required_checks": required_checks,
"source_controls_present": source_controls_present,
"host112_guest_readback_present": rollups["host112_guest_readback_present"],
"host112_console_ready": rollups["host112_console_ready"],
"host112_services_ready": rollups["host112_services_ready"],
"host112_recovery_timer_ready": rollups["host112_recovery_timer_ready"],
"host112_guest_ready": rollups["host112_guest_ready"],
"windows99_vmware_verify_ready": rollups["windows99_vmware_verify_ready"],
"windows99_update_no_auto_reboot_ready": rollups[
"windows99_update_no_auto_reboot_ready"
@@ -2366,6 +2518,19 @@ def enrich_machine_readback(payload: dict[str, Any]) -> dict[str, Any]:
"reboot_auto_recovery_safe_next_step": readback["safe_next_step"],
"reboot_auto_recovery_next_safe_action": readback["next_safe_action"],
"reboot_auto_recovery_source_controls_present": source_controls_present,
"reboot_auto_recovery_host112_guest_readback_present": rollups[
"host112_guest_readback_present"
],
"reboot_auto_recovery_host112_console_ready": rollups[
"host112_console_ready"
],
"reboot_auto_recovery_host112_services_ready": rollups[
"host112_services_ready"
],
"reboot_auto_recovery_host112_recovery_timer_ready": rollups[
"host112_recovery_timer_ready"
],
"reboot_auto_recovery_host112_guest_ready": rollups["host112_guest_ready"],
"reboot_auto_recovery_windows99_vmware_verify_ready": rollups[
"windows99_vmware_verify_ready"
],
@@ -2450,6 +2615,30 @@ def build_scorecard(args: argparse.Namespace) -> dict[str, Any]:
for row in host_rows
if row.get("reachable") and int_value(row.get("uptime_seconds"), -1) < 0
)
host112_row = next(
(row for row in host_rows if str(row.get("alias")) == "112"), {}
)
host112_guest_readiness = {
"readback_present": "guest_ready" in host112_row,
"reachable": host112_row.get("reachable") is True,
"systemd_state": str(host112_row.get("systemd_state") or "unknown"),
"default_target": str(host112_row.get("default_target") or "unknown"),
"graphical_target": str(host112_row.get("graphical_target") or "unknown"),
"display_manager": str(host112_row.get("display_manager") or "unknown"),
"lightdm": str(host112_row.get("lightdm") or "unknown"),
"vmware_tools": str(host112_row.get("vmware_tools") or "unknown"),
"xorg": str(host112_row.get("xorg") or "unknown"),
"wazuh_indexer": str(host112_row.get("wazuh_indexer") or "unknown"),
"wazuh_manager": str(host112_row.get("wazuh_manager") or "unknown"),
"wazuh_dashboard": str(host112_row.get("wazuh_dashboard") or "unknown"),
"filebeat": str(host112_row.get("filebeat") or "unknown"),
"console_ready": host112_row.get("console_ready") == "1",
"services_ready": host112_row.get("services_ready") == "1",
"recovery_timer_ready": host112_row.get("recovery_timer_ready") == "1",
"guest_ready": host112_row.get("guest_ready") == "1",
"last_action_count": int_value(host112_row.get("action_count"), 0),
"last_actions": str(host112_row.get("actions") or "unknown"),
}
if not host_rows:
blockers.append("all_host_reboot_detection_missing")
if missing_hosts:
@@ -2460,6 +2649,17 @@ def build_scorecard(args: argparse.Namespace) -> dict[str, Any]:
blockers.append("host_boot_observation_older_than_target_window")
if unknown_uptime_hosts:
blockers.append("host_uptime_unknown")
if not host112_guest_readiness["readback_present"]:
blockers.append("host112_guest_readback_missing")
else:
if not host112_guest_readiness["console_ready"]:
blockers.append("host112_console_not_ready")
if not host112_guest_readiness["services_ready"]:
blockers.append("host112_services_not_ready")
if not host112_guest_readiness["recovery_timer_ready"]:
blockers.append("host112_recovery_timer_not_ready")
if host112_guest_readiness["systemd_state"] != "running":
blockers.append("host112_system_state_not_running")
reboot_event_missing_hosts = strings(reboot_event.get("missing_hosts"))
reboot_event_unreachable_hosts = strings(reboot_event.get("unreachable_hosts"))
@@ -2549,6 +2749,7 @@ def build_scorecard(args: argparse.Namespace) -> dict[str, Any]:
"stale_hosts": stale_hosts,
"unknown_uptime_hosts": unknown_uptime_hosts,
"max_observed_uptime_seconds": max_uptime,
"host112_guest_readiness": host112_guest_readiness,
"host_rows": host_rows,
},
"reboot_event_detection": {

View File

@@ -30,7 +30,7 @@ TARGET_HOSTS=99,110,111,112,120,121,188
HOST_BOOT alias=99 target=192.168.0.99 startup_unit=vmware-host-autostart reachable=1 boot_id=aa uptime_seconds=100 systemd_state=windows_exporter startup_enabled=enabled startup_active=active
HOST_BOOT alias=110 target=wooo@192.168.0.110 startup_unit=awoooi-startup-110.service reachable=1 boot_id=a uptime_seconds=120 systemd_state=running startup_enabled=enabled startup_active=active
HOST_BOOT alias=111 target=192.168.0.111 startup_unit=vm-host-boot reachable=1 boot_id=bb uptime_seconds=125 systemd_state=node_exporter startup_enabled=unknown startup_active=unknown
HOST_BOOT alias=112 target=192.168.0.112 startup_unit=vm-host-boot reachable=1 boot_id=cc uptime_seconds=128 systemd_state=node_exporter startup_enabled=unknown startup_active=unknown
HOST_BOOT alias=112 target=kali@192.168.0.112 startup_unit=awoooi-host112-guest-recovery.timer reachable=1 boot_id=cc uptime_seconds=128 systemd_state=running startup_enabled=enabled startup_active=active default_target=graphical.target graphical_target=active display_manager=active lightdm=active vmware_tools=active xorg=active wazuh_indexer=active wazuh_manager=active wazuh_dashboard=active filebeat=active console_ready=1 services_ready=1 recovery_timer_ready=1 guest_ready=1 action_count=0 actions=none
HOST_BOOT alias=120 target=wooo@192.168.0.120 startup_unit=k3s.service reachable=1 boot_id=b uptime_seconds=130 systemd_state=running startup_enabled=enabled startup_active=active
HOST_BOOT alias=121 target=wooo@192.168.0.121 startup_unit=k3s.service reachable=1 boot_id=c uptime_seconds=140 systemd_state=running startup_enabled=enabled startup_active=active
HOST_BOOT alias=188 target=ollama@192.168.0.188 startup_unit=awoooi-startup.service reachable=1 boot_id=d uptime_seconds=150 systemd_state=running startup_enabled=enabled startup_active=active
@@ -86,6 +86,7 @@ VM_POWER alias=188 vmx_present=1 running=1
VM_POWER alias=120 vmx_present=1 running=1
VM_POWER alias=121 vmx_present=1 running=1
VM_POWER alias=112 vmx_present=1 running=1
VM_PROCESS alias=112 present=1 process_id=22288 session_id=0 owner=NT_AUTHORITY\\SYSTEM interactive_session=0 ui_truth=runtime_running_gui_session_isolated
VMWARE_AUTOSTART_CONFIG_READY=1
VMWARE_AUTOSTART_POWER_READY=1
WINDOWS_UPDATE_NO_AUTO_REBOOT_READY=1
@@ -492,6 +493,10 @@ def test_green_summary_and_recent_all_host_probe_can_claim_slo(tmp_path: Path) -
is False
)
assert payload["required_checks"]["windows99_management_channel_ready"] is True
assert payload["required_checks"]["host112_guest_readback_present"] is True
assert payload["required_checks"]["host112_console_ready"] is True
assert payload["required_checks"]["host112_services_ready"] is True
assert payload["required_checks"]["host112_guest_ready"] is True
assert payload["required_checks"]["public_maintenance_fallback_runtime_ready"] is True
assert payload["rollups"]["source_controls_present"] is True
assert payload["rollups"]["public_maintenance_runtime_readback_present"] is True
@@ -522,6 +527,10 @@ def test_green_summary_and_recent_all_host_probe_can_claim_slo(tmp_path: Path) -
"host_110_startup_controlled_drain_guarded_autostart_source_present"
] is True
assert payload["host_boot_detection"]["max_observed_uptime_seconds"] == 150
assert payload["host_boot_detection"]["host112_guest_readiness"]["guest_ready"] is True
assert payload["rollups"]["host112_console_ready"] is True
assert payload["rollups"]["host112_services_ready"] is True
assert payload["readback"]["host112_guest_ready"] is True
assert payload["windows99_vmware_autostart"]["required_vm_aliases"] == [
"111",
"112",
@@ -530,6 +539,12 @@ def test_green_summary_and_recent_all_host_probe_can_claim_slo(tmp_path: Path) -
"188",
]
assert payload["windows99_vmware_autostart"]["verify_ready"] is True
assert payload["windows99_vmware_autostart"]["ui_session_isolated_aliases"] == [
"112"
]
assert payload["windows99_vmware_autostart"]["operator_power_truth"] == (
"trust_vmx_process_and_guest_readiness_not_interactive_vmware_ui"
)
task = payload["windows99_vmware_autostart"]["scheduled_task"]
assert task["principal_user"] == "SYSTEM"
assert task["run_level"] == "Highest"
@@ -549,6 +564,36 @@ def test_green_summary_and_recent_all_host_probe_can_claim_slo(tmp_path: Path) -
] is True
def test_host112_console_gap_blocks_reboot_completion_with_controlled_action(
tmp_path: Path,
) -> None:
probe = HOST_PROBE_GREEN.replace("xorg=active", "xorg=inactive").replace(
"console_ready=1", "console_ready=0"
).replace("guest_ready=1", "guest_ready=0")
payload = run_scorecard(tmp_path, GREEN_SUMMARY, probe=probe)
assert "host112_console_not_ready" in payload["active_blockers"]
assert payload["host_boot_detection"]["host112_guest_readiness"][
"console_ready"
] is False
assert payload["current_phase"] == "host_boot_detection_blocked"
assert payload["safe_next_step"] == (
"run_host112_guest_recovery_controlled_apply_then_verify_forced_command_"
"readback_and_rerun_reboot_scorecard_no_host_reboot"
)
action = next(
item
for item in payload["active_blocker_action_matrix"]["items"]
if item["blocker"] == "host112_console_not_ready"
)
assert action["category"] == "host112_guest_recovery"
assert action["controlled_apply_mode"] == (
"host112_allowlisted_guest_recovery_with_cooldown"
)
assert "host_reboot" in action["forbidden_actions"]
def test_vm_power_provenance_suffix_is_preserved(tmp_path: Path) -> None:
windows99 = "\n".join(
f"{line} source=vmware_vmx_process"

View File

@@ -83,6 +83,29 @@ def test_reboot_p0_contract_covers_all_required_hosts_and_vmware_autostart() ->
assert "systemd_state=windows_ssh" in host_probe
assert '[[ "$boot_id" == windows_* && "$uptime_seconds" =~ ^[0-9]+$ ]]' in host_probe
assert '"111=ooo@192.168.0.111:com.momo.ollama111-allow-proxy"' in host_probe
assert '"112=kali@192.168.0.112:awoooi-host112-guest-recovery.timer"' in host_probe
assert "probe_host112_guest()" in host_probe
for field in ["console_ready", "services_ready", "recovery_timer_ready", "guest_ready"]:
assert field in host_probe
host112_readiness = read("scripts/reboot-recovery/host112-guest-readiness.sh")
host112_installer = read("scripts/reboot-recovery/install-host112-guest-recovery.sh")
host112_service = read(
"scripts/reboot-recovery/awoooi-host112-guest-recovery.service"
)
host112_timer = read("scripts/reboot-recovery/awoooi-host112-guest-recovery.timer")
assert "systemctl set-default graphical.target" in host112_readiness
assert "start_if_inactive lightdm.service" in host112_readiness
assert "start_if_inactive open-vm-tools.service" in host112_readiness
assert "INDEXER_RETRY_COOLDOWN_SECONDS" in host112_readiness
assert "console_ready=$console_ready" in host112_readiness
assert "guest_ready=$guest_ready" in host112_readiness
assert "restrict,command=" in host112_installer
assert "visudo -cf" in host112_installer
assert "--rollback" in host112_installer
assert "ExecStart=/usr/local/sbin/awoooi-host112-guest-readiness --apply" in host112_service
assert "OnBootSec=20s" in host112_timer
assert "OnUnitInactiveSec=60s" in host112_timer
macos_readback = read("scripts/reboot-recovery/macos-host-boot-readback.sh")
macos_installer = read("scripts/reboot-recovery/install-macos111-host-boot-readback.sh")
@@ -135,6 +158,9 @@ def test_reboot_p0_contract_covers_all_required_hosts_and_vmware_autostart() ->
assert "last_task_result" in windows99
assert "start_script_present" in windows99
assert "VMWARE_AUTOSTART_TASK_ACTION" in windows99
assert "Get-VmwareVmxProcessReadback" in windows99
assert "VM_PROCESS alias=$alias" in windows99
assert "runtime_running_gui_session_isolated" in windows99
verify_exit = windows99.index('if ($Mode -eq "Verify")')
apply_start = windows99.index("Write-StartupScript -VmMap $vmMap")
@@ -387,8 +413,17 @@ def test_reboot_slo_scorecard_fails_closed_on_raw_public_502(tmp_path: Path) ->
host_probe = tmp_path / "host-probe.txt"
host_probe.write_text(
"\n".join(
f"HOST_BOOT alias={alias} host=192.168.0.{alias} reachable=1 uptime_seconds=120"
for alias in ["99", "110", "111", "112", "120", "121", "188"]
[
f"HOST_BOOT alias={alias} host=192.168.0.{alias} reachable=1 uptime_seconds=120"
for alias in ["99", "110", "111", "120", "121", "188"]
]
+ [
"HOST_BOOT alias=112 host=192.168.0.112 reachable=1 uptime_seconds=120 "
"systemd_state=running default_target=graphical.target graphical_target=active "
"display_manager=active lightdm=active vmware_tools=active xorg=active "
"wazuh_indexer=active wazuh_manager=active wazuh_dashboard=active filebeat=active "
"console_ready=1 services_ready=1 recovery_timer_ready=1 guest_ready=1"
]
),
encoding="utf-8",
)

View File

@@ -187,6 +187,51 @@ function Get-VmwareVmxProcessCommandLines {
}
}
function Get-VmwareVmxProcessReadback {
param([hashtable]$VmMap)
$processes = @()
try {
$processes = @(Get-CimInstance -ClassName Win32_Process -Filter "Name='vmware-vmx.exe'" -ErrorAction SilentlyContinue)
} catch {
$processes = @()
}
foreach ($alias in $VmOrder) {
$path = "$($VmMap[$alias])"
$matches = @($processes | Where-Object {
$commandLine = [string]$_.CommandLine
$path -and $commandLine -and $commandLine.IndexOf($path, [StringComparison]::OrdinalIgnoreCase) -ge 0
})
if ($matches.Count -eq 0) {
Write-Output "VM_PROCESS alias=$alias present=0 process_id=unknown session_id=unknown owner=unknown interactive_session=0 ui_truth=not_running"
continue
}
foreach ($process in $matches) {
$owner = "unknown"
try {
$ownerResult = Invoke-CimMethod -InputObject $process -MethodName GetOwner -ErrorAction SilentlyContinue
if ($ownerResult -and $ownerResult.ReturnValue -eq 0 -and $ownerResult.User) {
$owner = if ($ownerResult.Domain) {
"$($ownerResult.Domain)\$($ownerResult.User)"
} else {
"$($ownerResult.User)"
}
}
} catch {
$owner = "unknown"
}
$sessionId = if ($null -ne $process.SessionId) { [int]$process.SessionId } else { -1 }
$interactiveSession = [int]($sessionId -gt 0)
$uiTruth = if ($interactiveSession -eq 1) {
"runtime_running_interactive_session"
} else {
"runtime_running_gui_session_isolated"
}
Write-Output "VM_PROCESS alias=$alias present=1 process_id=$($process.ProcessId) session_id=$sessionId owner=$(Format-ReadbackValue $owner) interactive_session=$interactiveSession ui_truth=$uiTruth"
}
}
}
function Get-VmxRunningSource {
param(
[string]$VmxPath,
@@ -350,6 +395,7 @@ Get-VmwareServiceReadback
Get-AutostartTaskReadback
Get-WindowsUpdatePolicyReadback
Get-VmPowerReadback -VmMap $vmMap
Get-VmwareVmxProcessReadback -VmMap $vmMap
$serviceReady = @("VMAuthdService", "VMnetDHCP") | ForEach-Object {
$svc = Get-Service -Name $_ -ErrorAction SilentlyContinue