Error 789 on a Windows L2TP connection means the tunnel died inside the IPsec security exchange, which happens long before Windows sends a user password anywhere. Retrying the password, or resetting it in the directory, cannot move that stage forward. What does move it is rebuilding the connection from PowerShell with the proposal the gateway actually offers, because the Settings wizard chooses IPsec transforms silently and never shows you what it picked. This is the runbook for that: create the profile, pin the proposal, then use a stage table so the next code tells you something.

Create the profile without the wizard

Add-VpnConnection writes a native phone-book entry, so the result is the same object the Settings app edits later. Run it from an elevated session when the connection should exist for every account on the machine, or from the user context when it should stay private:

Add-VpnConnection -Name "Contoso L2TP" `
  -ServerAddress 203.0.113.10 `
  -TunnelType L2tp `
  -EncryptionLevel Required `
  -AuthenticationMethod MSChapv2 `
  -RememberCredential -Force

Match -AuthenticationMethod to what the gateway offers. MSChapv2, EAP and PAP are not interchangeable, and a profile that demands a method the server will not accept fails before any user record is consulted. Keep -EncryptionLevel Required for anything real; Optional lets Windows accept an unencrypted tunnel if the peer offers one, which is a lab shortcut and not a setting to ship.

If you pass -L2tpPsk, that pre-shared key is written into the profile on disk, where anyone who can read the profile on that machine can recover it. Use a certificate for peer authentication when the gateway supports it, and when a PSK is unavoidable, keep it out of the repository and out of shell history rather than pasting it into every provisioning run.

Pin the proposal instead of accepting defaults

Windows fills in the IPsec transforms itself, which is why two machines with what looks like an identical connection can fail differently against the same gateway. Set-VpnConnectionIPsecConfiguration is the supported way to pin them:

Set-VpnConnectionIPsecConfiguration -ConnectionName "Contoso L2TP" `
  -AuthenticationTransformConstants SHA256128 `
  -CipherTransformConstants AES128 `
  -EncryptionMethod AES128 `
  -IntegrityCheckMethod SHA256 `
  -DHGroup Group14 `
  -PfsGroup None `
  -PassThru -Force

That set is one common L2TP/IPsec arrangement, not a universal answer. Each parameter accepts a fixed list of values, and a combination the platform cannot map comes back as a cmdlet error instead of a quietly weakened profile. Treat such an error as a statement about the values, not about your permissions.

Copy the proposal from the gateway documentation or from its live phase-1 and phase-2 settings, and change one field at a time only while the gateway is logging the transforms it refuses. Cycling through five fields produces a connection that works by accident and a record that explains nothing to the next person.

Read a failure by stage, not by error text

789 belongs to a family of codes that all look alike in the client dialog. Place the code against the stage it belongs to before you touch the profile again:

What you seeStage that failedCheck first
Nothing happens, then a timeoutNo IKE response at allServer address, UDP 500 and 4500 reachability, NAT traversal on the gateway
Error 789IKE security exchangeProposal, pre-shared key, certificate trust and client clock
Error 691 or a repeated password promptUser authenticationAccount state, domain, RADIUS or NPS policy
Tunnel up, some hosts unreachableRouting or DNS after PPPSplit-tunnel routes, pushed DNS, remote subnet mask

The two credential roles matter here. A pre-shared key or certificate authenticates the peers to each other, while MSChapv2 or EAP authenticates you inside the tunnel. Resetting a user password cannot fix the first, a new shared secret cannot fix the second, and changing both in one go destroys the evidence of which one was wrong.

On the certificate path, check the client clock, the trust chain and the identity the gateway expects before you consider relaxing validation. Disabling validation turns a visible 789 into a tunnel that connects while trusting the wrong peer, and nothing in the client will tell you that happened. Microsoft's remote-access error list is the reference for the codes themselves, and it separates the security-layer failures from the logon failures.

Verify from both ends before calling it fixed

Read the profile back, but do not expect the proposal in the output. Get-VpnConnection reports the name, server address, tunnel type, encryption level and authentication method, and it knows nothing about transforms, so the read-back confirms the entry exists and points at the right host:

Get-VpnConnection -Name "Contoso L2TP" |
  Select-Object Name, ServerAddress, TunnelType, EncryptionLevel, AuthenticationMethod

Dial from the command line so you get a number instead of a dialog: rasdial "Contoso L2TP" returns the same failure code the interface would, and rasdial "Contoso L2TP" /disconnect clears it between attempts. Then read the gateway side for that same attempt. A strongSwan ipsec statusall or a router IKE log states which proposal arrived and which one was refused, and comparing that with the cmdlet values is the only step that actually proves the two ends agreed.

A successful connect is not the finish line. Open the application the user cares about, because routes, pushed DNS and split-tunnel settings fail after the tunnel is up and produce no error dialog at all.

Automate it, and roll back cleanly

Unattended setup is the reason to script this, and the dial step is where credentials leak. rasdial takes them on its command line, where other local users and most log collectors can read them:

subprocess.run(["rasdial", "Contoso L2TP"], check=True)

Prefer a credential scoped to the account that runs the job, or let the profile store it with -RememberCredential, over passing a password as an argument in a scheduled task. The provisioning commands themselves are safe to repeat with -Force, but they will happily overlay an old proposal, so a re-run only helps if the script carries the current values.

Profiles persist across reboots and outlive the gateway configuration they were built for. When the gateway proposal moves, remove the entry and create it again rather than layering a second set of values on top: Remove-VpnConnection -Name "Contoso L2TP" -Force, then repeat the two cmdlets with the new set.

Close the loop with four checks that live next to the script: Get-VpnConnection shows the expected tunnel type and encryption level; the gateway logs a completed phase 1 and phase 2 for your client address; rasdial returns success and the application opens; and the proposal recorded in the script matches the current gateway setting. When the next 789 arrives, that comparison takes minutes instead of an afternoon.

Аффингæй хæстæг статьялтæ