Visual Indicators

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 effective PATH
  • โ‡ข 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


image

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 items
  • Alias.RemoveSelected โ€” Remove aliases pointing to selected items
  • Favorite.AddSelected โ€” Add selected items as favorites
  • Favorite.RemoveSelected โ€” Remove favorites pointing to selected items
  • Path.AddTo โ€” Add selected folders to PATH
  • Path.Remove โ€” Remove selected folders from PATH
  • Alias.Debug โ€” Show alias and PATH debug info for the current selection

MOTW / V2

  • MOTW.RefreshVisible โ€” Refresh MOTW state for visible files in the current tab
  • MOTW.ClearCache โ€” Clear cached MOTW state
  • MOTW.AddSelected โ€” Add MOTW to selected file(s) by writing Zone.Identifier
  • MOTW.RemoveSelected โ€” Remove MOTW from selected file(s) by deleting Zone.Identifier

V3

  • V3.RefreshVisible โ€” Refresh V3 signature status for visible files in the current tab
  • V3.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)

6 Likes

Interesting and good work! It works well for a given directory. Wonder if it could be tied in with Everything search and/or flat view to get a list of all applicable folders... Maybe next iteration. :wink:

1 Like

Thanks :).

If you press F5 to refresh after switching to flat view, it should show you aliased files within all folders within the display.

Upgraded to version 1.3

be great if it somehow worked in thumbnail mode. thumbnail overlays perhaps?

I just did a quick review of the Dopus Docs and there doesn't seem to be a straightforward way of doing this, but happy to be corrected :slight_smile:

Updated to Beta version 2.4.2:

Experimental

  • Added indicators for path variables, symlinks, and files locked by a program
  • Added new commands:
    • Path.Addto
    • Path.Remove
  • Added a new 'locked by' column which lists the locking program(s). This feature requires you to download the attached python helper and to point to it in the script configuration menu. This is my attempt at implementing a version of an idea conceived by @polargoose
  • Added delay timers for favorite and path removal commands (these can be adjusted in the script configuration. I run 1.5 secs.
1 Like

Updated to version 2.13.3.

  • general performance improvements.
  • added MOTW and signature checks.
  • removed locked-by.
  • added new helpers.
  • added Sandboxie column
1 Like