DTLknowsWhy — Reference Manual v2.1
Complete module and command reference for DTLknowsWhy 2.1 — Windows network diagnostic and causal analysis engine.
Preface
This manual describes the command-line interface, the graphical user interface, and the internal module reference for DTLknowsWhy 2.1. It covers every executable entry point, every collector module, every shared support module, the expert rule engine, the comparative analyser, and the snapshot format. For step-by-step operational guidance, refer to the companion DTLknowsWhy User Guide.
DTLknowsWhy answers one practical question: "Why does it work on one machine and not on another?" Rather than listing symptoms, it identifies probable causes and proposes corrective actions. Version 2.1 replaces the legacy ipconfig /all text-parsing approach with a structured PowerShell and CIM data collection engine, making the tool fully language-independent and compatible with any Windows locale.
Intended Audience
This manual is intended for:
- System administrators managing Windows 10 and 11 workstations and small Windows-centric networks
- Network administrators diagnosing SMB, DNS, and connectivity issues
- Developers extending or integrating DTLknowsWhy
Readers are assumed to be comfortable with the Windows command prompt, basic TCP/IP networking, and Python execution. No Python development experience is required for operational use.
Conventions
| Convention | Meaning |
|---|---|
monospace | Command text, file names, function names, parameter names, and output literals |
| italic | Variables and placeholders — substitute actual values when typing commands |
| Bold | Introduction of a new term or emphasis on a critical point |
[option] | Optional argument; do not type the brackets |
{a|b} | Mutually exclusive choices; choose exactly one; do not type the braces or pipe |
Related Documents
| Document | Description |
|---|---|
| DTLknowsWhy User Guide | Step-by-step operational guide for first-time and daily use |
| NetDTL Reference Manual | PHP/MySQL agentless network inventory web application |
| DTLsaysWhat Reference Manual | Windows system inventory tool inspired by the OpenVMS SHOW SYSTEM command |
| README.md | Quick-start summary included in the repository root |
Chapter 1 — Introduction
1.1 Overview
DTLknowsWhy is a Windows diagnostic and expert analysis tool. Run it on a machine to get an immediate picture of its configuration: OS version, network profile, IP settings, key Windows services, and basic connectivity. Optionally point it at another machine to classify it, test its ports, and retrieve its full remote snapshot.
Every collection run produces three output files: a JSON snapshot (raw data for archiving or later analysis), a plain-text report, and a dark-themed HTML report. Reports are available in French and English.
| Component | Role |
|---|---|
agent.py | Main entry point; CLI dispatcher and snapshot orchestrator |
DTLknowsWhy.exe | GUI executable (no console window); launches the Tkinter interface |
DTLknowsWhy-CLI.exe | CLI executable (console window); identical logic to agent.py at runtime |
DTLknowsWhy-Agent.exe | Remote agent; exposes HTTP snapshot endpoint; can run as a Windows service |
expert.py | Expert analysis engine; loads a snapshot and emits diagnostic findings |
compare.py | Comparative analyser; loads two snapshots and identifies causal differences |
1.2 What's New in Version 2.1
Language-independent network collection
Previous versions collected network configuration by parsing ipconfig /all text output, which depended on localised Windows labels and worked reliably only on French Windows. Version 2.1 replaces this engine entirely with structured PowerShell and CIM data objects.
| Aspect | Version 2.0 | Version 2.1 |
|---|---|---|
| Data source | ipconfig /all text parsing | PowerShell + CIM structured objects |
| Windows locale | French only | Any language |
| Fragility | Breaks on Windows update label changes | Resilient — structured data is version-stable |
| JSON snapshot format | — | Unchanged (full backward compatibility) |
Graphical user interface with language selection
Version 2.1 adds a Tkinter GUI (DTLknowsWhy.exe) with a language selection control at startup. The selected language applies to all interface labels, menus, generated reports, and diagnostic messages. French and English are supported. The language selection is independent from the Windows display language.
New collector keys
Two new keys are added to the system section of the snapshot: lm_compatibility_level (integer from the LSA registry key, or null if absent) and bitlocker_status (dict of drive letter to encryption state). These feed new rules in the expert engine.
Expert engine and comparative analyser
The analyze() function now accepts a lang parameter. The comparative analyser (compare.py) is fully internationalised via shared/i18n.py: all finding tags, cause descriptions, and remediation strings are available in French and English via --lang.
1.3 Architecture
The tool is structured in four layers:
- Entry points:
agent.py,expert.py,compare.pyand the compiled executables - Collectors:
agent/collectors/— one module per data category, all returning plain Python dicts - Shared modules:
shared/— serialisation, text and HTML report generation, i18n, command runner, logger - Expert modules:
expert/— rule engine and comparative analyser
Windows System
|
v
Collectors (system, network, tests, services, remote_tests)
|
v
Snapshot dict ──────────────────────────────────┐
| |
v v
serializer.py rules_engine.py
report.py / html_report.py compare.py
| |
v v
JSON + TXT + HTML files Diagnostic findings (stdout)
1.4 Requirements
| Component | Version | Notes |
|---|---|---|
| Windows | 10 / 11 | Collectors use Windows-specific commands and CIM classes |
| Python | 3.10+ | Standard library only — no pip install required |
| PowerShell | 5.1 / 7+ | Pre-installed on all supported Windows versions |
| Administrator privileges | Recommended | Required for full service inspection, SMB configuration, and BitLocker status |
1.5 Installation
No installer is required. Copy the project folder to the target machine and run from the project root. The directory layout is:
DTLknowsWhy/
├── agent.py ← main entry point
├── expert.py ← expert analysis entry point
├── compare.py ← comparative analysis entry point
├── DTLknowsWhy.exe ← GUI executable (console=False)
├── DTLknowsWhy-CLI.exe ← CLI executable (console=True)
├── DTLknowsWhy-Agent.exe ← remote agent executable
├── agent/
│ ├── gui.py
│ ├── server.py
│ ├── service.py
│ └── collectors/
│ ├── system.py
│ ├── network.py
│ ├── tests.py
│ ├── remote_tests.py
│ └── services.py
├── expert/
│ ├── rules_engine.py
│ └── compare.py
└── shared/
├── commands.py
├── serializer.py
├── report.py
├── report_writer.py
├── html_report.py
├── html_writer.py
├── i18n.py
├── version.py
└── logger.py
Chapter 2 — Command Descriptions
This chapter describes each executable entry point: syntax, parameters, options, behaviour, and examples. For module internals, see Chapter 3.
agent.py
python agent.py [--snapshot] [--target IP_OR_HOST] [--listen] [--once] [--lang {fr,en}]
| Parameter | Required | Description |
|---|---|---|
| --snapshot | Optional | Collect local snapshot and write output files. Can be combined with --target. |
| --target HOST | Optional | Run remote diagnostic tests plus retrieve a full remote snapshot from the agent on HOST. Implies --snapshot. |
| --listen | Optional | Start the HTTP server on port 5050. Mutually exclusive with --snapshot and --target. |
| --once | Optional | Stop the server after the first successful /snapshot request. Test mode only; ignored when running as a Windows service. |
| --lang {fr|en} | Optional | Report language. Default: en. |
is_cli_executable() checks sys.argv[0]: if the stem is agent, contains cli, or ends with -agent, the process runs in CLI mode; otherwise it launches the GUI. This makes the same source file behave correctly whether run as python agent.py, DTLknowsWhy.exe, or DTLknowsWhy-CLI.exe.
# Local snapshot, English report
python agent.py --snapshot --lang en
# Local snapshot + remote agent query
python agent.py --target PC-BEN-002 --lang en
# Start HTTP server
python agent.py --listen
DTLknowsWhy.exe (GUI)
agent.py; the console=False PyInstaller flag suppresses the console window. Launches the Tkinter interface automatically because is_cli_executable() returns False for this name.DTLknowsWhy.exe [--target IP_OR_HOST] [--lang {fr,en}]
Without --target: opens the GUI at the situation selection screen. With --target: pre-fills the target field and, if --auto-start is also passed internally, begins the diagnosis immediately. Language defaults to en; user can change it in the GUI combo box.
DTLknowsWhy-CLI.exe
agent.py; the console=True PyInstaller flag keeps the console window. Behaves as CLI because is_cli_executable() returns True for names containing cli.DTLknowsWhy-CLI.exe [--snapshot] [--target IP_OR_HOST] [--listen] [--lang {fr,en}]
Same parameters and behaviour as agent.py in CLI mode. Requires administrator privileges; displays a formatted warning and exits if not elevated.
DTLknowsWhy-Agent
DTLknowsWhy-Agent.exe --listen
DTLknowsWhy-Agent.exe install
DTLknowsWhy-Agent.exe start
DTLknowsWhy-Agent.exe stop
DTLknowsWhy-Agent.exe remove
| Parameter | Description |
|---|---|
| --listen | Start in interactive foreground mode; listens on TCP 5050 until Ctrl+C |
| install | Install as a Windows service (requires administrator) |
| start | Start the installed Windows service |
| stop | Stop the running Windows service |
| remove | Remove the Windows service registration |
GET /snapshot?key=DTLSECRET&lang=en
| Parameter | Required | Description |
|---|---|---|
| key | Yes | Must match API_KEY in agent/server.py. Returns HTTP 403 if absent or wrong. |
| lang | No | en (default) or fr |
server.py. No TLS. Use only on trusted local networks. TCP port 5050 must be open inbound on the Windows Firewall; see Appendix C. On first execution, Windows SmartScreen may block the agent; see Appendix D.# Interactive mode
DTLknowsWhy-Agent.exe --listen
# Install and start as Windows service
DTLknowsWhy-Agent.exe install
DTLknowsWhy-Agent.exe start
expert.py
python expert.py [snapshot.json] [--lang {fr,en}]
| Parameter | Required | Description |
|---|---|---|
| snapshot.json | Optional | Path to a snapshot JSON file. If omitted, the most recently modified *_snapshot_*.json in the current directory is used. Exits with code 1 if none found. |
| --lang {fr|en} | Optional | Output language. Default: en. |
| Level | Meaning |
|---|---|
[OK] | No problem detected for this check |
[INFO] | Informational; no action required |
[WARN] | Potential issue; review the remediation suggestion |
[FAIL] | Confirmed problem; apply the remediation |
# Analyse latest snapshot, English output
python expert.py --lang en
# Analyse a specific snapshot
python expert.py PC-BEN-002_snapshot_20260607_093442.json --lang en
compare.py
--lang.python compare.py snapshot_ref.json snapshot_target.json [--lang {fr,en}]
| Parameter | Required | Description |
|---|---|---|
| snapshot_ref.json | Yes | Reference snapshot (the machine that works correctly — PC A) |
| snapshot_target.json | Yes | Target snapshot (the machine under investigation — PC B) |
| --lang {fr|en} | Optional | Output language. Default: fr. |
| --ben-reference | Optional | Use the latest PC-BEN-001_snapshot_*.json as reference automatically |
| Tag | Meaning |
|---|---|
| [CONFIRMED CAUSE] | The difference directly causes the problem |
| [PROBABLE CAUSE] | A configuration known to block the feature in question |
| [POSSIBLE CAUSE] | A difference that may contribute depending on the scenario |
| [OBSERVED] | Factual observation; no issue implied |
| [TO VERIFY] | Notable configuration warranting manual check |
| [MISSING INFORMATION] | Field absent from target snapshot; no conclusion possible |
python compare.py PREDATOR_snapshot_20260607.json PC-BEN-002_snapshot_20260607.json --lang en
Chapter 3 — Module Reference
This chapter describes each Python module: purpose, public functions, parameters, and output keys. For CLI entry points, see Chapter 2.
Entry point
create_snapshot(), the central orchestration function.create_snapshot(target=None, lang="en", save_outputs=True) → dict
- Calls all collectors in sequence: system, network, tests, services
- If
targetis provided: callscollect_remote_tests(target)and attempts to retrieve a full remote snapshot from the agent via HTTP - Runs
analyze(snapshot, lang)and stores findings insnapshot["diagnosis"] - Runs
compare_causal()orcompare_remote_target()and stores results insnapshot["causal_comparison"] - If
save_outputs=True: serialises JSON, generates and saves TXT and HTML reports - Returns the complete snapshot dict
GUI
create_snapshot() in a background thread to keep the UI responsive.run_gui(create_snapshot, initial_target=None, auto_start=False, lang="en")
Seven pre-defined situations are defined in the SITUATIONS list constant. Each situation has an id, a title i18n key, a description i18n key, and a requires_target flag. The GUI uses these to filter and highlight relevant findings from snapshot["diagnosis"].
| id | requires_target | Description |
|---|---|---|
| SMB-001 | No | Machine invisible in network neighbourhood |
| SMB-002 | Yes | SMB access works by IP but not by name |
| SMB-003 | Yes | SMB authentication refused (error 86 / 1326) |
| LOCAL-NETWORK | No | Local network connectivity problem |
| LOCAL-SMB | No | Local SMB service failure |
| REMOTE-WINDOWS | Yes | Cannot access a remote Windows share |
| REMOTE-DEVICE | Yes | Diagnose a remote network device |
QueueWriter redirects stdout / stderr to a queue.Queue. The main thread polls the queue every 100 ms via root.after() and appends messages to the log pane. This avoids Tkinter thread-safety issues.
HTTP server
GET /snapshot. Calls create_snapshot() locally and returns the result as JSON. Used both by --listen and the Windows service.| Constant | Default | Description |
|---|---|---|
| API_KEY | DTLSECRET | Pre-shared key; requests with wrong key receive HTTP 403 |
| HOST | 0.0.0.0 | Binds to all network interfaces |
| PORT | 5050 | TCP port |
AGENT_TIMEOUT_SECONDS = 120 (defined in agent.py) is the HTTP client-side timeout when the diagnostic workstation fetches a remote snapshot.
Collectors
System collector
| Key | Source | Description |
|---|---|---|
| hostname | socket.gethostname() | NetBIOS / DNS hostname |
| username | getpass.getuser() | Logged-in Windows username |
| is_admin | ctypes.windll | Boolean — process has administrator privileges |
| windows_product_name | Registry + normalisation | OS name corrected for the Windows 10/11 reporting discrepancy |
| windows_version | Registry DisplayVersion | Feature update string, e.g. 23H2 |
| windows_build | Registry CurrentBuild | Build number string, e.g. 22631 |
| lm_compatibility_level | Registry HKLM\...\Lsa\LmCompatibilityLevel | Integer 0–5, or null if the key is absent (Windows default) |
| bitlocker_status | PowerShell Get-BitLockerVolume / manage-bde | Dict of drive letter to encryption state, or null if not collectible |
ProductName on some builds. The collector corrects this by checking whether the build number is ≥ 22000.null value means the registry key is absent and Windows uses its compiled-in default (NTLMv2 only on Windows 10/11 1903+). Values 0–5 indicate explicit overrides. See Appendix E for the full interpretation table.Network collector
| Key | Source | Description |
|---|---|---|
| active_adapter_profile | PowerShell Get-NetConnectionProfile | Name of the active connection profile |
| network_category | PowerShell NetworkCategory | Profile type: Public, Private, or Domain |
| ipv4 | CIM Win32_NetworkAdapterConfiguration | Primary IPv4 address |
| subnet_mask | CIM | Subnet mask |
| default_gateway | CIM | Default gateway IP |
| dns_servers | CIM | List of DNS server IPs (deduplicated) |
| dhcp_enabled | CIM | Boolean — DHCP active on the primary adapter |
| netbios_option | CIM TcpipNetbiosOptions | Raw integer: 0=via DHCP, 1=enabled, 2=disabled |
| netbios_enabled | Derived from netbios_option | Boolean: True for 0 or 1, False for 2, null if unknown |
Local tests collector
ping -n 1 with a 10-second timeout and returns True if exit code is 0.| Key | Target | Description |
|---|---|---|
| ping_localhost | 127.0.0.1 | Verifies the IP stack is functional |
| ping_self | Local IPv4 | Verifies the NIC is reachable; skipped (False) if no IPv4 was collected |
| ping_gateway | Default gateway | Verifies LAN reachability; skipped (False) if no gateway was collected |
Remote tests collector
| Key | Description |
|---|---|
| target | The IP or hostname passed to collect_remote_tests() |
| resolved_name | Hostname resolved from the IP via ping -a -n 1; None if not resolved |
| ping_target | Boolean — ping succeeded |
| tcp_80 / tcp_139 / tcp_443 / tcp_445 | Boolean — TCP port open (PowerShell Test-NetConnection, 15-second timeout each) |
| mac_address | MAC from the ARP table; None if not found |
| target_type | Classification string; see Appendix B |
Services collector
sc query. Returns one of: Running, Stopped, Failed, Missing, Unknown.| Service | Role | Impact when stopped |
|---|---|---|
| LanmanServer | SMB Server | File and printer sharing unavailable |
| LanmanWorkstation | SMB Workstation client | Cannot access remote shares |
| FDResPub | Function Discovery Resource Publication | Machine invisible in network neighbourhood |
| fdPHost | Function Discovery Provider Host | Device discovery degraded |
| lmhosts | TCP/IP NetBIOS Helper | NetBIOS name resolution may fail |
Shared Modules
Command runner
subprocess.run(). Tries utf-8, cp850, cp1252 for decoding; falls back to errors="replace". Always returns a consistent dict.run_command(command: str, timeout: int = 15) → dict
| Key | Type | Value on error |
|---|---|---|
| stdout | str | Empty string on timeout or exception |
| stderr | str | Empty string on timeout or exception |
| exit_code | int | -1 on timeout; -2 on exception |
Snapshot serializer
export_snapshot(data: dict, hostname: str) → Path
Writes HOSTNAME_snapshot_YYYYMMDD_HHMMSS.json with indent=2, ensure_ascii=False. Returns the Path of the created file.
Report generators
(snapshot: dict, lang: str) and return a string. Section labels are resolved via tr(key, lang). The HTML report is self-contained with an embedded dark theme.generate_text_report(snapshot, lang="en") → str
generate_html_report(snapshot, lang="en") → str
- Header: title, generation timestamp
- Local machine: identity, system, network, Windows services, local tests
- Diagnosis: findings from
snapshot["diagnosis"] - Remote agent snapshot (if
snapshot["remote_agent_snapshot"]is present) - Causal comparison (if
snapshot["causal_comparison"]is present)
Internationalisation
tr(key: str, lang: str = "fr") → str
Returns the translation of key for lang. Falls back to French if the language is not found. Returns the key itself if no translation exists, making missing keys immediately visible in the UI.
- Report section headings and field labels
- CLI progress messages (
cli_*) - GUI labels and dialog messages (
gui_*) - Comparator findings (
cmp_*) - Expert rule messages and remediations (
rule001_*throughrule015_*) - Collector v2.1 interpretation strings (
netbios_option_*,lm_compat_*,bitlocker_*)
Version
DTLKNOWSWHY_VERSION = "2.1.0"
Logger
dtlknowswhy.log in the current directory at INFO level.from shared.logger import logger — the singleton is ready to use. Handlers are attached only once (idempotent). Every run_command() call logs the command string at INFO; timeouts and exceptions log at ERROR with tracebacks.
Expert Modules
Rules engine
analyze() accepts a lang parameter and all messages are returned in the requested language via tr().analyze(snapshot: dict, lang: str = "en") → list[dict]
Each finding dict: {"level": str, "message": str, "remediation": str|None, "case": str|None}
| Case | Level | Condition |
|---|---|---|
| — | WARN | is_admin is False |
| — | FAIL / OK | Gateway ping result |
| — | WARN | Network profile is Public |
| — | FAIL | LanmanServer or LanmanWorkstation stopped |
| RÈGLE-001 | INFO | FDResPub running but machine may be invisible (SMB-001) |
| RÈGLE-003 | WARN | Profile Private + fdPHost running but FDResPub stopped |
| RÈGLE-005-006-014 | INFO | TCP 445 open on probable_windows target — auth error guidance |
| RÈGLE-007 | WARN / INFO | LmCompatibilityLevel present and noteworthy (0 or ≥5) |
| RÈGLE-008-013 | FAIL | Ping OK but TCP 445 closed on target |
| RÈGLE-009 | INFO | Ping OK, no TCP, no MAC — possible IPv6-only resolution |
| RÈGLE-010 | INFO | TCP 445 open but no resolved name — slow hostname enumeration |
| RÈGLE-011 | INFO | HTTP/HTTPS open but no SMB — TTL may indicate appliance |
| RÈGLE-012 | WARN | BitLocker active on one or more drives |
| — | FAIL / INFO | Remote target type rules (unreachable, mobile, device, etc.) |
Comparative analyser module
compare_causal() and compare_remote_target(). Compares two snapshot dicts and returns a list of finding dicts with level, title, evidence list, cause, and optional remediation. All strings resolved via tr(key, lang).compare_causal(reference: dict, target: dict, lang: str = "fr") → list[dict]
compare_remote_target(snapshot: dict, lang: str = "fr") → list[dict]
- Network profile (Public on target)
- LanmanServer and LanmanWorkstation status
- FDResPub and fdPHost status
- Gateway reachability
- NetBIOS option
- DNS servers
- IP topology (gateway and subnet mask)
- TCP 445 accessibility
- Bitdefender presence and fltmc filter stack
- SMB client and server configuration parameters
- Accessible SMB shares
- Identity context (local, domain, AzureAD Joined)
Appendices
Appendix A — Snapshot Format
The JSON snapshot produced by export_snapshot() has the following top-level structure in v2.1:
{
"metadata": {
"generated_at": "2026-06-07T09:34:42",
"generated_at_local": "07/06/2026 09:34:42",
"role": "local",
"target": "PC-BEN-002"
},
"system": {
"hostname": "PREDATOR",
"username": "didier",
"is_admin": true,
"windows_product_name": "Windows 11 Pro",
"windows_version": "23H2",
"windows_build": "22631",
"lm_compatibility_level": null,
"bitlocker_status": { "C:": "FullyEncrypted" }
},
"network": {
"active_adapter_profile": "Réseau",
"network_category": "Private",
"ipv4": "172.17.7.10",
"subnet_mask": "255.255.255.0",
"default_gateway": "172.17.7.1",
"dns_servers": ["172.17.7.1"],
"dhcp_enabled": false,
"netbios_option": 0,
"netbios_enabled": true
},
"tests": { "ping_localhost": true, "ping_self": true, "ping_gateway": true },
"services": { "LanmanServer": "Running", "LanmanWorkstation": "Running",
"FDResPub": "Running", "fdPHost": "Running", "lmhosts": "Running" },
"remote_tests": {
"target": "172.17.7.3", "resolved_name": "PC-BEN-002",
"ping_target": true, "tcp_80": false, "tcp_139": true,
"tcp_443": false, "tcp_445": true,
"mac_address": "B0:7B:25:7B:C7:58", "target_type": "probable_windows"
},
"diagnosis": [...],
"causal_comparison": [...],
"remote_agent_snapshot": { ... }
}
remote_tests is absent if no --target was specified. remote_agent_snapshot is absent if the agent was unreachable. causal_comparison is always present when target is set.
Appendix B — Target Classification
After remote tests complete, classify_target() in remote_tests.py assigns a target_type string. Rules are applied in order; the first match wins:
| target_type | Condition | Badge |
|---|---|---|
| probable_mobile_apple | Resolved hostname contains iphone or ipad | Blue |
| probable_mobile_android | Resolved hostname contains android | Blue |
| probable_windows | TCP 445 or TCP 139 open | Green |
| probable_device | TCP 80 or TCP 443 open | Orange |
| unknown_network_device | MAC resolved but no open ports | Orange |
| unknown_host | Ping succeeded but no MAC and no open ports | Grey |
| unreachable | Ping failed | Red |
probable_mobile_apple.Appendix C — Firewall Configuration
DTLknowsWhy-Agent listens on TCP 5050. Create the inbound rule on the target machine from an elevated command prompt:
netsh advfirewall firewall add rule name="DTLknowsWhy Agent" ^
dir=in action=allow protocol=TCP localport=5050
Alternatively, use Windows Defender Firewall → Advanced Settings → Inbound Rules → New Rule → Port → TCP 5050 → Allow.
Appendix D — SmartScreen Warning
On first execution, Windows Defender SmartScreen may display:
Windows protected your PC.
Microsoft Defender SmartScreen prevented an unrecognized app from starting.
This is expected for unsigned executables. To proceed: verify the file originates from the official DTLknowsWhy repository; click More info; click Run anyway. In corporate environments, request digital signing or explicit approval from your security team before wide deployment.
Appendix E — LmCompatibilityLevel
This registry value controls the NTLM authentication negotiation level. A missing key (null in the snapshot) means Windows uses its compiled-in default.
| Value | Client sends | Server accepts | Expert finding |
|---|---|---|---|
null (absent) | NTLMv2 only (W10/11 default) | NTLMv2 | INFO (no finding) |
| 0 | LM and NTLM | LM, NTLM, NTLMv2 | WARN — security risk |
| 1 | LM+NTLM; NTLMv2 if negotiated | LM, NTLM, NTLMv2 | INFO |
| 2 | NTLM only | LM, NTLM, NTLMv2 | INFO |
| 3 | NTLMv2 only | LM, NTLM, NTLMv2 | INFO |
| 4 | NTLMv2 only | NTLM, NTLMv2 (refuse LM) | INFO |
| 5 | NTLMv2 only | NTLMv2 only (refuse LM+NTLM) | WARN — may block Workgroup SMB |
To set the value from an elevated PowerShell prompt:
Set-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Control\Lsa" `
-Name LmCompatibilityLevel -Value 3 -Type DWord
Appendix F — Known Limitations
- Windows only. The tool imports
ctypes.windlland calls Windows-specific commands. It will not run on Linux or macOS. - Single active adapter. Collectors return values from the first matching adapter. On multi-adapter machines, secondary adapters are ignored.
- ARP MAC lookup requires LAN adjacency. The target must be on the same Layer 2 segment or have been recently contacted.
- Remote tests can be slow. Each TCP port probe has a 15-second timeout via PowerShell. Up to 60 seconds total if all four ports time out.
- Server mode writes files on every request. Each
GET /snapshottriggers a full collection and writes new JSON, TXT, and HTML files on the agent machine. - API key in plain text.
API_KEYis hardcoded inserver.py. No TLS. Trusted networks only. - BitLocker collection requires elevation.
Get-BitLockerVolumerequires administrator privileges; the fallbackmanage-bdealso requires elevation. Without admin,bitlocker_statuswill benull. - compare.py is directional. Only PC B deviations from PC A are reported. Swap arguments for reverse comparison.
- HTML report logo path is relative. Place
netdtl_logo.pngin the same directory as the HTML report. - Log file in current directory.
dtlknowswhy.logis written to the invocation directory; logging silently fails if write permission is absent.
Appendix G — Version History
| Version | Date | Changes |
|---|---|---|
| 2.1.0 | 7 June 2026 | Language-independent network collection (PowerShell/CIM replaces ipconfig /all); Tkinter GUI with language selector; lm_compatibility_level and bitlocker_status collector keys; fully internationalised comparator and expert engine; 15 knowledge-base rules from operational sessions; 280+ i18n keys; backward-compatible JSON format |
| 2.0.0 | 6 June 2026 | Remote agent support; Windows service; HTTP snapshot endpoint; local/remote causal comparison; enhanced HTML reports; expert rule engine |
| 1.2.0 | — | Experimental remote snapshot server |
| 1.0.0 | — | Initial release: local diagnostics and reporting |