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
This commit is contained in:
@@ -0,0 +1,75 @@
|
||||
# napalm-windows
|
||||
|
||||
NAPALM driver for Windows Server 2016+ and Windows 10/11, part of the netOrk
|
||||
driver family built on [`napalm-device-types`](https://git.netork.io/christianmanivong/napalm-device-types).
|
||||
|
||||
Driver name: `windows` · Role: `OSDriver` · Transport: PowerShell Remoting
|
||||
(PSRP) over WinRM via [`pypsrp`](https://github.com/jborean93/pypsrp).
|
||||
|
||||
## How it works
|
||||
|
||||
Every getter sends one PowerShell script. The script projects the cmdlet
|
||||
results onto flat, primitive fields and ends in `ConvertTo-Json`, so the
|
||||
Python side parses JSON, never text. All device I/O goes through a single
|
||||
seam (`PsrpTransport.run(script) -> str`), which is what the tests replace.
|
||||
|
||||
One runspace pool stays open per connection, so a poll pays the WinRM
|
||||
handshake once.
|
||||
|
||||
## Supported
|
||||
|
||||
| Method | Source |
|
||||
|---|---|
|
||||
| `get_facts` | `Win32_ComputerSystem`, `Win32_OperatingSystem`, `Win32_BIOS`, registry (`DisplayVersion`, `UBR`) |
|
||||
| `get_interfaces` | `Get-NetAdapter` |
|
||||
| `get_interfaces_ip` | `Get-NetIPAddress` (loopback dropped, IPv6 zone index stripped) |
|
||||
| `get_arp_table` | `Get-NetNeighbor -AddressFamily IPv4` (broadcast, multicast, unreachable dropped) |
|
||||
| `get_route_to` | `Get-NetRoute` (multicast, broadcast, loopback dropped) |
|
||||
| `get_services` / `manage_service` | `Win32_Service`, `Start-/Stop-/Restart-Service`, `Set-Service -StartupType` |
|
||||
|
||||
`running_kernel` carries the full build including the update revision
|
||||
(`10.0.20348.2340`): Windows ships fixes as UBR bumps, which is what CVE
|
||||
matching has to compare against.
|
||||
|
||||
Not yet: packages, Windows Update, scheduled tasks, health metrics, Hyper-V.
|
||||
See netork#300 for the plan.
|
||||
|
||||
## Preparing a host
|
||||
|
||||
WinRM is on by default on Windows Server; on Windows 10/11 run
|
||||
`Enable-PSRemoting` once. Then either
|
||||
|
||||
* **HTTPS (5986, default)** — needs a certificate-backed HTTPS listener, or
|
||||
* **HTTP (5985)** — set the device port to 5985. Traffic is still encrypted at
|
||||
message level (NTLM/Kerberos), credentials never travel in the clear.
|
||||
|
||||
A **local** administrator account additionally needs
|
||||
`LocalAccountTokenFilterPolicy = 1` under
|
||||
`HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System`; without it
|
||||
remote UAC strips the admin token. Domain accounts are not affected.
|
||||
|
||||
## optional_args
|
||||
|
||||
| Key | Default | Meaning |
|
||||
|---|---|---|
|
||||
| `port` | `5986` | WinRM port |
|
||||
| `winrm_ssl` | `port != 5985` | force HTTPS on or off |
|
||||
| `winrm_auth` | `negotiate` | pypsrp auth protocol (`negotiate`, `ntlm`, `kerberos`, `credssp`, `basic`) |
|
||||
| `ssl_verify` | `True` | validate the WinRM certificate |
|
||||
|
||||
## Tests and fixtures
|
||||
|
||||
```bash
|
||||
pip install -e ".[dev]"
|
||||
pytest
|
||||
```
|
||||
|
||||
`tests/fixtures/synthetic/` holds the JSON the scripts are *designed* to emit.
|
||||
To record the real thing from a host:
|
||||
|
||||
```bash
|
||||
python tools/harvest.py <host> <user> <label> [--port 5985] [--insecure]
|
||||
```
|
||||
|
||||
Output lands in `tools/harvest-out/` (gitignored); scrub it before copying
|
||||
anything into `tests/`.
|
||||
Reference in New Issue
Block a user