Visual Indicators adds custom columns, user commands, and batched helper-backed checks.
It currently includes five columns:
V1
๐Alias๐FavoriteโจSmart Favorite๐ฃ๏ธFolder is in effectivePATHโขSymbolic linkโขJunctionโGeneric reparse point
V2
Cheap local checks and a batched Python helper for mark of the web (MOTW)
Default-on combo markers:
๐งชInternet/Restricted MOTW + macro-capable / legacy active Office fileโฃ๏ธInternet/Restricted MOTW + directly executable or scriptable file๐ชคInternet/Restricted MOTW + indirect launcher (.lnk,.url)๐งณInternet/Restricted MOTW + archive/container
Optional standalone indicators:
๐MOTW Internet (ZoneId=3)โMOTW Restricted (ZoneId=4)โMacro-capable / legacy active Office fileโ๏ธExecutable or scriptable file type๐ฆArchive/container file type๐Hidden๐ก๏ธSystem๐Encrypted๐๏ธCompressedโ๏ธRead-onlyโ๏ธOffline๐Recall on open๐Recall on data access๐ญDeceptive filenameโ๏ธ๐ซMOTW probe skipped because the file is a cloud placeholder / recall file?Probe failed / unknown state
V3
V3 heavier column. It currently checks Windows Authenticode trust status using a Python helper.
Default indicators:
โValid trusted signatureโชUnsignedโSigned but expired๐ซRevokedโ ๏ธUntrusted / chain-invalidโInvalid / tampered / otherwise badโSignature-check error๐งฉPlaceholder, if enabled
V3Publisher
V3Publisher is a text column that shows the extracted publisher name for signed files when available.
V4 Sandbox
If you use Sandboxie and have pointed to 'sandboxie.ini' in the script configuration menu, this column will predict with reasonable accuracy which sandbox the file/program will be launched in.
Current commands
Alias / Favorite / PATH
Alias.AddSelectedโ Add alias for selected itemsAlias.RemoveSelectedโ Remove aliases pointing to selected itemsFavorite.AddSelectedโ Add selected items as favoritesFavorite.RemoveSelectedโ Remove favorites pointing to selected itemsPath.AddToโ Add selected folders toPATHPath.Removeโ Remove selected folders fromPATHAlias.Debugโ Show alias andPATHdebug info for the current selection
MOTW / V2
MOTW.RefreshVisibleโ Refresh MOTW state for visible files in the current tabMOTW.ClearCacheโ Clear cached MOTW stateMOTW.AddSelectedโ Add MOTW to selected file(s) by writingZone.IdentifierMOTW.RemoveSelectedโ Remove MOTW from selected file(s) by deletingZone.Identifier
V3
V3.RefreshVisibleโ Refresh V3 signature status for visible files in the current tabV3.ClearCacheโ Clear cached V3 signature state
Helpers
This script uses two external helpers for the non-trivial batched checks. You must point the script at each of these helpers in the script's configuration menu.
MOTW helper
Used by V2.
Default path:
C:\Utilities\lock_check.py
Purpose:
- batched MOTW detection through
Zone.Identifier - returns cached
motwState+zoneId
Signature helper
Used by V3.
Default path:
C:\Utilities\signature_check.py
Purpose:
- batched Authenticode trust checks
- returns cached signature status
- extracts publisher text when possible
Both helpers use the configured Python runtime:
PythonExe
Default:
python.exe
In most circumstances, you will need to point the script to "python.exe" on your system. This can be done in the script configuration menu.
Button to Toggle Columns
Set COLUMNSTOGGLE="scp:VisualIndicators/V1(8)"
Set COLUMNSTOGGLE="scp:VisualIndicators/V2(9)"
Set COLUMNSTOGGLE="scp:VisualIndicators/V3(10)"
Set COLUMNSTOGGLE="scp:VisualIndicators/V3Publisher(11)"
Set COLUMNSTOGGLE="scp:VisualIndicators/V4(12)"
Signature_check.py
#!/usr/bin/env python3
# C:\Utilities\signature_check.py
#
# Python Windows signature checker for Directory Opus V3.
# Uses WinVerifyTrust via ctypes and extracts a display publisher name via CryptQueryObject.
from __future__ import annotations
import ctypes
from ctypes import wintypes
import datetime as dt
import os
import sys
import traceback
LOG_PATH = r"C:\Utilities\signature_check.log"
DIRECT_HUMAN_OUTPUT = r"C:\Utilities\signature_test_output.txt"
DIRECT_BATCHLIKE_OUTPUT = r"C:\Utilities\signature_check_output.txt"
VERBOSE_LOG = False
_LOG_BUFFER: list[str] = []
def _append_log(msg: str) -> None:
ts = dt.datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f")[:-3]
_LOG_BUFFER.append(f"[{ts}] {msg}")
def log(msg: str) -> None:
_append_log(msg)
def log_verbose(msg: str) -> None:
if VERBOSE_LOG:
_append_log(msg)
def log_exception(prefix: str) -> None:
try:
_append_log(prefix)
_append_log(traceback.format_exc().rstrip())
except Exception:
pass
def flush_logs() -> None:
if not _LOG_BUFFER:
return
try:
parent = os.path.dirname(LOG_PATH)
if parent:
os.makedirs(parent, exist_ok=True)
with open(LOG_PATH, "a", encoding="utf-8", newline="\n") as f:
f.write("\n".join(_LOG_BUFFER))
f.write("\n")
except Exception:
pass
def ensure_parent_dir(path: str) -> None:
parent = os.path.dirname(path)
if parent:
os.makedirs(parent, exist_ok=True)
def sanitize_field(text: str) -> str:
return (text or "").replace("\r", " ").replace("\n", " ").replace("|", "/").strip()
def safe_get_full_path(path: str) -> str:
try:
return os.path.abspath(path)
except Exception as ex:
log(f"safe_get_full_path failed for {path!r}: {ex!r}")
return path
def decode_text_best_effort(raw: bytes) -> str:
for encoding in ("utf-8-sig", "utf-16", "utf-16-le", "utf-16-be", "cp1252", "latin-1"):
try:
return raw.decode(encoding)
except UnicodeDecodeError:
continue
return raw.decode("latin-1", errors="replace")
def read_input_paths(input_file: str) -> list[str]:
with open(input_file, "rb") as f:
raw = f.read()
text = decode_text_best_effort(raw)
paths: list[str] = []
seen: set[str] = set()
for raw_line in text.splitlines():
line = raw_line.rstrip("\r\n")
if not line.strip():
continue
norm = os.path.normcase(safe_get_full_path(line))
if norm in seen:
log_verbose(f"Skipped duplicate path: {line}")
continue
seen.add(norm)
paths.append(line)
log_verbose(f"Queued path: {line}")
return paths
def write_text_file(path: str, lines: list[str], encoding: str = "utf-16") -> None:
ensure_parent_dir(path)
with open(path, "w", encoding=encoding, newline="\n") as f:
for line in lines:
f.write(line + "\n")
def is_list_file(path: str) -> bool:
ext = os.path.splitext(path)[1].lower()
return ext in {".txt", ".lst", ".csv"}
# ---- WinVerifyTrust via ctypes ----
WTD_UI_NONE = 2
WTD_REVOKE_NONE = 0
WTD_CHOICE_FILE = 1
WTD_STATEACTION_VERIFY = 1
WTD_STATEACTION_CLOSE = 2
WTD_REVOCATION_CHECK_NONE = 0x00000010
WTD_CACHE_ONLY_URL_RETRIEVAL = 0x00000004
# HRESULT / WinVerifyTrust values
TRUST_E_NOSIGNATURE = ctypes.c_long(0x800B0100).value
TRUST_E_SUBJECT_FORM_UNKNOWN = ctypes.c_long(0x800B0003).value
TRUST_E_PROVIDER_UNKNOWN = ctypes.c_long(0x800B0001).value
CERT_E_EXPIRED = ctypes.c_long(0x800B0101).value
CERT_E_UNTRUSTEDROOT = ctypes.c_long(0x800B0109).value
CERT_E_CHAINING = ctypes.c_long(0x800B010A).value
CERT_E_REVOKED = ctypes.c_long(0x800B010C).value
CERT_E_REVOCATION_FAILURE = ctypes.c_long(0x800B010E).value
TRUST_E_EXPLICIT_DISTRUST = ctypes.c_long(0x800B0111).value
TRUST_E_BAD_DIGEST = ctypes.c_long(0x80096010).value
CRYPT_E_SECURITY_SETTINGS = ctypes.c_long(0x80092026).value
_UNSIGNED = {
TRUST_E_NOSIGNATURE,
TRUST_E_SUBJECT_FORM_UNKNOWN,
TRUST_E_PROVIDER_UNKNOWN,
}
_UNTRUSTED = {
CERT_E_UNTRUSTEDROOT,
CERT_E_CHAINING,
CERT_E_REVOCATION_FAILURE,
TRUST_E_EXPLICIT_DISTRUST,
CRYPT_E_SECURITY_SETTINGS,
}
class GUID(ctypes.Structure):
_fields_ = [
("Data1", wintypes.DWORD),
("Data2", wintypes.WORD),
("Data3", wintypes.WORD),
("Data4", ctypes.c_ubyte * 8),
]
WINTRUST_ACTION_GENERIC_VERIFY_V2 = GUID(
0x00AAC56B,
0xCD44,
0x11D0,
(ctypes.c_ubyte * 8)(0x8C, 0xC2, 0x00, 0xC0, 0x4F, 0xC2, 0x95, 0xEE),
)
class WINTRUST_FILE_INFO(ctypes.Structure):
_fields_ = [
("cbStruct", wintypes.DWORD),
("pcwszFilePath", wintypes.LPCWSTR),
("hFile", wintypes.HANDLE),
("pgKnownSubject", ctypes.c_void_p),
]
class WINTRUST_DATA(ctypes.Structure):
_fields_ = [
("cbStruct", wintypes.DWORD),
("pPolicyCallbackData", ctypes.c_void_p),
("pSIPClientData", ctypes.c_void_p),
("dwUIChoice", wintypes.DWORD),
("fdwRevocationChecks", wintypes.DWORD),
("dwUnionChoice", wintypes.DWORD),
("pFile", ctypes.POINTER(WINTRUST_FILE_INFO)),
("dwStateAction", wintypes.DWORD),
("hWVTStateData", wintypes.HANDLE),
("pwszURLReference", wintypes.LPCWSTR),
("dwProvFlags", wintypes.DWORD),
("dwUIContext", wintypes.DWORD),
("pSignatureSettings", ctypes.c_void_p),
]
# ---- Certificate publisher extraction via CryptQueryObject ----
CERT_QUERY_OBJECT_FILE = 1
CERT_QUERY_CONTENT_FLAG_ALL = 0x00003FFE
CERT_QUERY_FORMAT_FLAG_ALL = 0x0000000E
CERT_NAME_SIMPLE_DISPLAY_TYPE = 4
CERT_CLOSE_STORE_FORCE_FLAG = 0x00000001
crypt32 = ctypes.WinDLL("crypt32")
wintrust = ctypes.WinDLL("wintrust")
WinVerifyTrust = wintrust.WinVerifyTrust
WinVerifyTrust.argtypes = [wintypes.HWND, ctypes.POINTER(GUID), ctypes.POINTER(WINTRUST_DATA)]
WinVerifyTrust.restype = wintypes.LONG
CryptQueryObject = crypt32.CryptQueryObject
CryptQueryObject.argtypes = [
wintypes.DWORD,
ctypes.c_void_p,
wintypes.DWORD,
wintypes.DWORD,
wintypes.DWORD,
ctypes.POINTER(wintypes.DWORD),
ctypes.POINTER(wintypes.DWORD),
ctypes.POINTER(wintypes.DWORD),
ctypes.POINTER(ctypes.c_void_p),
ctypes.POINTER(ctypes.c_void_p),
ctypes.POINTER(ctypes.c_void_p),
]
CryptQueryObject.restype = wintypes.BOOL
CertEnumCertificatesInStore = crypt32.CertEnumCertificatesInStore
CertEnumCertificatesInStore.argtypes = [ctypes.c_void_p, ctypes.c_void_p]
CertEnumCertificatesInStore.restype = ctypes.c_void_p
CertGetNameStringW = crypt32.CertGetNameStringW
CertGetNameStringW.argtypes = [ctypes.c_void_p, wintypes.DWORD, wintypes.DWORD, ctypes.c_void_p, wintypes.LPWSTR, wintypes.DWORD]
CertGetNameStringW.restype = wintypes.DWORD
CertFreeCertificateContext = crypt32.CertFreeCertificateContext
CertFreeCertificateContext.argtypes = [ctypes.c_void_p]
CertFreeCertificateContext.restype = wintypes.BOOL
CertCloseStore = crypt32.CertCloseStore
CertCloseStore.argtypes = [ctypes.c_void_p, wintypes.DWORD]
CertCloseStore.restype = wintypes.BOOL
CryptMsgClose = crypt32.CryptMsgClose
CryptMsgClose.argtypes = [ctypes.c_void_p]
CryptMsgClose.restype = wintypes.BOOL
def hresult_hex(value: int) -> str:
return f"0x{ctypes.c_uint32(value).value:08X}"
def classify_signature_status(code: int) -> str:
if code == 0:
return "valid"
if code in _UNSIGNED:
return "unsigned"
if code == CERT_E_EXPIRED:
return "expired"
if code == CERT_E_REVOKED:
return "revoked"
if code in _UNTRUSTED:
return "untrusted"
if code == TRUST_E_BAD_DIGEST:
return "bad"
return "bad"
def extract_publisher_from_signed_file(full_path: str) -> str:
encoding = wintypes.DWORD()
content_type = wintypes.DWORD()
format_type = wintypes.DWORD()
cert_store = ctypes.c_void_p()
crypt_msg = ctypes.c_void_p()
context = ctypes.c_void_p()
try:
ok = CryptQueryObject(
CERT_QUERY_OBJECT_FILE,
ctypes.c_wchar_p(full_path),
CERT_QUERY_CONTENT_FLAG_ALL,
CERT_QUERY_FORMAT_FLAG_ALL,
0,
ctypes.byref(encoding),
ctypes.byref(content_type),
ctypes.byref(format_type),
ctypes.byref(cert_store),
ctypes.byref(crypt_msg),
ctypes.byref(context),
)
if not ok:
return ""
cert_ctx = CertEnumCertificatesInStore(cert_store, None)
while cert_ctx:
needed = CertGetNameStringW(cert_ctx, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0, None, None, 0)
if needed and needed > 1:
buf = ctypes.create_unicode_buffer(needed)
CertGetNameStringW(cert_ctx, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0, None, buf, needed)
name = buf.value.strip()
if name:
return name
cert_ctx = CertEnumCertificatesInStore(cert_store, cert_ctx)
return ""
except Exception:
log_exception(f"extract_publisher_from_signed_file exception for {full_path!r}")
return ""
finally:
try:
if context:
CertFreeCertificateContext(context)
except Exception:
pass
try:
if crypt_msg:
CryptMsgClose(crypt_msg)
except Exception:
pass
try:
if cert_store:
CertCloseStore(cert_store, CERT_CLOSE_STORE_FORCE_FLAG)
except Exception:
pass
def verify_signature_wintrust(full_path: str) -> tuple[str, str]:
file_info = WINTRUST_FILE_INFO()
file_info.cbStruct = ctypes.sizeof(WINTRUST_FILE_INFO)
file_info.pcwszFilePath = full_path
file_info.hFile = None
file_info.pgKnownSubject = None
data = WINTRUST_DATA()
data.cbStruct = ctypes.sizeof(WINTRUST_DATA)
data.pPolicyCallbackData = None
data.pSIPClientData = None
data.dwUIChoice = WTD_UI_NONE
data.fdwRevocationChecks = WTD_REVOKE_NONE
data.dwUnionChoice = WTD_CHOICE_FILE
data.pFile = ctypes.pointer(file_info)
data.dwStateAction = WTD_STATEACTION_VERIFY
data.hWVTStateData = None
data.pwszURLReference = None
data.dwProvFlags = WTD_REVOCATION_CHECK_NONE | WTD_CACHE_ONLY_URL_RETRIEVAL
data.dwUIContext = 0
data.pSignatureSettings = None
try:
status = WinVerifyTrust(None, ctypes.byref(WINTRUST_ACTION_GENERIC_VERIFY_V2), ctypes.byref(data))
log_verbose(f"WinVerifyTrust result for {full_path!r}: {hresult_hex(status)}")
return classify_signature_status(status), hresult_hex(status)
except Exception:
log_exception(f"verify_signature_wintrust exception for {full_path!r}")
return "error", "exception"
finally:
try:
data.dwStateAction = WTD_STATEACTION_CLOSE
WinVerifyTrust(None, ctypes.byref(WINTRUST_ACTION_GENERIC_VERIFY_V2), ctypes.byref(data))
except Exception:
pass
def signature_row_for_path(original_path: str) -> tuple[str, str, str, str]:
full_path = safe_get_full_path(original_path)
if not full_path or not os.path.exists(full_path):
log(f"Path does not exist: {original_path!r}")
return (original_path, "error", "", "missing")
if os.path.isdir(full_path):
log_verbose(f"Skipping directory: {full_path!r}")
return (original_path, "error", "", "directory")
status, detail = verify_signature_wintrust(full_path)
publisher = ""
if status != "unsigned" and status != "error":
publisher = extract_publisher_from_signed_file(full_path)
log_verbose(f"Signature result: path={full_path} | status={status} | publisher={publisher} | detail={detail}")
return (full_path, status, publisher, detail)
def write_direct_reports(target_path: str, status: str, publisher: str, detail: str) -> None:
human = [
f"File: {target_path}",
f"Status: {status}",
f"Detail: {detail}",
f"Publisher: {publisher}",
]
write_text_file(DIRECT_HUMAN_OUTPUT, human, encoding="utf-8")
log(f"Wrote human-readable direct report: {DIRECT_HUMAN_OUTPUT}")
batchlike = [f"{sanitize_field(target_path)}|{sanitize_field(status)}|{sanitize_field(publisher)}|{sanitize_field(detail)}"]
write_text_file(DIRECT_BATCHLIKE_OUTPUT, batchlike, encoding="utf-16")
log(f"Wrote batch-style direct report: {DIRECT_BATCHLIKE_OUTPUT}")
def main() -> int:
args = sys.argv[1:]
try:
log("----- signature_check.py start -----")
log(f"argv={sys.argv!r}")
log(f"python={sys.executable!r}")
log(f"cwd={os.getcwd()!r}")
if not args:
log("No arguments supplied.")
return 1
input_path = args[0]
output_path = args[1] if len(args) > 1 else ""
input_full = safe_get_full_path(input_path)
direct_mode = not is_list_file(input_full)
if direct_mode:
log("Mode=direct")
original, status, publisher, detail = signature_row_for_path(input_path)
write_direct_reports(original, status, publisher, detail)
if not output_path:
output_path = DIRECT_BATCHLIKE_OUTPUT
rows = [f"{sanitize_field(original)}|{sanitize_field(status)}|{sanitize_field(publisher)}|{sanitize_field(detail)}"]
write_text_file(output_path, rows, encoding="utf-16")
log(f"Wrote output file: {output_path}")
log("----- signature_check.py success -----")
return 0
log("Mode=batch")
if not output_path:
output_path = os.path.join(r"C:\Utilities", "signature_check_batch_output.txt")
if not os.path.exists(input_full):
log(f"Input list file does not exist: {input_full}")
write_text_file(output_path, [], encoding="utf-16")
return 0
paths = read_input_paths(input_full)
log(f"Unique queued path count: {len(paths)}")
rows: list[str] = []
for path in paths:
original, status, publisher, detail = signature_row_for_path(path)
rows.append(f"{sanitize_field(original)}|{sanitize_field(status)}|{sanitize_field(publisher)}|{sanitize_field(detail)}")
write_text_file(output_path, rows, encoding="utf-16")
log(f"Wrote output file: {output_path}")
log(f"Output row count: {len(rows)}")
log("----- signature_check.py success -----")
return 0
except Exception:
log_exception("Top-level failure")
try:
out = args[1] if len(args) > 1 else os.path.join(r"C:\Utilities", "signature_check_batch_output.txt")
write_text_file(out, [], encoding="utf-16")
log(f"Wrote empty fallback output file: {out}")
except Exception:
log_exception("Failed to write fallback output file")
return 0
finally:
flush_logs()
if __name__ == "__main__":
sys.exit(main())
lock_check.py
#!/usr/bin/env python3
# C:\Utilities\lock_check.py
#
# Batched MOTW checker for Directory Opus
#
# Usage:
# python lock_check.py "C:\Temp\motw_input.txt" "C:\Temp\motw_output.txt"
#
# Output format:
# <full-path>|<motw-state>|<zone id>
from __future__ import annotations
import datetime as dt
import os
import re
import sys
import traceback
LOG_PATH = r"C:\Utilities\lock_check.log"
VERBOSE_LOG = False
MAX_ADS_READ = 4096
ABSENT_ADS_WINERRORS = {2, 3}
ZONE_ID_RE = re.compile(r"(?im)^\s*ZoneId\s*=\s*(\d+)\s*$")
_LOG_BUFFER: list[str] = []
def _append_log(msg: str) -> None:
ts = dt.datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f")[:-3]
_LOG_BUFFER.append(f"[{ts}] {msg}")
def log(msg: str) -> None:
if VERBOSE_LOG:
_append_log(msg)a
def log_force(msg: str) -> None:
_append_log(msg)
def log_exception(prefix: str) -> None:
try:
_append_log(prefix)
_append_log(traceback.format_exc().rstrip())
except Exception:
pass
def flush_logs() -> None:
if not _LOG_BUFFER:
return
try:
parent = os.path.dirname(LOG_PATH)
if parent:
os.makedirs(parent, exist_ok=True)
with open(LOG_PATH, "a", encoding="utf-8", newline="\n") as f:
f.write("\n".join(_LOG_BUFFER))
f.write("\n")
except Exception:
pass
def ensure_parent_dir(path: str) -> None:
parent = os.path.dirname(path)
if parent:
os.makedirs(parent, exist_ok=True)
def sanitize_field(text: str) -> str:
return (text or "").replace("\r", " ").replace("\n", " ").replace("|", "/").strip()
def dedupe_paths_preserve_order(paths: list[str]) -> list[str]:
seen: set[str] = set()
out: list[str] = []
for path in paths:
key = os.path.normcase(os.path.abspath(path)) if path else ""
if key in seen:
continue
seen.add(key)
out.append(path)
return out
def decode_text_best_effort(raw: bytes) -> str:
for encoding in ("utf-8-sig", "utf-16", "utf-16-le", "utf-16-be", "cp1252", "latin-1"):
try:
return raw.decode(encoding)
except UnicodeDecodeError:
continue
return raw.decode("latin-1", errors="replace")
def read_input_paths(input_file: str) -> list[str]:
with open(input_file, "rb") as f:
raw = f.read()
if raw.startswith((b"\xff\xfe", b"\xfe\xff")):
text = raw.decode("utf-16")
elif raw.startswith(b"\xef\xbb\xbf"):
text = raw.decode("utf-8-sig")
else:
try:
text = raw.decode("utf-8")
except UnicodeDecodeError:
text = raw.decode("utf-16")
paths: list[str] = []
for raw_line in text.splitlines():
line = raw_line.rstrip("\r\n")
if not line.strip():
continue
paths.append(line)
return dedupe_paths_preserve_order(paths)
def write_output_lines(output_file: str, lines: list[str]) -> None:
ensure_parent_dir(output_file)
with open(output_file, "w", encoding="utf-16", newline="\n") as f:
for line in lines:
f.write(line + "\n")
def preprocess_path(path: str) -> tuple[str, str, bool]:
original = path or ""
if not original:
return original, "", False
abs_path = os.path.abspath(original)
try:
if not os.path.exists(abs_path):
return original, abs_path, False
if os.path.isdir(abs_path):
return original, abs_path, False
except Exception:
return original, abs_path, False
return original, abs_path, True
def probe_motw_abs(abs_path: str) -> tuple[str, str]:
ads_path = abs_path + ":Zone.Identifier"
try:
with open(ads_path, "rb") as f:
raw = f.read(MAX_ADS_READ)
text = decode_text_best_effort(raw)
zone_match = ZONE_ID_RE.search(text)
zone_id = zone_match.group(1) if zone_match else ""
return "1", zone_id
except FileNotFoundError:
return "0", ""
except OSError as ex:
if getattr(ex, "winerror", None) in ABSENT_ADS_WINERRORS:
return "0", ""
log_force(f"probe_motw_abs OSError for {ads_path!r}: {ex!r}")
return "?", ""
except Exception:
log_exception(f"probe_motw_abs exception for {ads_path!r}")
return "?", ""
def main() -> int:
total_paths = 0
probed_paths = 0
try:
if len(sys.argv) != 3:
log_force("Invalid argument count. Expected: input_file output_file")
return 1
input_file = sys.argv[1]
output_file = sys.argv[2]
paths = read_input_paths(input_file)
total_paths = len(paths)
out_lines: list[str] = []
for path in paths:
original_path, abs_path, probeable = preprocess_path(path)
if not probeable:
out_lines.append("|".join([sanitize_field(original_path), "0", ""]))
continue
probed_paths += 1
motw_state, zone_id = probe_motw_abs(abs_path)
out_lines.append("|".join([sanitize_field(original_path), motw_state, sanitize_field(zone_id)]))
write_output_lines(output_file, out_lines)
log_force(f"Processed {total_paths} input paths; probed {probed_paths} files; wrote {len(out_lines)} lines.")
return 0
except Exception:
log_exception("Fatal error in main")
return 1
finally:
flush_logs()
if __name__ == "__main__":
sys.exit(main())
Visual_Indicators.opusscriptinstall (22.8 KB)


