Commit latest version in progress
This commit is contained in:
commit
b88b7f684e
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
examples_private
|
247
dism.py
Executable file
247
dism.py
Executable file
@ -0,0 +1,247 @@
|
||||
#!/bin/env python3
|
||||
|
||||
import argparse
|
||||
import pathlib
|
||||
import re
|
||||
import os
|
||||
import xml.etree.ElementTree as ET
|
||||
|
||||
parser = argparse.ArgumentParser(description='Deals with DISM stuff.',
|
||||
formatter_class=argparse.ArgumentDefaultsHelpFormatter)
|
||||
parser.add_argument('manifests',
|
||||
help='DISM manifests directory',
|
||||
type=pathlib.Path)
|
||||
parser.add_argument('packages', nargs="*",
|
||||
help='Packages to manipulate',
|
||||
type=str)
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
namespaces = {
|
||||
"asm": "urn:schemas-microsoft-com:asm.v3"
|
||||
}
|
||||
|
||||
known_tags = [
|
||||
"{urn:schemas-microsoft-com:asm.v3}assemblyIdentity",
|
||||
"{urn:schemas-microsoft-com:asm.v3}dependency",
|
||||
"{urn:schemas-microsoft-com:asm.v3}file",
|
||||
'{urn:schemas-microsoft-com:asm.v3}genericCommands',
|
||||
"{urn:schemas-microsoft-com:asm.v3}registryKeys",
|
||||
|
||||
"{urn:schemas-microsoft-com:asm.v3}trustInfo",
|
||||
"{urn:schemas-microsoft-com:asm.v3}localization",
|
||||
"{urn:schemas-microsoft-com:asm.v3}instrumentation",
|
||||
"{urn:schemas-microsoft-com:asm.v3}configuration",
|
||||
'{urn:schemas-microsoft-com:wcs.v1}Application',
|
||||
'{urn:schemas-microsoft-com:rescache.v1}rescache',
|
||||
'{urn:schemas-microsoft-com:asm.v3}mof',
|
||||
'{urn:schemas-microsoft-com:asm.v3}imaging',
|
||||
'{urn:schemas-microsoft-com:asm.v3}deployment',
|
||||
'{urn:schemas-microsoft-com:asm.v3}directories',
|
||||
'{urn:schemas-microsoft-com:asm.v3}memberships',
|
||||
'{urn:schemas-microsoft-com:asm.v3}migration',
|
||||
'{urn:schemas-microsoft-com:asm.v3}unattendActions'
|
||||
]
|
||||
unknown_tags = []
|
||||
|
||||
|
||||
variables = {
|
||||
"runtime.system32": "C:\\windows\\system32",
|
||||
"runtime.programfiles": "C:\\Program Files",
|
||||
"runtime.windows": "C:\\windows",
|
||||
"runtime.wbem": "C:\\windows\\wbem",
|
||||
"runtime.commonfiles": "C:\\Program Files\\Common Files"
|
||||
}
|
||||
unknown_variables = []
|
||||
|
||||
known = {}
|
||||
|
||||
def resolve_variables_lookup(match) -> str:
|
||||
capture = match.group(1)
|
||||
if capture is None:
|
||||
return "!!!ERROR!!!"
|
||||
if capture.lower() in variables:
|
||||
return variables[capture.lower()]
|
||||
else:
|
||||
if not capture.lower() in unknown_variables:
|
||||
unknown_variables.append(capture.lower())
|
||||
return "\033[91m${!!!UNKNOWN KEY: " + capture + "!!!}\033[0m"
|
||||
|
||||
def resolve_variables(input_str: str):
|
||||
if input_str is None:
|
||||
return None
|
||||
return re.sub(r'\$\(([^)]+)\)', resolve_variables_lookup, input_str)
|
||||
|
||||
def print_deps(root, depth: int = 0, print_header: bool = True, print_all: bool = False):
|
||||
dep = root.findall("asm:dependency/asm:dependentAssembly", namespaces)
|
||||
|
||||
if print_header and len(dep) > 0:
|
||||
print(f'{" " * (depth * 2 + 1)}Depends on:')
|
||||
depth += 1
|
||||
|
||||
for d in dep:
|
||||
a_type = d.get("dependencyType")
|
||||
|
||||
x = d.find("asm:assemblyIdentity", namespaces)
|
||||
name = x.get("name")
|
||||
print(f'{" " * (depth * 2 + 1)}- {name} ({x.get("version")}) {a_type}')
|
||||
if print_all:
|
||||
if not name.lower() in known:
|
||||
print(f'{" " * (depth * 2 + 3)}- \033[91m!!!MISSING!!!\033[0m')
|
||||
continue
|
||||
print_deps(known[name.lower()].getroot(), depth + 1, False, True)
|
||||
|
||||
def print_files(root, depth: int = 0, print_header: bool = True, print_all: bool = False, print_from: bool = False, print_info: bool = True):
|
||||
files = root.findall("asm:file", namespaces)
|
||||
|
||||
if print_header and (len(files) > 0 or print_all):
|
||||
print(f'{" " * (depth * 2 + 1)}Files:')
|
||||
depth += 1
|
||||
|
||||
for x in files:
|
||||
name = x.get("name")
|
||||
if not print_from:
|
||||
print(f'{" " * (depth * 2 + 1)}- {name}')
|
||||
else:
|
||||
identity = root.find("asm:assemblyIdentity", namespaces)
|
||||
print(f'{" " * (depth * 2 + 1)}- {name} from {identity.get("name")} ({identity.get("version")})')
|
||||
if print_info:
|
||||
print(f'{" " * (depth * 2 + 3)} - To "{resolve_variables(x.get("destinationPath"))}" from "{x.get("sourcePath")}{x.get("sourceName")}"')
|
||||
|
||||
if not print_all:
|
||||
return
|
||||
|
||||
for x in root.findall("asm:dependency/asm:dependentAssembly/asm:assemblyIdentity", namespaces):
|
||||
name = x.get("name")
|
||||
if not name.lower() in known:
|
||||
print(f'{" " * (depth * 2 + 1)}- \033[91m!!!MISSING!!!\033[0m')
|
||||
continue
|
||||
print_files(known[name.lower()], depth, False, True, True)
|
||||
|
||||
value_types = []
|
||||
|
||||
def print_registry(root, depth: int = 0, print_header: bool = True, print_all: bool = False, print_from: bool = False, print_info: bool = True):
|
||||
count = 0
|
||||
values = 0
|
||||
|
||||
reg_keys = root.findall("asm:registryKeys/asm:registryKey", namespaces)
|
||||
|
||||
if print_header and (len(reg_keys) > 0 or print_all):
|
||||
print(f'{" " * (depth * 2 + 1)}Registry:')
|
||||
depth += 1
|
||||
value_types.clear()
|
||||
|
||||
for key in reg_keys:
|
||||
print(f'{" " * (depth * 2 + 3)}- [{key.get("keyName")}]')
|
||||
|
||||
reg_values = key.findall("asm:registryValue", namespaces)
|
||||
for value in reg_values:
|
||||
name = value.get("name")
|
||||
if name == "":
|
||||
name = "@"
|
||||
else:
|
||||
name = f"\"{name}\""
|
||||
vtype = value.get("valueType")
|
||||
if not vtype.upper() in value_types:
|
||||
value_types.append(vtype.upper())
|
||||
if vtype.upper() == "REG_SZ":
|
||||
vtype = ""
|
||||
print(f'{" " * (depth * 2 + 7)}{name} = {vtype}"{resolve_variables(value.get("value"))}"')
|
||||
|
||||
|
||||
count += 1
|
||||
values += len(reg_values)
|
||||
#print(key.get("keyName"))
|
||||
|
||||
if not print_all:
|
||||
return
|
||||
|
||||
for x in root.findall("asm:dependency/asm:dependentAssembly/asm:assemblyIdentity", namespaces):
|
||||
name = x.get("name")
|
||||
if not name.lower() in known:
|
||||
print(f'{" " * (depth * 2 + 1)}- \033[91m!!!MISSING!!!\033[0m')
|
||||
continue
|
||||
print(f'{" " * (depth * 2 + 3)}- {name}')
|
||||
add_count, add_values = print_registry(known[name.lower()], depth + 1, False, True, True)
|
||||
count += add_count
|
||||
values += add_values
|
||||
|
||||
if count > 0:
|
||||
print(f'{" " * (depth * 2 + 1)}- Keys: {count}')
|
||||
print(f'{" " * (depth * 2 + 1)}- Values: {values}')
|
||||
if print_header:
|
||||
print(f'{" " * (depth * 2 + 1)}- Value types: {value_types}')
|
||||
|
||||
return (count, values)
|
||||
|
||||
|
||||
def check_unknown_tags(root, depth: int = 0, print_header: bool = True, do_print: bool = False):
|
||||
for child in root:
|
||||
if child.tag not in known_tags:
|
||||
if do_print:
|
||||
if print_header:
|
||||
print(f'{" " * (depth * 2 + 1)} Unknown tags:')
|
||||
depth += 1
|
||||
print_header = False
|
||||
print(f'{" " * (depth * 2 + 1)}- {child.tag}')
|
||||
if child.tag not in unknown_tags:
|
||||
unknown_tags.append(child.tag)
|
||||
|
||||
|
||||
def print_known(name: str, print_all: bool):
|
||||
tree = known[name.lower()]
|
||||
root = tree.getroot()
|
||||
identity = root.find("asm:assemblyIdentity", namespaces)
|
||||
print(f'Package {identity.get("name")} ({identity.get("version")})')
|
||||
print_deps(root, print_all=print_all)
|
||||
print_files(root, print_all=print_all)
|
||||
print_registry(root, print_all=print_all)
|
||||
|
||||
|
||||
def parse_manifest(path: pathlib.Path, do_print: bool):
|
||||
tree = None
|
||||
try:
|
||||
tree = ET.parse(path)
|
||||
except Exception as e:
|
||||
print("Exception parsing " + path.name)
|
||||
print(e)
|
||||
return
|
||||
|
||||
root = tree.getroot()
|
||||
identity = root.find("asm:assemblyIdentity", namespaces)
|
||||
|
||||
if identity is None:
|
||||
if do_print:
|
||||
print(f"\033[91mMissing identity in: {path.name}\033[0m")
|
||||
return
|
||||
|
||||
name = identity.get("name")
|
||||
if name.lower() in known:
|
||||
raise Exception("WTF - Duplicate name " + name)
|
||||
known[name.lower()] = tree
|
||||
if do_print:
|
||||
print_known(name, False)
|
||||
check_unknown_tags(root, do_print=do_print)
|
||||
|
||||
|
||||
if __name__ != '__main__':
|
||||
quit()
|
||||
|
||||
do_print = False if len(args.packages) > 0 else True
|
||||
|
||||
for entry in args.manifests.iterdir():
|
||||
if entry.is_dir():
|
||||
continue
|
||||
parse_manifest(entry, do_print)
|
||||
if do_print:
|
||||
print()
|
||||
|
||||
if len(unknown_tags) > 0:
|
||||
print("Unknown tags:")
|
||||
for name in unknown_tags:
|
||||
print(f" - {name}")
|
||||
print()
|
||||
|
||||
for name in args.packages:
|
||||
print_known(name, True)
|
||||
print()
|
Loading…
Reference in New Issue
Block a user