Windows Agent / schannel Connectivity
Diagnosing and fixing WireGuard tunnel failures for the Windows TMAgent/schannel client.
WireGuard tunnel service won't start after a reboot
Symptom: the TMAgent (agentv200rc29.exe or similar, installed under C:\Program Files\TMAgent)
is running and connects to the engine fine, but the local WireGuard tunnel never comes up. In
Windows Services, WireGuardTunnel$schannel shows Stopped even though its Start type is
Automatic.
Two independent causes have been seen to produce this. Check both — fixing one does not guarantee the other isn't also present.
Step 1 — check what actually failed
Look at the Windows System event log for Service Control Manager events mentioning WireGuard:
Get-WinEvent -FilterHashtable @{LogName="System"; ProviderName="Service Control Manager"} -MaxEvents 20 |
Where-Object { $_.Message -like "*WireGuard*" } |
Select-Object TimeCreated, Id, MessageFor a more precise error, dump WireGuard's own internal log — it reports the exact failure point (interface creation, driver, or socket bind) that the Windows service error alone doesn't show:
& "C:\Program Files\WireGuard\wireguard.exe" /dumplogor read C:\Program Files\WireGuard\Data\log.bin's LastWriteTime to confirm whether a start
attempt is even reaching the tunnel process at all.
Cause A — a Windows UDP port exclusion overlaps WireGuard's listen port
If the log shows something like:
Could not bind socket to 0.0.0.0:51820 (0xc0000022)
Unable to bring up adapter: Access is denied.this is not a schannel or TMAgent problem — it's Windows itself refusing the bind because the port falls inside a reserved exclusion range. Check:
netsh int ipv4 show excludedportrange protocol=udpLook for a range (without a trailing *, i.e. not an "administered" exclusion) that covers 51820
— e.g. 51752–51851. This is typically a dynamic reservation from Hyper-V/WSL2/Docker Desktop's
NAT driver, re-created on every boot. Fix by restarting the Windows NAT driver service:
net stop winnat
net start winnatRe-check the excluded range — it should no longer cover 51820. This alone briefly interrupts Docker/WSL2 networking (a few seconds), so warn the user before running it if other work depends on a live container connection at that moment.
Cause B — the WireGuardNT virtual adapter isn't being instantiated
If Cause A doesn't apply (no port conflict), or the tunnel still won't start after fixing it, check whether the actual virtual network adapter exists in Device Manager:
Get-PnpDevice -Class Net | Where-Object { $_.FriendlyName -like "*WireGuard*" }If nothing is listed at all (not even in an Error state), sc.exe start will fail with:
[SC] StartService FAILED 1058:
The service cannot be started, either because it is disabled or because it has no enabled devices associated with it.First confirm the driver package itself is intact (this rules out a corrupted WireGuard install):
pnputil /enum-drivers | Select-String -Pattern "wireguard" -Context 3,3If the driver is present but no device instance exists, this is usually a broader Windows
networking-stack issue, not specific to WireGuard. Check whether other VPN products on the same
machine are also affected — e.g. PANGP (GlobalProtect) or Fortinet's SSL VPN adapter showing
Error status in Get-PnpDevice -Class Net. If so, that confirms it's an NDIS/virtual-adapter
subsystem problem introduced by the reboot (or a recent Windows Update), not a schannel bug. Fix
with a full network stack reset, which requires a restart to take effect:
netsh winsock reset
netsh int ip reset
# then restart the machineThis resets Winsock LSPs and the IP stack broadly — it can affect other networking tools on the
machine, not just WireGuard. It has, in practice, fixed the WireGuard/schannel adapter
specifically without necessarily clearing the same Error state on other vendors' VPN adapters
(PANGP, Fortinet) — don't assume it fully resolved the underlying cause just because schannel came
back.
Reinstalling the tunnel service manually
If the service registration itself looks broken (present but permanently Stopped, or sc.exe start reports the service doesn't exist despite Get-Service showing it), reinstall it from the
TMAgent's own config file:
& "C:\Program Files\WireGuard\wireguard.exe" /uninstalltunnelservice schannel
& "C:\Program Files\WireGuard\wireguard.exe" /installtunnelservice "C:\Program Files\TMAgent\schannel\schannel.conf"/installtunnelservice can silently register the service without actually starting it
when a same-named service already exists (even a broken/stopped one) — it will return exit code
0 either way. Always verify with Get-Service afterward, and if it's still Stopped, start it
explicitly:
sc.exe start 'WireGuardTunnel$schannel'Use single quotes (or a backtick before $) around the service name in PowerShell — a
double-quoted "WireGuardTunnel$schannel" gets $schannel interpolated as an (empty) variable,
and sc.exe will report the service doesn't exist even though Get-Service shows it does.
Verifying the fix
Confirm the service is running and a real peer handshake is happening, not just that the process started:
Get-Service WireGuardTunnel*
wgA working tunnel shows a recent latest handshake timestamp (well under a minute old) and nonzero
transfer bytes for at least one peer.
Where TMAgent's own logs live
The agent's log directory is C:\ProgramData\TMAgent\, not under Program Files — specifically
C:\ProgramData\TMAgent\tmagent.log. This shows the agent's own connection state to the engine
(got engine connection, config loaded, putting peer / tunnel not running, not adding peer,
etc.) and is the right place to check whether the agent is healthy before assuming the problem is
WireGuard-specific. Note: agent-app-data (under Program Files\TMAgent) is typically empty —
don't expect logs there.
Inspecting the local WFP firewall policy
TMAgent installs its own Windows Filtering Platform (WFP) filters for local ZTNA enforcement
(egress allow rules, mostly at FWPM_LAYER_ALE_AUTH_CONNECT_V4). To see everything currently
registered, including filters from other vendors:
netsh wfp show filters file="C:\path\to\wfpfilters.xml"Search the resulting XML for Threatmatic/TMAgent/schannel to find TMAgent's own filters, and
for the relevant layer (FWPM_LAYER_ALE_AUTH_CONNECT_V4 for outbound TCP, FWPM_LAYER_ALE_AUTH_LISTEN_V4
for listen/bind authorization) to see whether a specific block is in play. In practice, TMAgent's
filters have only ever been observed as narrow PERMIT rules for specific ports/processes — a
missing permit is a different problem from an active block, and neither has so far been the actual
cause of a WireGuard bind failure (see Cause A/B above instead).
How is this guide?
Last updated on