Skip to content

Instantly share code, notes, and snippets.

@debakarr
Last active May 20, 2023 06:27
Show Gist options
  • Save debakarr/61daff23000b00b69bee3cb74b0261e4 to your computer and use it in GitHub Desktop.
Save debakarr/61daff23000b00b69bee3cb74b0261e4 to your computer and use it in GitHub Desktop.
Calling PowerShell Command via Python

You first need to install pythonnet and pypsrp

pip install pythonnet pypsrp

Below is the code which uses pythonnet to execute the powershell command and pypsrp to deserialize it into Python object:

import sys
from typing import Any, Dict
import xml.etree.ElementTree as ET
from io import StringIO
from pathlib import Path

import clr
from pypsrp.serializer import Serializer


def find_powershell_dll() -> Path:
    """Find the path to System.Management.Automation.dll file in the Windows.NET directory."""
    powershell_dll_path = next(Path(r"C:\Windows\Microsoft.NET").rglob("System.Management.Automation.dll"), None)

    if powershell_dll_path is None:
        raise FileNotFoundError

    return powershell_dll_path


def add_dll_path_to_sys(powershell_dll_path: Path) -> None:
    """Add the parent folder path of the PowerShell DLL to sys.path."""
    folder_path = powershell_dll_path.parent
    sys.path.append(str(folder_path))


def initialize_powershell_automation() -> None:
    """Initialize PowerShell by adding the required reference and importing the necessary modules."""
    clr.AddReference("System.Management.Automation")


def invoke_powershell_command(command: str, **kwargs: Dict[str, Any]) -> list:
    """Invoke a PowerShell command and return the output."""
    from System.Management.Automation import PowerShell

    ps = PowerShell.Create()
    ps.AddCommand(command)
    for key, value in kwargs.items():
        ps.AddParameter(key, value)
    output = ps.Invoke()
    ps.Stop()

    ps = PowerShell.Create()
    ps.AddCommand("Format-List").AddParameter("InputObject", output)
    ps.AddCommand("Out-String")
    stdout = ps.Invoke()
    stdout = stdout.pop().ToString() if stdout else ""
    return output, stdout


def serialize_output_to_xml(output: list) -> str:
    """Serialize the PowerShell output to XML format."""
    from System.Management.Automation import PSSerializer

    serialized_psobject = PSSerializer.Serialize(output, 2)
    return serialized_psobject


def parse_xml_data(serialized_data: str) -> list:
    """Parse the serialized XML data and return the deserialized objects."""
    serializer = Serializer()
    it = ET.iterparse(StringIO(serialized_data))

    for _, el in it:
        _, _, el.tag = el.tag.rpartition("}")

    root = it.root
    deserialized_objects = [serializer.deserialize(psobject) for psobject in root.findall("Obj")].pop()
    return deserialized_objects


def main() -> None:
    # Find the PowerShell DLL
    powershell_dll_path = find_powershell_dll()

    # Add DLL path to sys.path
    add_dll_path_to_sys(powershell_dll_path)

    # Initialize PowerShell
    initialize_powershell_automation()

    # Invoke the PowerShell command
    output, stdout = invoke_powershell_command(
        "Get-ChildItem", **{"Path": r"HKLM:\Software\Microsoft\Windows\CurrentVersion\\Uninstall"}
    )

    # Serialize the output to XML
    serialized_data = serialize_output_to_xml(output)

    # Parse and deserialize the XML data
    deserialized_objects = parse_xml_data(serialized_data)

    # Print the deserialized objects
    print(deserialized_objects)
    print(f"Human readable output: {stdout}")


if __name__ == "__main__":
    main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment