Files
Christian Manivong 1ce42ef099 feat: NAPALM driver for Windows over PowerShell Remoting
Talks PSRP over WinRM via pypsrp, one runspace pool per connection. Each
getter sends one PowerShell script that projects cmdlet results onto flat
fields and ends in ConvertTo-Json, so the Python side parses JSON, not text.

Covers facts, interfaces, IP addresses, ARP, routes and services, plus
service start/stop/restart/enable/disable. Service names are validated and
quoted as PowerShell verbatim strings, typographic quotes included.

Fixtures are synthetic: they pin down the JSON the scripts are designed to
emit. tools/harvest.py records the real output from a host.

Refs christianmanivong/netork#300
2026-09-24 09:23:25 +02:00

68 lines
2.1 KiB
Python

"""Record what the driver's PowerShell scripts emit on a real Windows host.
python tools/harvest.py <host> <user> <label> [--port 5985] [--insecure]
Asks for the password, runs every getter script over one WinRM connection and
writes the raw JSON to tools/harvest-out/<label>/<fixture>.json — the same file
names as tests/fixtures/synthetic/. harvest-out/ is gitignored: scrub serials,
MAC and IP addresses and host names before copying anything into tests/.
"""
from __future__ import annotations
import argparse
import getpass
import pathlib
from napalm_windows import WindowsDriver
from napalm_windows import windows as mod
SCRIPTS = {
"facts": mod._PS_FACTS,
"interfaces": mod._PS_INTERFACES,
"interfaces_ip": mod._PS_INTERFACES_IP,
"arp": mod._PS_ARP,
"routes": mod._PS_ROUTES,
"services": mod._PS_SERVICES,
}
OUT = pathlib.Path(__file__).parent / "harvest-out"
def main() -> None:
ap = argparse.ArgumentParser(description=__doc__.splitlines()[0])
ap.add_argument("host")
ap.add_argument("user")
ap.add_argument("label", help="subdirectory name, e.g. server2022 or win11")
ap.add_argument("--port", type=int, default=5986)
ap.add_argument("--insecure", action="store_true", help="skip certificate validation")
args = ap.parse_args()
driver = WindowsDriver(
args.host,
args.user,
getpass.getpass(f"Password for {args.user}@{args.host}: "),
optional_args={"port": args.port, "ssl_verify": not args.insecure},
)
target = OUT / args.label
target.mkdir(parents=True, exist_ok=True)
driver.open()
try:
for name, script in SCRIPTS.items():
try:
raw = driver._run_raw(script)
except Exception as exc: # record the failure, keep harvesting
raw = ""
print(f" {name}: FAILED — {exc}")
else:
print(f" {name}: {len(raw)} bytes")
(target / f"{name}.json").write_text(raw + "\n")
finally:
driver.close()
print(f"written to {target}")
if __name__ == "__main__":
main()