Source code for winshlrc.scripts.extract

#!/usr/bin/env python3
"""Script to extract Windows shell information."""

import argparse
import logging
import os
import sys
import yaml

from dfvfs.helpers import command_line as dfvfs_command_line
from dfvfs.helpers import volume_scanner as dfvfs_volume_scanner
from dfvfs.lib import errors as dfvfs_errors

import winshlrc

from winshlrc import extractor
from winshlrc import yaml_definitions_file


[docs] def Main(): """Entry point of console script to extract Windows shell information. Returns: int: exit code that is provided to sys.exit(). """ argument_parser = argparse.ArgumentParser( description=("Extract Windows shell information.") ) argument_parser.add_argument( "-d", "--debug", dest="debug", action="store_true", default=False, help="enable debug output.", ) argument_parser.add_argument( "-w", "--windows_version", "--windows-version", dest="windows_version", action="store", metavar="Windows XP", default=None, help="string that identifies the Windows version.", ) argument_parser.add_argument( "source", nargs="?", action="store", metavar="PATH", default=None, help=( "path of the volume containing C:\\Windows or the filename of " "a storage media image containing the C:\\Windows directory." ), ) options = argument_parser.parse_args() if not options.source: print("Source value is missing.") print("") argument_parser.print_help() print("") return 1 try: with open(options.source, "r", encoding="utf-8") as file_object: source_definitions = list(yaml.safe_load_all(file_object)) except (SyntaxError, UnicodeDecodeError, yaml.parser.ParserError): source_definitions = [ {"source": options.source, "windows_version": options.windows_version} ] logging.basicConfig(level=logging.INFO, format="[%(levelname)s] %(message)s") data_path = os.path.join(os.path.dirname(winshlrc.__file__), "data") path = os.path.join(data_path, "observed_shellfolders.yaml") definitions_file = yaml_definitions_file.YAMLShellFoldersDefinitionsFile() observed_shell_folder_definitions = { definition.identifier: definition for definition in definitions_file.ReadFromFile(path) } mediator = dfvfs_command_line.CLIVolumeScannerMediator() volume_scanner_options = dfvfs_volume_scanner.VolumeScannerOptions() volume_scanner_options.partitions = ["all"] volume_scanner_options.snapshots = ["none"] volume_scanner_options.volumes = ["none"] shell_folders = {} observed_shell_folders = {} unknown_shell_folders = {} windows_versions_per_shell_folder = {} for source_definition in source_definitions: source_path = source_definition["source"] logging.info(f"Processing: {source_path:s}") extractor_object = extractor.WindowsShellExtractor( debug=options.debug, mediator=mediator ) try: result = extractor_object.ScanForWindowsVolume( source_path, options=volume_scanner_options ) except dfvfs_errors.ScannerError: result = False if not result: print( ( f"Unable to retrieve the volume with the Windows directory " f"from: {source_path:s}." ) ) print("") return 1 if extractor_object.windows_version: windows_version = extractor_object.windows_version logging.info(f"Detected Windows version: {windows_version:s}") if source_definition["windows_version"]: windows_version = source_definition["windows_version"] else: print("Unable to determine Windows version.") windows_version = source_definition["windows_version"] for shell_folder in extractor_object.CollectShellFolders(): existing_shell_folder = shell_folders.get(shell_folder.identifier) if not existing_shell_folder: shell_folders[shell_folder.identifier] = shell_folder elif not existing_shell_folder.name: existing_shell_folder.name = shell_folder.name elif ( shell_folder.name and shell_folder.name != existing_shell_folder.name and shell_folder.name not in existing_shell_folder.alternate_names ): existing_shell_folder.alternate_names.append(shell_folder.name) if windows_version: if shell_folder.identifier not in windows_versions_per_shell_folder: windows_versions_per_shell_folder[shell_folder.identifier] = [] windows_versions_per_shell_folder[shell_folder.identifier].append( windows_version ) shell_folder_definition = observed_shell_folder_definitions.get( shell_folder.identifier, None ) if shell_folder_definition: observed_shell_folders[shell_folder.identifier] = shell_folder continue unknown_shell_folders[shell_folder.identifier] = shell_folder mapped_names = { "AppSuggestedLocations": "Application Suggested Locations", "CompressedFolder": "Compressed Folder", "DeviceCenter Initialization": "Device Center Initialization", "FileHistoryDataSource": "File History Data Source", "HomeGroup Control Panel": "Home Group Control Panel", "IE History and Feeds Shell Data Source for Windows Search": ( "Internet Explorer History and Feeds Shell Data Source for Windows " "Search" ), "IE RSS Feeds Folder": "Internet Explorer RSS Feeds Folder", "LayoutFolder": "Layout Folder", "printhood delegate folder": "Printhood delegate folder", "StreamBackedFolder": "Stream Backed Folder", "UsersLibraries": "Users Libraries", } if observed_shell_folders: print("Observed shell folders:") for identifier, shell_folder in sorted(observed_shell_folders.items()): shell_folder_definition = observed_shell_folder_definitions.get( identifier, None ) print(f"\t{identifier:s}", end="") if shell_folder_definition and shell_folder_definition.name: print(f" ({shell_folder_definition.name:s})", end="") print("") names = list(shell_folder.alternate_names or []) if shell_folder.name: names.append(shell_folder.name) for name in names: name = mapped_names.get(name, name) if ( name and name != shell_folder_definition.name and name not in shell_folder_definition.alternate_names ): print(f"\t\tAlternate name: {shell_folder.name:s}") print("") if unknown_shell_folders: print("Unknown shell folders:") for identifier, shell_folder in sorted(unknown_shell_folders.items()): print(f"\t{identifier:s}", end="") if shell_folder_definition and shell_folder_definition.name: print(f" ({shell_folder_definition.name:s})", end="") print("") print("") return 0
if __name__ == "__main__": sys.exit(Main())