This project has an aim to allow System Administrators and also to who Thinks to be System Administrator to launch Power Shell scripts and console applications as Windows Service.
Go to file
2026-03-01 13:17:50 +01:00
assets (feature): update repo utils 2026-03-01 12:50:30 +01:00
src (feature): update repo utils 2026-03-01 12:50:30 +01:00
utils (feature): update repo utils 2026-03-01 13:17:50 +01:00
.gitattributes Add .gitattributes, .gitignore, and LICENSE.txt. 2023-12-27 00:46:37 +01:00
.gitignore Add .gitattributes, .gitignore, and LICENSE.txt. 2023-12-27 00:46:37 +01:00
CHANGELOG.md (bugfix): unblock script and dependencies 2026-02-16 21:39:08 +01:00
CONTRIBUTING.md (feature): update repo utils 2026-03-01 12:50:30 +01:00
LICENSE.md (feature): release 1.0.1. Improved release with bundled scripts. UI to register service, change scheduling and log viewer 2026-02-15 19:44:03 +01:00
README.md (feature): update repo utils 2026-03-01 12:50:30 +01:00

MaksIT Unified Scheduler Service

Line Coverage Branch Coverage Method Coverage

A modern, fully rewritten Windows service built on .NET 10 for scheduling and running PowerShell scripts and console applications. Designed for system administrators — and also for those who feel like system administrators — who need a predictable, resilient, and secure background execution environment.

Tip: A graphical Schedule Manager UI is included for easy service registration, script scheduling, and log viewing — no command-line required.


Table of Contents

Scripts Examples

Note: These examples are bundled with the release and included in the default appsettings.json, but are disabled by default. To enable an example, set "Disabled": false in the configuration.


Features at a Glance

  • .NET 10 Worker Service clean, robust, stable.
  • Fully portable relocate between machines without reconfiguration.
  • Windows only designed specifically for Windows services.
  • Strongly typed configuration via appsettings.json.
  • Parallel execution PowerShell scripts & executables run concurrently using RunspacePool and Task.WhenAll.
  • Relative path support script and process paths can be relative to the application directory.
  • Signature enforcement (AllSigned by default).
  • Automatic restart-on-failure for supervised processes.
  • Extensible logging (file + console + Windows EventLog).
  • Built-in CLI for service management (--install, --uninstall, --start, --stop, --status).
  • Reusable scheduling module: SchedulerTemplate.psm1.
  • Thread-isolated architecture — individual failures do not affect others.

Installation

Using CLI Commands

The executable includes built-in service management commands. Run as Administrator:

# Install the service (auto-start enabled)
MaksIT.UScheduler.exe --install

# Start the service
MaksIT.UScheduler.exe --start

# Check service status
MaksIT.UScheduler.exe --status

# Stop the service
MaksIT.UScheduler.exe --stop

# Uninstall the service
MaksIT.UScheduler.exe --uninstall

# Show help
MaksIT.UScheduler.exe --help
Command Short Description
--install -i Install the Windows service (auto-start)
--uninstall -u Stop and remove the Windows service
--start Start the service
--stop Stop the service
--status Query service status
--help -h Show help message

Note: Service management commands require administrator privileges.

Using sc.exe

Alternatively, use Windows Service Control Manager directly:

sc.exe create "MaksIT.UScheduler" binpath="C:\Path\To\MaksIT.UScheduler.exe" start=auto
sc.exe start "MaksIT.UScheduler"

To uninstall:

sc.exe stop "MaksIT.UScheduler"
sc.exe delete "MaksIT.UScheduler"

Schedule Manager UI

The Schedule Manager is a WPF application that provides a graphical interface for managing the UScheduler service and its scheduled scripts.

Getting Started

When you download and unpack the release bundle, launch Start-ScheduleManager.bat as administrator.

Manager launcher

Note: Administrator privileges are required only for service management operations (register, start, stop, unregister). Regular schedule editing can be done without elevation.

Settings View

The Settings view is your starting point for configuring the Schedule Manager.

Settings view

