Skip to content

s3nafps/State-Ops-Controller

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

State-Ops Controller

Enterprise-grade, zero-dependency PowerShell module for automating workstation transitions between air-gapped staging VLANs and production networks with automatic stateful rollback.

PowerShell 5.1+ Dependencies Version


Table of Contents


Overview

State-Ops solves a common problem in air-gapped or segmented network environments: safely switching a workstation's network identity between staging and production VLANs without risking a stranded, half-configured state.

Key Design Principles

Principle Implementation
Zero dependencies Pure PowerShell 5.1+ using only built-in NetAdapter, NetTCPIP, and DnsClient cmdlets
Stateful rollback Full adapter state captured to memory AND disk before any change; automatic rollback on ANY failure
Idempotent Detects if the adapter already matches the target config and skips redundant changes
Auditable Every operation writes structured entries to the Windows Application Event Log
Concurrency-safe Lock file prevents parallel transitions on the same adapter
Fail-fast Pre-flight diagnostics catch physical-layer issues (cable, link, IP conflict) before touching config

Architecture

Transition Pipeline

flowchart TD
    A["0. Test-NetStatePreFlight\n(Adapter up? Cable? IP conflict?)"] -->|PASS| B["1. Acquire Transition Lock"]
    A -->|FAIL| Z["Abort -- no changes made"]
    B --> C["2. Get-NetState\n(Backup to memory + JSON on disk)"]
    C --> D["3. Set-NetState\n(Validate input -> Strip config -> Apply -> Flush DNS)"]
    D --> E["4. Test-NetStateValidation\n(ICMP + TCP + DNS with retry/backoff)"]
    E -->|PASS| F["5. Success\n(Event Log + structured result)"]
    E -->|FAIL| G["ROLLBACK\n(Set-NetState with backup object)"]
    G --> H["Event Log error entry + re-throw"]
    F --> I["Release Lock"]
    H --> I
Loading

Auto-Toggle Launcher Flow

flowchart TD
    A["Load PROD.json + STG.json"] --> B["Get-NetState on adapter"]
    B --> C{"Current IP matches\na known profile?"}
    C -->|"Matches PROD"| D["Auto-target: STG"]
    C -->|"Matches STG"| E["Auto-target: PROD"]
    C -->|"No match"| F["Interactive menu:\n1=PROD  2=STG  Q=Quit"]
    D --> G["Invoke-EnvironmentTransition"]
    E --> G
    F --> G
    G -->|OK| H["Success banner + summary"]
    G -->|FAIL| I["Rollback + error details"]
Loading

Directory Structure

State-Ops Controller/
|-- Switch-Environment.ps1          # Auto-toggle launcher (run this)
|-- StateOps/
|   |-- StateOps.psm1              # Core module (8 public + 5 private functions)
|   |-- StateOps.psd1              # Module manifest v2.1.0
|   |-- Environments/
|       |-- PROD.json              # Production network profile
|       |-- STG.json               # Staging VLAN profile

Prerequisites

Requirement Details
OS Windows 10 / Server 2016 or later
PowerShell 5.1+ (ships with Windows)
Privileges Must run as Administrator (elevated session)
Network Static IP adapter (e.g., Ethernet); DHCP adapters will lose their lease
Dependencies None -- uses only built-in Windows cmdlets

Quick Start

1. Configure the Environment Profiles

Edit the JSON files in StateOps/Environments/ to match your actual network:

PROD.json -- Production network

{
    "AdapterName":    "Ethernet",
    "IPAddress":      "10.0.50.25",
    "PrefixLength":   24,
    "DefaultGateway": "10.0.50.1",
    "DnsServers":     ["10.0.50.10", "10.0.50.11"],
    "VlanId":         50
}

STG.json -- Staging VLAN

{
    "AdapterName":    "Ethernet",
    "IPAddress":      "10.0.20.25",
    "PrefixLength":   24,
    "DefaultGateway": "10.0.20.1",
    "DnsServers":     ["10.0.20.10", "10.0.20.11"],
    "VlanId":         20
}

2. Run the Launcher

Open an elevated PowerShell window and run:

