Explanation of client-side scripting with simple examples

What client-side scripting can do

OpenVPN Access Server supports pushing scripts to VPN clients. By default OpenVPN Connect for Windows and Mac prompts once for the user to confirm if scripts should be executed or not. If the user approves then the script runs from that point on whenever the user connects or disconnects.

For security reasons, client-side script commands are limited to the user context. For system-wide configuration, you must call a program that asks the user for privilege escalation. Client-side scripting handles simple tasks. If you want to do complicated tasks, this also requires that the client-side script calls a program. By calling an external program that can do a privilege escalation request to the user, full system level access can be gained instead and that program can then do any task that any installation file with administrative privileges can do.

Some examples of tasks you can accomplish with client-side scripts:

  • Open a web page automatically after the user connects.
  • Open a network drive in Explorer or Finder automatically.
  • Display a message on the computer screen indicating a successful connection (in addition to the popup window that Connect shows or with additional information). 
  • Run a separate program to remove any temporary files or close any programs left open that only work over the VPN connection.

The language for client-side scripts can be shell language like batch scripting or sh/bash scripting or even Python. You can configure environment variables that are set on the client operating system.

Scripting works on Windows, Mac, and Linux, if the client program permits execution of scripts and if it runs them. For example on Windows and Mac, if you use OpenVPN Connect, then by default it will ask the user if it's okay to run the script, before executing it.

For Linux clients, client-side scripting isn’t implemented out-of-the box. Refer to the “scripting and environmental variables” section in the Reference manual for OpenVPN 2.4 for how to configure this functionality. Currently server-side scripting is only possible using a post-auth script, which has some limitations and caveats. A post-auth script runs after a client has successfully authenticated, but before the client establishes a connection. This offers the ability to add additional criteria before allowing the connection, or additional commands like sending out a notification to the administrator that someone has connected. Note: auto-login type profiles bypass post-auth entirely. Refer to the post-auth page.

How to set up a script on Access Server

You can set up a script for user groups in the Admin Web UI. You can also set up a script using the command line tools.

To create a group (if needed) in the Admin Web UI:

  1. Sign in to your Admin Web UI.
  2. Click User Management > Group Permissions.
  3. Create a new group.

Once the group exists, you can enable client-side scripting:

  1. Click the More Settings icon for the group.
  2. Click Yes or Use Client Scripting?
  3. Click the environment variables, Windows, Mac, or Linux script options that display.
  4. Enter the script into the text box that opens when you click.
  5. Click Save Settings and Update Running Server.
  6. Click on User Management > User Permissions and assign users to your group that you want to execute the client-side script.
  7. Click Save Settings and Update Running Server.

Various options display to set scripts for Windows, Mac, and Linux. For each, you can set scripts for on-connect and on-disconnect. On-connect client-side scripts run when the client establishes a VPN connection. On-disconnect client-side scripts run when the user gives the command to disconnect. OpenVPN Connect will not wait for the client-side scripting to execute before disconnecting the VPN tunnel.

To create a client-side script using the command line tools, refer to “Specify a client-side script” on Managing user and group properties from command line.

It is possible to set a script per user or per group or for the entire server using the special DEFAULT keyword. This must be done through the command line.

Which languages are supported

Supported languages for client-side scripting depend on the languages installed on the VPN client. For example, Windows uses the command line interpreter cmd.exe, by default, but you can specifically indicate you want to use Powershell. We use the shebang method of specifying which language you want to use, and if the interpreter is present and installed, you can use it to run client-side scripting.

To use Powershell, add these lines at the start of a script:

#!"C:\windows\System32\WindowsPowerShell\v1.0\powershell.exe" -ExecutionPolicy ByPass -File
#EXT ps1

To use the integrated Python interpreter that comes with OpenVPN Connect for Windows or Mac:

#!/usr/bin/env python

To use only the integrated Python interpreter that comes with OpenVPN Connect for Windows or Mac:

#PYTHON

To pass the script as a file to an interpreter (last argument is the implicit script filename):

#!"C:\Program Files\Foo Corp\interpreter.exe" -a somearg

On Linux, refer to the Reference manual for OpenVPN 2.4.

OpenVPN Connect for Windows or Mac comes bundled with a slimmed-down version of Python. It doesn't have all of the libraries of a standard Python installation.

Open web page on Windows or Mac

To open a web page with client-side scripting, you specify the command for the OS and the URL you want to open. Windows uses the command, ‘start’ to open the local web browser. Mac uses the command, ‘open’.

To open https://www.openvpn.net/ in an on-connect script for Windows:

start https://www.openvpn.net/

To open https://www.openvpn.net/ in an on-connect script for Mac:

open https://www.openvpn.net/

To open a web browser to https://www.openvpn.net/ using Python:

#!/usr/bin/env python
import os, webbrowser
if os.environ['N_RECONNECTS'] == '0':
    webbrowser.open_new("https://openvpn.net/")

Open an installation file from a network share

To open files from a network share, you use the same ‘start’ command in Windows, and specify the network location. In the examples we're assuming that guest access is allowed to a 'setup' file share on a server at 192.168.47.252, and that it's a standard samba file share.

To open installer.exe in an on-connect script for Windows:

start \\192.168.70.251\setup\installer.exe

Mac requires a bit more complexity. You must mount the network share to a local folder, then open the file in hdiutil (a tool used to open .dmg files which is what most installers come wrapped in on Mac) after which you can then run an installer.

To mount the network share in Mac and access a .dmg installer file:

mkdir ~/setup
mount -t smbfs //GUEST@192.168.47.252/setup ~/setup
hdiutil attach ~/level0/installer.dmg
open "/Volumes/dmg label name here/"

You can cleanup later with:

hdiutil detach "/Volumes/dmg label name here/"
umount ~/setup
rmdir ~/setup

Set environment variables on the client system

There's a special option in the group permissions section where client-side scripts can be specified, to specify environment variables as well. These are set before the client-side script executes. These environmental variables may be defined on the server, pushed to the client, and made available to the script. Using this in the command line to load scripts you could for example set a different environment variable for each user, which can then be used in the script to do something specifically for that user, like open their home folder on a server. This option can set environment variables per user or group specifically via the command line tools.

There's a special environment variable that may be set on the Access Server:

  • PREPATH - if defined, will be prepended to the client's PATH before the script is executed.

And there are two special environment variables set by the OpenVPN Connect backend before scripts execute:

  • N_RECONNECTS - the number of reconnects that have occurred thus far in this connection session.
  • GRACEFUL_DISCONNECT - set to '1' if the disconnect was requested by the user, as opposed to '0' when the disconnect was unexpected.