Feature Description
Service Bin Path Path to the UScheduler installation folder containing MaksIT.UScheduler.exe
Service Status Real-time status indicator (Running, Stopped, Starting, Stopping, Paused, Not Installed)
Register/Unregister Install or remove the Windows service (requires admin)
Start/Stop Control the service state (requires admin)
Refresh Update the current service status display
Reload Settings Refresh service configuration from appsettings.json

Main View — Schedule Management

The Main view allows you to manage script schedules and execution settings.

Main view

Script List Panel:

  • Lists all PowerShell scripts configured in appsettings.json
  • Select a script to view and edit its schedule

Script Configuration:

Setting Description
Name Display name for the script
Is Signed Require script to be digitally signed (AllSigned policy)
Disabled Skip this script during scheduled execution

Schedule Configuration:

Setting Description
Run Month Select specific months to run (empty = every month)
Run Weekday Select specific days of the week (empty = every day)
Run Time Add/remove specific execution times (HH:mm format)
Min Interval Minimum minutes between executions (prevents duplicate runs)

Actions:

  • Save — Persist schedule changes to scriptsettings.json
  • Revert — Discard unsaved changes
  • Launch — Execute the script immediately via its .bat file

Script Status:

  • View lock file status (indicates if script is currently running)
  • View last execution timestamp
  • Remove stale lock files from crashed scripts

Service Logs View

Monitor the UScheduler service activity and troubleshoot issues.

Logs view

Features:

  • Browse service log files sorted by date
  • View log content directly in the application
  • Open log files in Windows Explorer
  • Refresh logs to see latest entries

Script Logs View

View execution logs for individual scheduled scripts.

Script logs view

Features:

  • Browse log folders organized by script name
  • Select and view individual log files
  • Track script execution history and errors
  • Open logs in Explorer for external tools

Configuration (appsettings.json)

{
  "Logging": {
    "LogLevel": {
      "Default": "Information"
    },
    "EventLog": {
      "SourceName": "MaksIT.UScheduler",
      "LogName": "Application",
      "LogLevel": {
        "Microsoft": "Information",
        "Microsoft.Hosting.Lifetime": "Information"
      }
    }
  },
  "Configuration": {
    "ServiceName": "MaksIT.UScheduler",
    "LogDir": "C:\\Logs",

    "Powershell": [
      { "Path": "..\\Scripts\\MyScript.ps1", "IsSigned": true, "Disabled": false },
      { "Path": "C:\\Scripts\\AnotherScript.ps1", "IsSigned": false, "Disabled": true }
    ],

    "Processes": [
      { "Path": "..\\Tools\\MyApp.exe", "Args": ["--option"], "RestartOnFailure": true, "Disabled": false }
    ]
  }
}

Note: ServiceName and LogDir are optional. Defaults: "MaksIT.UScheduler" and Logs folder in app directory.

Path Resolution

Paths can be either absolute or relative:

Path Type Example Resolved To
Absolute C:\Scripts\backup.ps1 C:\Scripts\backup.ps1
Relative ../Scripts/backup.ps1 {AppDirectory}\..\Scripts\backup.ps1
Relative scripts/backup.ps1 {AppDirectory}\scripts\backup.ps1

Relative paths are resolved against the application's base directory (where MaksIT.UScheduler.exe is located).

Log Levels

The "Default": "Information" setting controls the minimum severity of messages that get logged. Available levels (from most to least verbose):

Level Description
Trace Most detailed, for debugging internals
Debug Debugging information
Information General operational events (recommended default)
Warning Abnormal or unexpected events
Error Errors and exceptions
Critical Critical failures requiring immediate attention
None Disables logging

PowerShell Scripts

Property Type Default Description
Path string required Path to .ps1 file (absolute or relative)
IsSigned bool true true enforces AllSigned, false runs unrestricted
Disabled bool false true skips this script during execution

Processes

Property Type Default Description
Path string required Path to executable (absolute or relative)
Args string[] null Command-line arguments
RestartOnFailure bool false Restart process if it exits with non-zero code
Disabled bool false true skips this process during execution

How It Works

Each script or process is executed in its own managed thread.

PowerShell Execution Parameters

myCommand.Parameters.Add(new CommandParameter("Automated", true));
myCommand.Parameters.Add(new CommandParameter("CurrentDateTimeUtc", DateTime.UtcNow.ToString("o")));

Inside the script:

param (
    [switch]$Automated,
    [string]$CurrentDateTimeUtc
)

Execution Model

Scripts and processes run in parallel using:

  • PowerShell: RunspacePool (up to CPU core count concurrent runspaces)
  • Processes: Task.WhenAll for concurrent process execution
Unified Scheduler Service
├── PSScriptBackgroundService (RunspacePool)
│   ├── ScriptA.ps1     ─┐
│   ├── ScriptB.ps1     ─┼─ Parallel execution
│   └── ScriptC.ps1     ─┘
└── ProcessBackgroundService (Task.WhenAll)
    ├── ProgramA.exe    ─┐
    ├── ProgramB.exe    ─┼─ Parallel execution
    └── ProgramC.exe    ─┘
  • A failure in one script/process never stops the service or other components.
  • The same script/process won't run twice concurrently (protected by "already running" check).
  • Execution cycle repeats every 10 seconds.

Reusable Scheduler Module (SchedulerTemplate.psm1)

This module provides:

  • Scheduling by:

    • Month
    • Weekday
    • Exact time(s)
    • Minimum interval
  • Automatic lock file (no concurrent execution)

  • Last-run file tracking

  • Unified callback execution pattern

Exported Functions

Function Description
Write-Log Logging with timestamp, level (Info/Success/Warning/Error), and color support
Invoke-ScheduledExecution Main scheduler — checks schedule, manages locks, runs callback
Get-CredentialFromEnvVar Retrieves credentials from Base64-encoded machine environment variables
Test-UNCPath Validates whether a path is a UNC path
Send-EmailNotification Sends SMTP email with optional SSL and credential support

Module Version

The module exports $ModuleVersion and $ModuleDate for version tracking.

Example usage

param (
    [switch]$Automated,
    [string]$CurrentDateTimeUtc
)

Import-Module "$PSScriptRoot\..\SchedulerTemplate.psm1" -Force

$Config = @{
    RunMonth = @()
    RunWeekday = @()
    RunTime = @("22:52")
    MinIntervalMinutes = 10
}

function Start-BusinessLogic {
     Write-Log "Executing business logic..." -Automated:$Automated
}

Invoke-ScheduledExecution -Config $Config -Automated:$Automated -CurrentDateTimeUtc $CurrentDateTimeUtc -ScriptBlock {
    Start-BusinessLogic
}

Workflow for new scheduled scripts:

  1. Copy template
  2. Modify $Config
  3. Implement Start-BusinessLogic
  4. Add script to appsettings.json

Thats it — the full scheduling engine is reused automatically.


Security

  • Scripts run with AllSigned execution policy by default.
  • Set IsSigned: false to use Unrestricted policy (not recommended for production).
  • Scripts are auto-unblocked before execution (Zone.Identifier removed).
  • Signature validation ensures only trusted scripts execute.

Logging

  • Console logging — standard output
  • File logging — written to LogDir (default: Logs folder in app directory)
  • Windows EventLog — events logged to Application log under MaksIT.UScheduler source
  • All events (start, stop, crash, restart, error, skip) are logged

Testing

The project includes a comprehensive test suite using xUnit and Moq for unit testing.

Running Tests

# Run all tests
dotnet test src/MaksIT.UScheduler.Tests

# Run with verbose output
dotnet test src/MaksIT.UScheduler.Tests --verbosity normal

Code Coverage

Coverage badges are generated locally using ReportGenerator.

Prerequisites:

dotnet tool install --global dotnet-reportgenerator-globaltool

Generate coverage report and badges:

.\src\scripts\Run-Coverage\Run-Coverage.ps1

# With HTML report opened in browser
.\src\scripts\Run-Coverage\Run-Coverage.ps1 -OpenReport

Test Structure

Test Class Coverage
ConfigurationTests Configuration POCOs and default values
ProcessBackgroundServiceTests Process execution lifecycle and error handling
PSScriptBackgroundServiceTests PowerShell script execution and signature validation

Contact

Maksym SadovnychyyMAKS-IT
Email: maksym.sadovnychyy@gmail.com


License

This project is licensed under the MIT License. See LICENSE.md for details.