.\Switch-Environment.ps1

The script will:

  1. Detect your current environment (PROD or STG) by matching the adapter's IP
  2. Prompt to confirm the switch to the opposite environment
  3. Execute the full transition pipeline with pre-flight, backup, apply, validate, and rollback protection

3. Or Use the Module Directly

Import-Module .\StateOps\StateOps.psd1

# Snapshot current state
$current = Get-NetState -AdapterName 'Ethernet'

# Load a profile and transition
$target = Import-EnvironmentProfile -Path '.\StateOps\Environments\PROD.json'

Invoke-EnvironmentTransition -TargetConfiguration $target `
                              -ValidationTarget '10.0.50.1' `
                              -ValidationTcpPort 389 `
                              -Force

Environment Profiles

Profiles are plain JSON files stored in StateOps/Environments/. They can be version-controlled, templated, and validated at load time.

Required Fields

Field Type Description
AdapterName string Windows adapter display name (e.g., Ethernet)
IPAddress string Target IPv4 address (validated via IPAddress.TryParse)
PrefixLength int Subnet prefix length (1-32)
DnsServers string[] One or more DNS server IPv4 addresses

Optional Fields

Field Type Description
DefaultGateway string IPv4 gateway; omit for isolated/gateway-less VLANs
VlanId int 802.1Q VLAN tag; applied via adapter advanced properties
_meta object Documentation metadata (ignored by the module)

Profile Operations

# Load and validate a profile
$config = Import-EnvironmentProfile -Path '.\StateOps\Environments\PROD.json'

# Export current adapter state as a new profile
Export-EnvironmentProfile -AdapterName 'Ethernet' -Path '.\StateOps\Environments\CurrentState.json'

# Export an existing config object
Export-EnvironmentProfile -Configuration $config -Path '.\backup.json'

Function Reference

Core Pipeline

Function Purpose Key Parameters
Get-NetState Snapshots full adapter state (IP, DNS, GW, VLAN, MAC, link speed, status) -AdapterName, -ExportPath
Set-NetState Validates input, strips existing config, applies new static IP/DNS, flushes DNS cache -Configuration, -Force
Test-NetStateValidation ICMP ping + TCP port + DNS resolution with configurable retry/backoff -TargetHost, -TcpPort, -DnsName, -RetryCount
Invoke-EnvironmentTransition Full orchestrated pipeline with pre-flight, backup, apply, validate, and auto-rollback -TargetConfiguration, -ValidationTarget, -Force

Diagnostics

Function Purpose Key Parameters
Test-NetStatePreFlight Checks adapter existence, operational status, cable, link speed, and IP conflicts via ARP -AdapterName, -TargetIP

Profiles

Function Purpose Key Parameters
Import-EnvironmentProfile Loads and validates a JSON profile -Path
Export-EnvironmentProfile Serializes a config or live state to JSON -Configuration or -AdapterName, -Path

Audit

Function Purpose Key Parameters
Get-StateOpsLog Queries Windows Event Log for StateOps entries -Hours, -EntryType, -MaxRecords

Safety Mechanisms

1. Input Validation

Every configuration object is validated before use:

  • IPv4 addresses parsed via [System.Net.IPAddress]::TryParse()
  • Prefix length enforced to 1-32 range
  • DNS array must contain at least one valid IPv4 address
  • Required properties checked: AdapterName, IPAddress, PrefixLength, DnsServers

2. Idempotency Detection

Set-NetState compares the target config against the adapter's live state. If IP, prefix, and DNS already match, the operation is skipped with a [SKIP] message. Override with -Force.

3. Pre-Flight Diagnostics

Test-NetStatePreFlight runs before every transition (unless -SkipPreFlight):

  • Adapter exists and is status Up
  • Media connection state is Connected (cable plugged in)
  • Link speed reported
  • ARP probe for IP conflicts on the target address

4. Transition Lock

A .lock file in $env:TEMP\StateOps\ prevents concurrent transitions on the same adapter. Stale locks (older than 300 seconds) are automatically cleared.

5. Persistent Backup

Before applying any changes, the current state is:

  • Held in memory (for immediate rollback)
  • Written to $env:TEMP\StateOps\backup_<adapter>_<timestamp>.json (for manual recovery)

6. Automatic Rollback

If Set-NetState or Test-NetStateValidation throws, the catch block in Invoke-EnvironmentTransition:

  1. Logs a Critical event to the Windows Event Log
  2. Calls Set-NetState with the backup object to restore the original config
  3. Re-throws the error to the caller

7. DNS Cache Flush

Clear-DnsClientCache is called automatically after every DNS server change to prevent stale resolution.


Audit & Logging

State-Ops registers itself as an Event Log source under Application/StateOps and writes entries at every pipeline boundary:

Event ID Category Trigger
1000 StateCapture Get-NetState completes a snapshot
2000 ConfigApply Set-NetState applies or skips a config
3000 Validation Test-NetStateValidation reports pass/fail
4000 Rollback Automatic rollback executed
5000 TransitionComplete Full pipeline succeeds
6000 PreFlight Pre-flight diagnostics result
7000 ProfileIO Profile imported or exported
9000 CriticalFailure Fatal errors (apply fail, rollback fail)

Querying Logs

# Last 8 hours, all entry types
Get-StateOpsLog -Hours 8

# Only errors from the last 24 hours
Get-StateOpsLog -EntryType Error

# Formatted table
Get-StateOpsLog -Hours 1 | Format-Table TimeGenerated, EntryType, Message -AutoSize

Configuration Schema

Get-NetState Output Object (StateOps.NetState)

AdapterName    : Ethernet
InterfaceIndex : 5
IPAddress      : 10.0.50.25
PrefixLength   : 24
DefaultGateway : 10.0.50.1
DnsServers     : {10.0.50.10, 10.0.50.11}
VlanId         : 50
MacAddress     : AA-BB-CC-DD-EE-FF
LinkSpeed      : 1 Gbps
AdapterStatus  : Up
MediaState     : Connected
Timestamp      : 2026-03-01T12:00:00.0000000+01:00
ComputerName   : WKS-001
CapturedBy     : admin

Test-NetStateValidation Result (StateOps.ValidationResult)

Success       : True
IcmpSuccess   : True
TcpSuccess    : True
DnsSuccess    :             # null = not tested
LatencyMs     : 1.23
RetryAttempts : 0
TargetHost    : 10.0.50.1
Timestamp     : 2026-03-01T12:00:05.0000000+01:00

Invoke-EnvironmentTransition Result (StateOps.TransitionResult)

Success          : True
BackupState      : [StateOps.NetState]
AppliedState     : [PSCustomObject]
ValidationResult : [StateOps.ValidationResult]
BackupFile       : C:\Users\admin\AppData\Local\Temp\StateOps\backup_Ethernet_20260301_120000.json
Duration         : 00:00:07.3421234
Timestamp        : 2026-03-01T12:00:07.0000000+01:00

Troubleshooting

Symptom Cause Resolution
State-Ops requires an elevated PowerShell session Not running as admin Right-click PowerShell > Run as Administrator
Adapter 'X' not found Wrong AdapterName in profile Run Get-NetAdapter to list actual adapter names
A transition is already in progress Stale lock from crashed session Delete $env:TEMP\StateOps\StateOps_*.lock manually
Pre-flight FAILED: Media 'Disconnected' Network cable unplugged Check physical connection
Validation FAILED after N attempts Target unreachable on new VLAN Verify VLAN trunking, firewall rules, and gateway reachability
ROLLBACK FAILED Multiple cascading errors Manually restore from backup JSON at $env:TEMP\StateOps\
Module won't parse on PS 5.1 Non-ASCII characters in file Ensure file uses ASCII-only encoding

Contributing

See CONTRIBUTING.md for development guidelines, code standards, and PR workflow.

Changelog

See CHANGELOG.md for version history and release notes.

Author

Mohamed Senator -- Network Automation Engineer

License

This project is licensed under the MIT License.

About

Stateful PowerShell network controller for automating secure workstation transitions between production and air-gapped VLANs with Fortinet integration.

Topics

Resources

License

Contributing

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors