Skip to content

Instantly share code, notes, and snippets.

@rdev5
Last active October 6, 2016 21:13
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rdev5/fb5aacc9e5f5a89fe21f9bed9d7f3a29 to your computer and use it in GitHub Desktop.
Save rdev5/fb5aacc9e5f5a89fe21f9bed9d7f3a29 to your computer and use it in GitHub Desktop.
Windows Service for disabling network adapters on screen lock, and re-enabling on screen unlock. Must be installed under Local System account to have write access to Event Log and managing network adapters (netsh).
using System;
using System.Diagnostics;
using System.Linq;
using System.Net.NetworkInformation;
namespace WorkstationLockdown
{
public static class NetworkAdapterHelpers
{
/// <summary>
/// Default list of adapters.
/// </summary>
public static readonly string[] Adapters = NetworkInterface.GetAllNetworkInterfaces().Select(a => a.Name).ToArray();
private static void Log(EventLog logger, string msg, EventLogEntryType type = EventLogEntryType.Information)
{
if (logger == null)
return;
if (string.IsNullOrEmpty(msg))
return;
logger.WriteEntry(msg, type);
}
/// <summary>
/// Evaluates if adapter is currently installed.
/// </summary>
/// <param name="adapter"></param>
/// <param name="logger"></param>
/// <returns></returns>
public static bool ValidAdapter(string adapter, EventLog logger = null)
{
Log(logger, string.Format("Looking for {0} in list of valid adapters ({1})", adapter, string.Join(", ", Adapters)));
return !string.IsNullOrEmpty(adapter) && Adapters.Contains(adapter);
}
/// <summary>
/// Enables network adapter.
/// </summary>
/// <remarks>
/// Command: netsh interface set interface {0} enable
///
/// Must be run as administrator
/// </remarks>
/// <param name="adapter"></param>
/// <param name="logger"></param>
public static void EnableAdapter(string adapter, EventLog logger = null)
{
if (!ValidAdapter(adapter, logger))
throw new Exception("Invalid adapter: " + adapter);
var start = new ProcessStartInfo("netsh", string.Format("interface set interface \"{0}\" enable", adapter));
Log(logger, ("Executing: netsh " + string.Format("interface set interface \"{0}\" enable", adapter)));
using (var process = new Process { StartInfo = start })
{
Log(logger,
process.Start()
? string.Format("Re-enabled network adapter ({0})", adapter)
: string.Format("Failed to re-enable network adapter ({0})", adapter));
}
}
/// <summary>
/// Disables network adapter.
/// </summary>
/// <remarks>
/// Command: netsh interface set interface {0} disable
///
/// Must be run as administrator
/// </remarks>
/// <param name="adapter"></param>
/// <param name="logger"></param>
public static void DisableAdapter(string adapter, EventLog logger = null)
{
if (!ValidAdapter(adapter, logger))
throw new Exception("Invalid adapter: " + adapter);
var start = new ProcessStartInfo("netsh", string.Format("interface set interface \"{0}\" disable", adapter));
Log(logger, "Executing: netsh " + string.Format("interface set interface \"{0}\" disable", adapter));
using (var process = new Process { StartInfo = start })
{
Log(logger,
process.Start()
? string.Format("Disabled network adapter ({0})", adapter)
: string.Format("Failed to disable network adapter ({0})", adapter));
}
}
/// <summary>
/// Bulk enables list of network adapters.
/// </summary>
/// <param name="adapters">Specifies alternate list of adapters to enable.</param>
/// <param name="logger"></param>
public static void EnableAll(string[] adapters = null, EventLog logger = null)
{
adapters = adapters ?? Adapters;
if (adapters == null || adapters.Length == 0)
throw new ArgumentNullException("adapters");
foreach (var a in adapters)
EnableAdapter(a, logger);
}
/// <summary>
/// Bulk disables list of network adapters.
/// </summary>
/// <param name="adapters">Specifies alternate list of adapters to disable.</param>
/// <param name="logger"></param>
public static void DisableAll(string[] adapters = null, EventLog logger = null)
{
adapters = adapters ?? Adapters;
if (adapters == null || adapters.Length == 0)
throw new ArgumentNullException("adapters");
foreach (var a in adapters)
DisableAdapter(a, logger);
}
}
}
using System;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
using System.ServiceProcess;
using System.Timers;
namespace WorkstationLockdown
{
public enum ServiceState
{
SERVICE_STOPPED = 0x00000001,
SERVICE_START_PENDING = 0x00000002,
SERVICE_STOP_PENDING = 0x00000003,
SERVICE_RUNNING = 0x00000004,
SERVICE_CONTINUE_PENDING = 0x00000005,
SERVICE_PAUSE_PENDING = 0x00000006,
SERVICE_PAUSED = 0x00000007,
}
[StructLayout(LayoutKind.Sequential)]
public struct ServiceStatus
{
public long dwServiceType;
public ServiceState dwCurrentState;
public long dwControlsAccepted;
public long dwWin32ExitCode;
public long dwServiceSpecificExitCode;
public long dwCheckPoint;
public long dwWaitHint;
};
public partial class WorkstationLockdownService : ServiceBase
{
private const string EventLogName = "WorkstationLockdown";
private const string EventLogSource = "WorkstationLockdownService";
private const double PollingInterval = 60000;
private const long StatusWaitHint = 10000;
/// <summary>
/// The Service Control Manager uses the dwWaitHint and dwCheckpoint members of the SERVICE_STATUS structure to determine how much time to wait for a Windows Service to start or shut down.
/// </summary>
/// <remarks>
/// If OnStart and OnStop methods run long, service can request more time by calling SetServiceStatus again with an incremented dwCheckPoint value.
/// </remarks>
/// <param name="handle"></param>
/// <param name="serviceStatus"></param>
/// <returns></returns>
[DllImport("advapi32.dll", SetLastError = true)]
private static extern bool SetServiceStatus(IntPtr handle, ref ServiceStatus serviceStatus);
/// <summary>
///
/// </summary>
/// <remarks>
/// Constructor arguments allow specifying an alternate log name (else, default EventLogName is used)
/// </remarks>
/// <param name="args">Optional list of arguments passed to command line</param>
public WorkstationLockdownService(string[] args)
{
InitializeComponent();
CanHandleSessionChangeEvent = true;
var source = args.Any() && !string.IsNullOrEmpty(args[0]) ? args[0] : EventLogSource;
EventLog.DeleteEventSource(source);
// TODO: Do we need to also call CreateEventSource when alternate log names are specified on the command line?
if (!EventLog.SourceExists(source))
EventLog.CreateEventSource(source, EventLogName);
eventLog.Source = source;
eventLog.Log = EventLogName;
}
protected override void OnStart(string[] args)
{
var status = new ServiceStatus
{
dwCurrentState = ServiceState.SERVICE_START_PENDING,
dwWaitHint = StatusWaitHint
};
SetServiceStatus(ServiceHandle, ref status);
eventLog.WriteEntry("Service started.");
var timer = new Timer(PollingInterval);
timer.Elapsed += Poll;
status.dwCurrentState = ServiceState.SERVICE_RUNNING;
SetServiceStatus(ServiceHandle, ref status);
}
/// <summary>
/// Handle session change event (i.e. screen lock/unlock).
/// </summary>
/// <remarks>
/// Requires CanHandleSessionChangeEvent = true
/// </remarks>
/// <param name="e"></param>
protected override void OnSessionChange(SessionChangeDescription e)
{
switch (e.Reason)
{
case SessionChangeReason.SessionLock:
OnScreenLock();
break;
case SessionChangeReason.SessionUnlock:
OnScreenUnlock();
break;
}
}
/// <summary>
/// Disables network adapter on screen lock.
/// </summary>
private void OnScreenLock()
{
// Disable network adapter
NetworkAdapterHelpers.DisableAll();
}
/// <summary>
/// Re-enables network adapter on screen unlock.
/// </summary>
private void OnScreenUnlock()
{
// Re-enable network adapter
NetworkAdapterHelpers.EnableAll();
}
private void Poll(object sender, ElapsedEventArgs e)
{
}
protected override void OnStop()
{
eventLog.WriteEntry("Service stopped");
}
protected override void OnContinue()
{
eventLog.WriteEntry("Service resumed");
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment