Sometimes your job will force you to use antequated technology like a VPN client to access resources (ever heard of SSO??).. When that breaks things, it can be a pain. In my case, whenever I connect to Cisco Anyconnect VPN, I get booted off all my WSL2 SSH sessions. As I spend all day in a WSL2 Ubuntu terminal on my Windows 10 deskop machine, it gets a bit tedious to reconnect things whenever I am forced to use the VPN.

In my scenario, I connect to the VPN (which in my case is a split tunnel, which interferes with the vEthernet (WSL) Hyper-V network adaptor that WSL2 uses. My sessions hang, I can’t resolve DNS etc. Disaster. To fix this issue, I can run the following 2 lines in an Administrator privileged Powershell window:

Get-NetAdapter | Where-Object {$_.InterfaceDescription -Match "Cisco AnyConnect"} | Set-NetIPInterface -InterfaceMetric 4000
Get-NetIPInterface -InterfaceAlias "vEthernet (WSL)" | Set-NetIPInterface -InterfaceMetric 1

This fairly self explanitory script bumps up the preference of the Cisco AnyConnect interface and drops the WSL down a peg or 3999. Note this is a metric, not a cost.

OK that’s fine, but doing that every time you connect to the VPN is annoying. To automate this, we can use Task Scheduler in Windows.

Before we start, we need to enable the running of scripts on our local machine. To do this, follow steps here. For reference, I only want my local machine to be able to run scripts created on this machine, so I ran:

Get-ExecutionPolicy -List
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser

Step 1: We open up Task Scheduler and create a new task. I found it important to run whether user is logged in or not, run with highest privileges and tell it to run as my user (who is local admin). Add a new task to Task Scheduler

Step 2: We want to create a trigger for this event. Click New.. and get triggered Add a new trigger for our task

Step 3: Trigger the task On an event and use Microsoft-Windows-NetworkProfile/Operational log, with NetworkProfile as source, and Event ID as 10000. This is when an interface goes up or down. Define our trigger

Step 3a: Create a powershell script to be run, stick it somewhere on your C drive, such as C:\scripts: Sample script:

# vpn-script.ps1

# Ensure that the script can run by setting the execution policy
Set-ExecutionPolicy Bypass -Scope Process -Force

# Change the interface metric for Cisco AnyConnect adapter
Get-NetAdapter | Where-Object {$_.InterfaceDescription -Match "Cisco AnyConnect"} | Set-NetIPInterface -InterfaceMetric 4000

# Change the interface metric for vEthernet (WSL) adapter
Get-NetIPInterface -InterfaceAlias "vEthernet (WSL)" | Set-NetIPInterface -InterfaceMetric 1

Step 4: Create an action to do when triggered. Click New… and here we go Add a new action for our task

Step 5: Define our action as starting a progam, run powershell with the argument -File C:\scripts\vpn-script.ps1 (or whatever you want to call your script). Point our action to run our script

Now when we connect to AnyConnect, our WSL2 sessions should be able to route nicely (they will all go over the VPN, which in my case was desirable). We can test this by pinging google.com from our WSL2 session before and after joining the VPN. The latency (and dst IP) will likely change. If ping doesn’t work, something is wrong.