Visual Indicators adds custom columns and user commands
It currently includes five columns:
V1
πAliasπFavoriteβ¨Smart Favoriteπ£οΈFolder is in effectivePATH
V2
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
V3
`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
Prompts to create a single helper script in place. Code provided below for reference.
#!/usr/bin/env python3
"""Visual Indicators helper v1.1.0.
Usage: python visual_indicators_helper_v1.1.0.py --mode motw INPUT OUTPUT
python visual_indicators_helper_v1.1.0.py --mode signature INPUT OUTPUT
One standalone file; uses Python's standard library. Signature mode requires Windows.
"""
from __future__ import annotations
import time
_SCRIPT_START = time.perf_counter()
import json
import os
import re
import stat
import sys
VERSION = "1.1.0"
LOG_PATH = os.path.join(os.path.dirname(os.path.abspath(__file__)), "motw_check.log")
ZONE = re.compile(r"(?im)^\s*ZoneId\s*=\s*(\d+)\s*$")
CLOUD_FLAGS = (getattr(stat, "FILE_ATTRIBUTE_OFFLINE", 0x1000)
| getattr(stat, "FILE_ATTRIBUTE_RECALL_ON_OPEN", 0x40000)
| getattr(stat, "FILE_ATTRIBUTE_RECALL_ON_DATA_ACCESS", 0x400000))
def decode_text(raw: bytes) -> str:
if raw.startswith((b"\xff\xfe", b"\xfe\xff")):
return raw.decode("utf-16")
if b"\x00" in raw:
encoding = "utf-16-be" if raw.startswith(b"\x00") else "utf-16-le"
return raw.decode(encoding)
try:
return raw.decode("utf-8-sig")
except UnicodeDecodeError:
return raw.decode("cp1252", errors="replace")
def probe_motw(path: str) -> tuple[str, str]:
try:
info = os.stat(path)
if stat.S_ISDIR(info.st_mode):
return "0", ""
if getattr(info, "st_file_attributes", 0) & CLOUD_FLAGS:
return "?", "" # Do not recall cloud-only files.
try:
with open(path + ":Zone.Identifier", "rb") as stream:
raw = stream.read(65536)
except FileNotFoundError:
return "0", ""
match = ZONE.search(decode_text(raw))
return "1", match.group(1) if match else ""
except (OSError, ValueError, UnicodeError):
return "?", ""
def run_motw(args: list[str] | None = None) -> int:
args = sys.argv[1:] if args is None else args
metrics = {"version": VERSION, "initialisation_ms": round((time.perf_counter() - _SCRIPT_START) * 1000, 3)}
phase = "arguments"
try:
if len(args) != 2:
raise ValueError("Expected INPUT_LIST OUTPUT_FILE")
input_path, output_path = args
phase = "input"
started = time.perf_counter()
with open(input_path, "rb") as source:
paths = [p for p in decode_text(source.read()).splitlines() if p.strip()]
if any("|" in p or "\x00" in p for p in paths):
raise ValueError("Input path contains an unsupported delimiter")
metrics["input_ms"] = round((time.perf_counter() - started) * 1000, 3)
phase = "probing"
rows = []
counts = {"present": 0, "absent": 0, "unknown": 0}
longest = 0.0
started = time.perf_counter()
for path in paths:
probe_started = time.perf_counter()
state, zone = probe_motw(path)
longest = max(longest, (time.perf_counter() - probe_started) * 1000)
counts[{"1": "present", "0": "absent", "?": "unknown"}[state]] += 1
rows.append("|".join((path, state, zone)))
metrics.update(counts)
metrics["files"] = len(paths)
metrics["probe_ms"] = round((time.perf_counter() - started) * 1000, 3)
metrics["slowest_probe_ms"] = round(longest, 3)
phase = "output"
started = time.perf_counter()
with open(output_path, "w", encoding="utf-16", newline="\n") as target:
target.write("".join(row + "\n" for row in rows))
metrics["output_ms"] = round((time.perf_counter() - started) * 1000, 3)
metrics["status"] = "ok"
return 0
except Exception as error:
metrics.update(status="error", phase=phase, error=str(error))
return 1
finally:
metrics["script_ms_before_log"] = round((time.perf_counter() - _SCRIPT_START) * 1000, 3)
metrics["timestamp"] = time.strftime("%Y-%m-%d %H:%M:%S")
# Excludes interpreter startup before this module and this final log write.
try:
with open(LOG_PATH, "a", encoding="utf-8") as target:
target.write(json.dumps(metrics, ensure_ascii=True) + "\n")
except OSError:
pass
def run_signature(arguments: list[str]) -> int:
# Initialise Windows signature libraries only for signature requests.
import ctypes
from ctypes import wintypes
import datetime as dt
import os
import sys
import traceback
LOG_PATH = os.path.join(os.path.dirname(os.path.abspath(__file__)), "signature_check.log")
DIRECT_HUMAN_OUTPUT = os.path.join(os.path.dirname(LOG_PATH), "signature_test_output.txt")
DIRECT_BATCHLIKE_OUTPUT = os.path.join(os.path.dirname(LOG_PATH), "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 = arguments
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(os.path.dirname(LOG_PATH), "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(os.path.dirname(LOG_PATH), "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()
return main()
def main(args: list[str] | None = None) -> int:
args = sys.argv[1:] if args is None else args
if len(args) != 4 or args[0] != "--mode" or args[1] not in ("motw", "signature"):
print("Usage: helper.py --mode motw|signature INPUT OUTPUT", file=sys.stderr)
return 2
if args[1] == "motw":
return run_motw(args[2:])
if os.name != "nt":
print("Signature mode requires Windows.", file=sys.stderr)
return 2
return run_signature(args[2:])
if __name__ == "__main__":
sys.exit(main())
You must have python installed as the helper uses the 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)"
Visual_Indicators.opusscriptinstall (29.5 KB)


