Skip to content

Instantly share code, notes, and snippets.

@denji
Last active August 4, 2026 11:21
Show Gist options
  • Select an option

  • Save denji/a311545c36a32b6cd5c6075f79743c9a to your computer and use it in GitHub Desktop.

Select an option

Save denji/a311545c36a32b6cd5c6075f79743c9a to your computer and use it in GitHub Desktop.
vmx_sort.py — Diff-optimized VMware .vmx parser and formatter.
#!/usr/bin/env python3
"""
vmx_sort.py — Diff-optimized VMware .vmx parser and formatter.
"""
import re
import sys
from collections import OrderedDict
LINE_RE = re.compile(r'^\s*([^\s=]+)\s*=\s*(.*?)\s*$')
PINNED_FIRST = [".encoding", "config.version", "virtualHW.version"]
# Full descriptive group names ordered by volatility (Static -> Volatile)
GROUP_RULES = [
# 1. Identity & Core Specs (Static)
("Identity & Guest OS",
r'^(displayName|annotation|guestOS.*|virtualHW\.productCompatibility)$'),
("CPU Configuration & Nested Virt",
r'^(numvcpus|cpuid\..*|vcpu\..*|vhv\..*|vvtd\..*|vmx\.allowNested|featMask\..*'
r'|paevm|vpmc\.enable|mce\.enable|vhu\.enable|ulm\.disableMitigations)$'),
("CPU Scheduling & Priority",
r'^(Priority\..*|sched\.cpu\..*)$'),
("NUMA Topology",
r'^numa\..*$'),
("Memory Configuration & Scheduling",
r'^(memSize|memory\..*|mem\..*|mainMem\..*|MemTrimRate|MemAllowAutoScaleDown'
r'|sched\.mem\..*|prefvmx\..*|pciHole\..*)$'),
# 2. Controllers & Hardware Topology (Static)
("Storage Controllers & Drives",
r'^(scsi\d+|sata\d+|nvme\d+|ide\d+|floppy\d+)(:\d+)?\..*$'),
("Network Adapters",
r'^(ethernet\d+|vmxnet\d*)\..*$'),
("USB Controllers & Devices",
r'^(usb.*|ehci\..*|xhci\..*)$'),
("BIOS / EFI / Firmware",
r'^(firmware|bios\..*|bios440\..*|efi\..*|uefi\..*|nvram|acpi\..*)$'),
("Chipset & PCI",
r'^(chipset\..*|pciBridge\d*\..*|pciPassthru\d*\..*|pci\.allowPassthrough|hpet0\..*)$'),
("Virtual TPM (vTPM)",
r'^(vtpm\..*|managedVM\.autoAddVTPM)$'),
# 3. Peripherals & Guest Services (Semi-Static)
("Input Devices & Sensors",
r'^(mouse\..*|vmmouse\..*|keyboard\..*|touchpad\..*|mks\.gamingMouse\..*'
r'|mks\.useDirectInput|mks\.disableTypematic|mks\.disableRemoteClientTypematic'
r'|mks\.keyboardFilter|sensor\..*)$'),
("Display & Graphics (MKS)",
r'^(svga\..*|mks\..*|gui\..*|pref\..*|gfx\..*)$'),
("Sound",
r'^sound\..*$'),
("Serial & Parallel Ports",
r'^(serial|parallel)\d+\..*$'),
("Shared Folders (HGFS)",
r'^(hgfs\..*|sharedFolder\d*\..*)$'),
("VMware Tools",
r'^(tools\..*|toolscripts\..*|installerDefaults\..*)$'),
# 4. Security, Stealth & Advanced
("Anti-Detection / VM Stealth",
r'^(hypervisor\.cpuid\..*|smbios\..*|hw\.model.*|board-id.*|serialNumber.*'
r'|monitor_control\.disable_mmu_largepages|vmGenCounter\.enable)$'),
("Security & Policy",
r'^(isolation\..*|policy\..*|Guest\.Command\.Enabled)$'),
("VM Encryption",
r'^(migrate\.encryptionMode|ftcpt\.ftEncryptionMode|encryption\..*|cryptoState)$'),
# 5. Advanced Tuning, Debugging & Logging
("Storage I/O Tuning",
r'^(aiomgr\..*|cbtmotion\..*)$'),
("Time Synchronization",
r'^(tools\.syncTime|time\.synchronize\..*|host\.cpukHz|host\.noTSC|ptsc\.noTSC)$'),
("Power Management",
r'^(powerType\..*|suspend\.disabled)$'),
("VMCI Interface",
r'^vmci\d*\..*$'),
("Remote Display (VNC) & Unity",
r'^(RemoteDisplay\..*|unity\..*)$'),
("Logging & Debugging",
r'^(log\..*|vmx\.buildType|vmx\.scoreboard\..*|vmxstats\..*|debug\..*'
r'|monitor_control\.log.*)$'),
("Snapshot & File References",
r'^(snapshot\..*|.*\.fileName)$'),
# 6. Hypervisor State (Volatile — Bottom)
("Runtime & VM State (VMware-managed)",
r'^(cleanShutdown|checkpoint\..*|uuid\..*|vc\.uuid|migration\..*|vmotion\..*|replay\..*'
r'|softPowerOff|monitor\.phys_bits_used|toolsInstallManager\..*'
r'|guestinfo\.detailed\..*|extendedConfigFile|sched\.swap\..*'
r'|vm\.genid.*|vm\.lastPowerRequestTimestamp)$'),
]
ENCRYPTION_KEYS = {"encryption.data", "encryption.keysafe", "encryption.bundle"}
def is_encrypted_vmx(entries):
parsed_lower_keys = {k.lower() for k in entries.keys()}
return bool(parsed_lower_keys & ENCRYPTION_KEYS)
def natural_key(text):
chunks = re.split(r'(\d+)', text)
key = []
for c in chunks:
if c == "":
continue
if c.isdigit():
key.append((1, int(c)))
else:
key.append((0, c.lower()))
return key
def parse_vmx(lines):
entries = OrderedDict()
lower_to_orig = {}
for raw in lines:
stripped = raw.strip()
if not stripped or stripped.startswith("#") or stripped.startswith("!"):
continue
m = LINE_RE.match(raw.rstrip("\n"))
if not m:
continue
key, value = m.group(1), m.group(2)
lower_key = key.lower()
if lower_key in lower_to_orig:
del entries[lower_to_orig[lower_key]]
lower_to_orig[lower_key] = key
entries[key] = value
return entries
def group_for(key):
for name, pattern in GROUP_RULES:
if re.match(pattern, key, re.IGNORECASE):
return name
return "Miscellaneous"
def build_sorted_vmx(entries):
out_lines = []
# 1. Pinned header lines
lower_entries = {k.lower(): k for k in entries.keys()}
for pinned in PINNED_FIRST:
orig_key = lower_entries.get(pinned.lower())
if orig_key:
out_lines.append(f'{orig_key} = {entries[orig_key]}')
if out_lines:
out_lines.append("")
# 2. Bucket entries
pinned_lower = {p.lower() for p in PINNED_FIRST}
buckets = OrderedDict((name, []) for name, _ in GROUP_RULES)
buckets["Miscellaneous"] = []
for key, value in entries.items():
if key.lower() in pinned_lower:
continue
buckets[group_for(key)].append((key, value))
# 3. Format output with original style headers: # --- Full Name ---------------------------
for group_name, items in buckets.items():
if not items:
continue
items.sort(key=lambda kv: natural_key(kv[0]))
header_text = f"# --- {group_name} "
header_line = header_text + "-" * max(0, 47 - len(header_text))
out_lines.append(header_line)
for key, value in items:
out_lines.append(f"{key} = {value}")
out_lines.append("")
return "\n".join(out_lines).rstrip() + "\n"
def main():
if len(sys.argv) < 2:
sys.exit("Usage: python3 vmx_sort.py input.vmx [output.vmx]")
in_path = sys.argv[1]
out_path = sys.argv[2] if len(sys.argv) > 2 else None
with open(in_path, "r", encoding="utf-8", errors="replace") as f:
lines = f.readlines()
entries = parse_vmx(lines)
if is_encrypted_vmx(entries):
sys.exit(f"Error: '{in_path}' contains encrypted configuration data. Aborting.")
result = build_sorted_vmx(entries)
if out_path:
with open(out_path, "w", encoding="utf-8") as f:
f.write(result)
else:
sys.stdout.write(result)
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment