Automating Network-Aware Script Execution: Triggering Actions on Connection Changes


2 views

Modern workstations often need to adapt to different network environments dynamically. The requirement to execute specific scripts when network conditions change - whether switching between WiFi networks, detecting new Ethernet connections, or noticing VPN activations - is common in enterprise environments.

Windows Approach

For Windows systems, we can leverage the built-in Task Scheduler with event triggers:

# PowerShell script to detect network changes
Register-EngineEvent -SourceIdentifier NetworkChange -Action {
    $currentNetwork = Get-NetConnectionProfile
    if ($currentNetwork.Name -eq "Office-WiFi") {
        # Office network actions
        Set-AudioDevice -Mute $true
        Set-DnsClientServerAddress -InterfaceIndex $currentNetwork.InterfaceIndex -ServerAddresses ("192.168.1.1","8.8.8.8")
    } else {
        # Default actions
        Set-AudioDevice -Mute $false
        Set-DnsClientServerAddress -InterfaceIndex $currentNetwork.InterfaceIndex -ResetServerAddresses
    }
}

Linux Implementation

On Linux systems, we can use NetworkManager's dispatcher scripts:

#!/bin/bash
# /etc/NetworkManager/dispatcher.d/99-network-actions

interface=$1
status=$2

case "$status" in
    up)
        SSID=$(iwgetid -r)
        if [ "$SSID" = "Office-WiFi" ]; then
            # Office network actions
            amixer set Master mute
            cp /etc/resolv.conf.office /etc/resolv.conf
            systemctl restart cups
        else
            # Default actions
            amixer set Master unmute
            cp /etc/resolv.conf.home /etc/resolv.conf
        fi
        ;;
esac

For a more portable solution, consider using Python with the psutil library:

import psutil
import time
import subprocess

last_state = None

while True:
    current_state = []
    for nic, addrs in psutil.net_if_addrs().items():
        if addrs and nic != 'lo':
            current_state.append(nic)
    
    if current_state != last_state:
        print(f"Network change detected: {current_state}")
        # Add your custom logic here
        if 'eth0' in current_state:
            subprocess.run(["pactl", "set-sink-mute", "0", "1"])
        last_state = current_state
    
    time.sleep(5)

For more sophisticated scenarios, you might want to:

  • Incorporate multiple detection methods (SSID, IP range, gateway MAC)
  • Implement proper logging for debugging
  • Add error handling for temporary network flaps
  • Consider security implications of automatic configuration changes

In corporate environments, you might want to package this as a proper service/daemon with:

  • Configuration files for different network profiles
  • Proper init/systemd integration
  • User permission management
  • Centralized monitoring capabilities

To run scripts automatically when network connections change, we need reliable detection mechanisms. Here are the most common approaches across different operating systems:

Windows Solution

On Windows, we can use PowerShell with WMI events to monitor network changes:


# PowerShell script to monitor network changes
Register-WmiEvent -Query "SELECT * FROM __InstanceModificationEvent WITHIN 5 WHERE TargetInstance ISA 'Win32_NetworkAdapter' AND TargetInstance.NetConnectionStatus=2" 
-Action {
    # Your custom actions here
    Write-Host "Network connection changed!"
    # Example: Change DNS when connected to office network
    if (Test-Connection -ComputerName "office-router" -Count 1 -Quiet) {
        Set-DnsClientServerAddress -InterfaceIndex (Get-NetAdapter | Where-Object {$_.Status -eq "Up"}).ifIndex -ServerAddresses ("192.168.1.1","8.8.8.8")
    }
}

Linux Solution

For Linux systems, NetworkManager's dispatcher scripts work well:


#!/bin/bash
# Save as /etc/NetworkManager/dispatcher.d/99-network-change

INTERFACE=$1
ACTION=$2

if [ "$ACTION" = "up" ]; then
    # Check if connected to office WiFi
    if [[ "$(iwgetid -r)" == "OfficeWiFi" ]]; then
        # Mute system
        amixer set Master mute
        # Change DNS
        nmcli con mod "$(iwgetid -r)" ipv4.dns "192.168.1.1,8.8.8.8"
        # Restart network to apply changes
        nmcli con up "$(iwgetid -r)"
    fi
fi

To determine when you're on specific networks, consider these identification methods:


# Python example to detect network
import socket
import subprocess

def get_current_network():
    try:
        # For WiFi networks
        if sys.platform == "linux":
            return subprocess.check_output(["iwgetid", "-r"]).decode().strip()
        elif sys.platform == "darwin":
            return subprocess.check_output(["/System/Library/PrivateFrameworks/Apple80211.framework/Versions/Current/Resources/airport", "-I"]).decode()
        # For gateway-based detection (cross-platform)
        gateway = socket.gethostbyname(socket.gethostname())
        return gateway
    except:
        return None

For more complex scenarios, consider these approaches:

  • NetworkManager's connection-specific hooks: Create scripts that run when specific connections activate
  • systemd-networkd: Use .network files with ExecStartPost directives
  • Third-party tools: Tools like NetWatcher (Windows) or ifplugd (Linux) can trigger scripts

Here's a comprehensive Python script that handles multiple office network scenarios:


import os
import platform
import time

def is_office_network():
    # Implement your specific office network detection logic
    return True  # Replace with actual detection

def set_office_settings():
    if platform.system() == "Linux":
        os.system("amixer set Master mute")
        os.system("nmcli con mod OfficeWiFi ipv4.dns '192.168.1.1'")
        os.system("lpadmin -d 'Office_Printer'")
    elif platform.system() == "Windows":
        os.system('netsh interface ip set dns "Ethernet" static 192.168.1.1')
        # Add Windows-specific commands here

def set_home_settings():
    # Revert changes when not on office network
    pass

while True:
    if is_office_network():
        set_office_settings()
    else:
        set_home_settings()
    time.sleep(60)  # Check every minute

For a more portable solution, this Python script uses psutil to monitor network changes:


import psutil
import time

last_state = None

def network_changed():
    global last_state
    current = psutil.net_if_stats()
    if current != last_state:
        last_state = current
        return True
    return False

while True:
    if network_changed():
        print("Network state changed!")
        # Add your custom logic here
    time.sleep(5)

When implementing network-triggered scripts:

  • Always validate network conditions before making changes
  • Implement proper error handling for network operations
  • Consider adding authentication for sensitive operations
  • Log all automated changes for audit purposes