# PowerShell Automation Center A unified framework for managing Windows automation tasks with a modular, extensible feature system. All configuration and execution flows through a single entry point: `configure.ps1`. ## Quick Start Clone or extract the repo to any location, then: ```powershell # Navigate to the repo folder (any path works) cd # Run the main menu .\configure.ps1 ``` All paths are relative to `configure.ps1`, so the repo is portable. ## Architecture ### Entry Point: `configure.ps1` The only file you interact with directly. Provides a menu-driven interface for: - **Check**: View registration status of the background runner task - **Register**: Create a scheduled task that runs automation features at logon and every 2 minutes - **Remove**: Unregister the scheduled task - **Configure**: Adjust per-feature settings (toggles, custom values) ### Core Structure ``` ArnePowershellAutomation/ ├── configure.ps1 # Single user entry point └── internal/ ├── runner.ps1 # Scheduled task entry point (runs every 2 min + at logon) ├── lib/ # Shared utilities │ ├── Logging.ps1 # Centralized logging with rotation │ ├── Config.ps1 # Configuration and state I/O │ ├── Elevation.ps1 # UAC elevation helper │ ├── NetworkUtils.ps1 # DNS suffix detection │ ├── ToastHelper.ps1 # Windows 11 toast notifications │ ├── PromptHelper.ps1 # Multi-choice dialog boxes (up to 4 buttons) │ └── SandwichAutoOrder.ps1 # Browser keyboard automation for sandwich auto-order ├── features/ # Automation feature modules │ ├── DynamicLock.ps1 # Toggle Dynamic Lock on network presence │ ├── DefaultBrowser.ps1 # Monitor default browser setting │ ├── SandwichReminder.ps1 # Time-based reminder with snooze options │ └── SandwichReminder-AutoOrder.ps1 # Personal browser automation for sandwich ordering └── data/ ├── config.json # Feature toggles & settings (auto-seeded) ├── state/ │ └── state.json # Per-feature runtime state └── logs/ ├── automation-*.log # Daily rotating logs (7-day retention) ├── elevated-process.log # Elevation diagnostics ├── last-register-result.json # Last registration result └── last-remove-result.json # Last removal result ``` ### Execution Flow **At Logon / Every 2 Minutes:** 1. Scheduled task launches `internal/runner.ps1` 2. Runner loads all lib utilities and feature modules 3. For each enabled feature: - Reads configuration from `internal/data/config.json` - Reads previous state from `internal/data/state/state.json` - Calls `Invoke-Feature` function - Captures errors; one feature failure doesn't break others - Saves updated state back to file 4. Logs all activity to `internal/data/logs/automation-YYYY-MM-DD.log` **For Configuration Changes:** 1. User selects menu option 4 (Configure) 2. Navigate feature menu (numbers to toggle, C for sub-menu) 3. For each setting, enter value or accept default 4. Config is saved to `internal/data/config.json` immediately 5. Changes take effect on next scheduled task run ## Feature Contract Each feature in `internal/features/` must export: ### `$FeatureMeta` Variable ```powershell $FeatureMeta = @{ Name = "My Feature" Description = "What this feature does" Settings = @( @{ Key = "settingKey1"; Label = "Display Label"; Type = "string"; Default = "value"; Description = "Help text" } @{ Key = "settingKey2"; Label = "Port"; Type = "int"; Default = 8080; Description = "Port number" } @{ Key = "settingKey3"; Label = "Enabled"; Type = "bool"; Default = $true; Description = "Enable this?" } ) } ``` ### `Invoke-Feature` Function ```powershell function Invoke-Feature { param( [Parameter(Mandatory)][hashtable]$Config, # Feature settings from config.json [Parameter(Mandatory)][hashtable]$State # Feature state from state.json ) # Perform work here # Use Write-Log -Feature "MyFeature" for logging # Return updated $State hashtable return $State } ``` ### Built-in Utilities Available to Features - **Logging.ps1**: `Write-Log -Level (Info|Warn|Error) -Message -Feature` - **Config.ps1**: `Get-Config`, `Save-Config`, `Get-State`, `Save-State` - **NetworkUtils.ps1**: `Test-DnsSuffixConnected -Suffix` - **ToastHelper.ps1**: `Show-ToastNotification -Title -Body -Buttons` - **Elevation.ps1**: `Test-Administrator`, `Request-Elevation` ## Included Features ### DynamicLock Enables/disables Windows Dynamic Lock based on network connectivity. - **Settings**: Network domain suffix (e.g., "example.com"), revert timeout in minutes - **Logic**: When connected to configured network, enables Dynamic Lock (`EnableGoodbye`=1); when disconnected, reverts after timeout - **State Tracked**: Current connection status, last connected timestamp ### DefaultBrowser Monitors if your default browser matches expected ProgId (app identifier). - **Settings**: Target ProgId (e.g., "FirefoxURL", "OperaGXStable") - **Logic**: On each run, reads current ProgId; if mismatch, shows a Yes/No dialog; "Yes" opens Windows Settings → Default apps for manual selection; max once per day - **State Tracked**: Last notification date to avoid spam - **Note**: Windows 11 protects the default browser registry key with a hash; the browser cannot be changed programmatically, hence the guided Settings approach ### SandwichReminder Shows a reminder dialog at a specific time on a specific network with snooze options. - **Settings**: Reminder time (HH:MM), network domain suffix, reminder URL, notification window in minutes - **Logic**: If on configured network AND current time is within window of reminder time AND not shown today, display a 4-choice dialog: Order now / Snooze 15 min / Snooze 1 hour / No - **State Tracked**: Last shown date, snooze-until timestamp - **Auto-order delegation**: If `SandwichReminder-AutoOrder` feature is enabled, selecting "Order now" triggers the automated browser flow instead of just opening the URL ### SandwichReminder-AutoOrder Personal browser automation feature that drives the sandwich ordering website via keyboard navigation. - **Settings**: Base URL, item ID, browser window title hint, tab counts for each navigation step, delays, calibration mode - **Logic**: Opens the item modal URL, brings the browser window to the foreground (with retry), then sends keyboard inputs to: toggle option checkboxes → click add-to-cart → refresh page → tab to mini-cart → open cart → tab to confirm order button → open delivery popup - **Key settings**: - `tabsToOption1` / `tabsBetweenOptions` / `tabsToAddButton`: navigation within item modal - `refreshBeforeCart`: send F5 after add-to-cart to reset focus to a known page position - `tabsToCartButton` / `tabsToConfirmButton`: navigation after refresh - `calibrationOnly` + `calibrationTabs`: safe mode to manually count tab stops without clicking - **Note**: Uses WScript.Shell SendKeys (best-effort); relies on stable tab order in the target website ## Usage Guide ### Main Menu ``` 1) Check Registration Status → Displays current task registration, last run time, next run time 2) Register Runner → Creates scheduled task (AtLogon trigger + 2-min repetition) → If not admin, prompts for UAC elevation → Updates internal/data/logs/last-register-result.json 3) Remove Runner → Unregisters the scheduled task → If not admin, prompts for UAC elevation → Updates internal/data/logs/last-remove-result.json 4) Configure Features → Submenu with feature toggles and per-feature settings → Enter number to toggle (on/off) → Enter C to configure settings → Q to return to main menu → Saves config.json immediately Q) Quit → Exits configure.ps1 ``` ### Configuring a Feature When you select a feature for configuration, you'll be prompted for each setting: - **Type: string** → Enter any text - **Type: int** → Enter a number - **Type: bool** → Enter Y/N (yes/no) - **Type: time** → Enter HH:MM format - Press Enter to accept the displayed default ## Known Limitations - **Default Browser Registry Protection**: On Windows 11, Microsoft protects the default browser registry key with a hash. The DefaultBrowser feature reads the ProgId but cannot *set* the default browser programmatically. The toast provides a link to Settings for manual override. - **Windows 11 Only for Toasts**: Toast notifications require WinRT (Windows 10+), but full Windows 11 support is assumed. Win10 may work but is untested. - **Scheduled Task Security**: The runner task executes as the current user with Limited RunLevel (no elevation). Features cannot perform system-wide administrative tasks; they're limited to user-level operations. - **DNS Suffix Matching**: Network detection relies on `Get-DnsClient` adapter DNS suffix. Make sure your network adapter is configured with the correct suffix for accurate detection. - **Manual Execution & Repetition Timer**: Executing the runner manually via menu option 5 ("Execute runner now") runs the task immediately but does **not** start the 2-minute repetition timer. The repetition timer only activates on logon/restart. For continuous testing, you may need to restart or wait for next logon. ## Extending with New Features To add a new automation feature: 1. Create `internal/features/MyFeature.ps1`: ```powershell #Requires -Version 5.1 param() # Empty; loaded via dot-source $FeatureMeta = @{ Name = "My Feature" Description = "Does something cool" Settings = @( @{ Key = "enabled"; Label = "Enable"; Type = "bool"; Default = $true; Description = "Turn on/off" } ) } function Invoke-Feature { param([hashtable]$Config, [hashtable]$State) if (-not $Config.enabled) { return $State } try { Write-Log -Level Info -Message "Running My Feature" -Feature "MyFeature" # Do work here } catch { Write-Log -Level Error -Message "Error: $_" -Feature "MyFeature" } return $State } ``` 2. Drop it in `internal/features/` — it will auto-discover on next configure.ps1 run 3. Run `.\configure.ps1` → menu option 4 → Your feature appears with toggles and config sub-menu ## Logging All activity is logged to `internal/data/logs/automation-YYYY-MM-DD.log` (UTC date). - **Retention**: 7 days (older logs auto-deleted) - **Format**: `[YYYY-MM-DD HH:mm:ss] [LEVEL] [Feature] Message` - **Levels**: Info, Warn, Error Elevation diagnostics go to `internal/data/logs/elevated-process.log` for troubleshooting registration issues. ## Troubleshooting **Task not running?** - Check Task Scheduler (root library) for "PSAutomation-Runner" task - Verify "Run as current user" and Limited RunLevel - Check `automation-.log` for errors **Features not executing?** - Verify feature is enabled in menu option 4 - Check `internal/data/config.json` for `"enabled": true` on that feature - Look for errors in `automation-.log` with feature name **Elevation prompts failing?** - Check `elevated-process.log` for bootstrap diagnostics - Ensure PowerShell isn't blocked by execution policy: `Get-ExecutionPolicy` - If needed, set: `Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser` ## License None. Use freely.