Skip to content

Instantly share code, notes, and snippets.

@webtroter
Last active September 8, 2025 16:43
Show Gist options
  • Select an option

  • Save webtroter/36477c014e4cc5f169468891fa7652f2 to your computer and use it in GitHub Desktop.

Select an option

Save webtroter/36477c014e4cc5f169468891fa7652f2 to your computer and use it in GitHub Desktop.
WireGuard Windows Routing Helper Script

WireGuard Windows Routing Helper Script

This script is developped in a PowerShell 7 environment. The script works PowerShell for Windows right now. I might try to be smart about that in the future.

The tunnel configuration is only an example for the Table, [Post|Pre][Up|Down] parameters. I don't know right now if the peer configuration works. Help for that would be appreciated

Setting Up WireGuard Dangerous Script Execution

To Setup the registry run the script with the -Setup switch in a Administrative PowerShell Console. Add the -RestartWGService switch to restart the Wireguard Service while setting up.

.\Invoke-WireGuardRoutingHelper.ps1 -Setup -RestartWGService

Configuring the WireGuard Tunnel

You can use the switch -NoDefaultRoute to not add de default route, and the switch -RouteOne to add the Route One. You can change the route in the the script.

PostUp = pwsh.exe -File "C:\Invoke-WireGuardRoutingHelper.ps1" -PostUp -NoDefaultRoute -RouteOne
[CmdletBinding(DefaultParameterSetName = "PreDown")]
param (
[Parameter(ParameterSetName = "Setup")]
[switch]
$Setup,
[Parameter(ParameterSetName = "Setup")]
[switch]
$RestartWGService,
# WireGuard Interface
[Parameter(Position = 0)]
[string]
$WireGuardInterfaceName = $env:WIREGUARD_TUNNEL_NAME,
# Post Up Switch
[Parameter(ParameterSetName = "PostUp")]
[switch]
$PostUp,
# Post Up Switch
[Parameter(ParameterSetName = "PreDown")]
[switch]
$PreDown,
# No Default Route
[Parameter(ParameterSetName = "PostUp")]
[Parameter(ParameterSetName = "PreDown")]
[switch]
$NoDefaultRoute,
# Use Route One
[Parameter(ParameterSetName = "PostUp")]
[Parameter(ParameterSetName = "PreDown")]
[switch]
$RouteOne
)
$InformationPreference = "Continue"
# $ErrorActionPreference = "SilentlyContinue"
function Invoke-WireGuardExternalRoutingSetup {
[CmdletBinding()]
param (
# Restart the Wireguard service if demanded
[Parameter()]
[switch]
$RestartWGService
)
begin {
}
process {
if ($PSCmdlet.ShouldContinue("DangerousScriptExecution", "Activating")) {
$ActivateDangerousScriptExecutionSplat = @{
Path = "hklm:\Software\WireGuard"
Name = "DangerousScriptExecution"
PropertyType = 'DWord'
Value = 1
ErrorAction = 'SilentlyContinue'
}
New-ItemProperty @ActivateDangerousScriptExecutionSplat
if ($RestartWGService) {
Write-Information "Restarting the Wireguard Service"
Get-Service WireGuardManager | Restart-Service -Verbose
}
else {
Write-Warning "You have to restart the wireguard service to apply the registry change"
}
}
}
end {
}
}
if ($Setup) {
Invoke-WireGuardExternalRoutingSetup -RestartWGService:$RestartWGService
} else {
$WireGuardInterface = Get-NetAdapter -Name $WireGuardInterfaceName
}
if (-not $NoDefaultRoute) {
$DefaultNetRouteSplat = @{
InterfaceAlias = $WireGuardInterface.InterfaceAlias
DestinationPrefix = "0.0.0.0/0"
RouteMetric = 35
Confirm = $false
}
Write-Information -MessageData "Taking care of Default Route"
switch ($PSCmdlet.ParameterSetName) {
"PostUp" { New-NetRoute @DefaultNetRouteSplat | Out-Null }
"PreDown" { Remove-NetRoute @DefaultNetRouteSplat | Out-Null }
Default {}
}
}
if ($RouteOne) {
$RouteOneSplat = @{
InterfaceAlias = $WireGuardInterface.InterfaceAlias
DestinationPrefix = "192.168.0.0/24"
Confirm = $false
}
Write-Information -MessageData "Taking care of Route One"
switch ($PSCmdlet.ParameterSetName) {
"PostUp" { New-NetRoute @RouteOneSplat | Out-Null }
"PreDown" { Remove-NetRoute @RouteOneSplat | Out-Null }
Default {}
}
}
# Bonus DNS Snippet
# Set to $true to enable
$SetupDNS = $false
if ($SetupDNS){
$setDnsClientServerAddressSplat = @{
InterfaceAlias = $WireGuardInterface.InterfaceAlias
}
Write-Information -MessageData "Taking care of DNS"
switch ($PSCmdlet.ParameterSetName) {
"PostUp" {
Set-DnsClientServerAddress @setDnsClientServerAddressSplat -ServerAddresses "192.168.0.1"
}
"PreDown" {
Set-DnsClientServerAddress @setDnsClientServerAddressSplat -ResetServerAddresses
}
Default {}
}
}
[Interface]
PrivateKey = redacted
Address = 10.0.10.4/24
PostUp = pwsh.exe -File "C:\Invoke-WireGuardRoutingHelper.ps1" -PostUp
PreDown = pwsh.exe -File "C:\Invoke-WireGuardRoutingHelper.ps1" -PreDown
Table = off
[Peer]
PublicKey = redacted
AllowedIPs = 10.0.10.0/24, 0.0.0.0/1
Endpoint = redacted
@roninpawn
Copy link

This is great, now that I've got it working.
Thanks so much for automating it!

That said, I got really jammed up at least 3 times, trying to get it up and running. First, because I was relying on Win10's baked-in PowerShell to execute the script -- which it doesn't. So I needed to install PowerShell 7.0 and let the installer give me a real PATH registration for the new pwsh.

Then, before I realized that powershell was blocking execution because it's a foreign, unsigned script, I ended up adding the needed:
Computer\HKEY_LOCAL_MACHINE\SOFTWARE\WireGuard\DangerousScriptExecution = DWORD32(1) by hand.

Then when the WireGuard log showed that it was being blocked for lack of a signature, I figured I'd just lower my execution policy threshold to 'unrestricted' to get it through. But somehow that wasn't enough! And I had to go find out that you can just do this instead:

Unblock-File -Path "<your-path-to>\Invoke-WireGuardRoutingHelper.ps1"

And THEN!... It worked. And I now have a discreet, always-on VPN tunnel that runs silently in the background, while I innocently check my email over the unmasked public connection from the ISP. It's a real thing of beauty, this! 👍

@webtroter
Copy link
Author

webtroter commented Sep 8, 2025

Hi @roninpawn , what problem did you encounter when using Windows 10's Windows PowerShell? Which error did you get?

Can you confirm your Windows PowerShell version (using $PSVersionTable.PSVersion.ToString())?

About your other two issues :

  1. Yes, you need to set the ExecutionPolicy to Unrestricted. Can also be done when calling the Powershell executable -ExecutionPolicy <ExecutionPolicy> about_PowerShell_exe -ExecutionPolicy and PowerShell execution policies
  2. Yes, you always need to Unblock-File when downloading scripts from the Internet. It clears the Zone.Identifier ADS that is added to files downloaded from the Internet.

I hope this clarifies some things.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment