Quick Start • Log Styles • Sending Logs • Concurrency • Development
Lightweight PowerShell logging for scripts, scheduled tasks, and automation jobs.
PSLogging2 provides file-based logging with simple writer functions, multiple log file layouts, optional timestamps, and SMTP delivery for completed logs. The module is designed for straightforward use in PowerShell 5.1 style environments while still being usable in newer shells.
- Three log file layouts:
Simple,Standard, andDaily - Dedicated helpers for info, warning, and error messages
- Optional timestamp placement controlled by
-TimestampPosition <Front|Back|None> - Daily log reuse with automatic run separators
- Atomic append logic for safer concurrent writes
- Optional SMTP delivery with
Send-Log
PSLogging2/
|- Functions/ # Module functions
|- Docs/ # Review notes and planning docs
|- Tests/ # Validation and smoke-test scripts
|- PSLogging2.psm1
|- PSLogging2.psd1
`- README.md
Import-Module .\PSLogging2.psm1 -ForceCopy the PSLogging2 folder into one of your PowerShell module paths, then import it normally:
Import-Module PSLogging2Import-Module .\PSLogging2.psm1 -Force
# Explicit LogContext pattern
$ctx = Start-Log -Style Simple -LogDir .\log -Title 'Inventory Script' -Version '1.0' -ToScreen -ReturnContext
Write-LogInfo -Message 'Starting run' -LogContext $ctx
Write-LogWarning -Message 'Using fallback configuration' -TimestampPosition Front -LogContext $ctx
Write-LogInfo -Message 'Completed step 1' -TimestampPosition Back -LogContext $ctx
Stop-Log -LogContext $ctxCreates one log file per run.
Example output path:
log\2026-08-15_214530.log
Creates nested year and month folders, then writes a timestamped file for each run.
Example output path:
log\2026\2026-08\2026-08-15_214530.log
Use this when you want a clean archive layout for long-running or recurring automation.
Writes all runs for the same day into a shared daily log.
Example output path:
log\2026\2026-08\2026-08-15.log
When the file already exists, the module appends a run separator unless -DisableDailySeparator is used.
$ctx = Start-Log -Style Standard -LogDir .\log -Title 'Nightly Job' -Version '2.3' -ReturnContext
Write-LogInfo -Message 'Job started' -LogContext $ctx
Write-LogInfo -Message 'Import complete' -TimestampPosition Back -LogContext $ctx
Stop-Log -LogContext $ctx$ctx = Start-Log -Style Daily -LogDir .\log -Title 'Daily Sync' -ReturnContext
Write-LogInfo -Message 'Sync started' -TimestampPosition Front -LogContext $ctx
Write-LogWarning -Message 'Remote system responded slowly' -LogContext $ctx
Stop-Log -LogContext $ctx$ctx = Start-Log -Style Simple -LogDir .\log -Title 'Deployment' -ReturnContext
Write-LogError -Message 'Deployment failed' -TimestampPosition Back -ToScreen -LogContext $ctx
Stop-Log -LogContext $ctxTimestamps are optional and controlled by the -TimestampPosition parameter. This simplified configuration is fully implemented and covered by tests.
-TimestampPosition None(default): message is written as-is-TimestampPosition Front: timestamp is prepended-TimestampPosition Back: timestamp is appended
Example:
Write-LogInfo -Message 'Processing item' -TimestampPosition Front
Write-LogWarning -Message 'Retrying request' -TimestampPosition Back| Function | Purpose |
|---|---|
Start-Log |
Initializes the log path and writes the run header. -ReturnContext returns a New-LogContext instance with an active stopwatch. |
Write-LogInfo |
Appends informational messages |
Write-LogWarning |
Appends warning messages |
Write-LogError |
Appends error messages and can optionally stop execution |
Stop-Log |
Writes footer information and returns a status; use -Exit to terminate the caller |
Send-Log |
Emails a completed log through SMTP, with configurable inline/attachment delivery, optional redaction, and opt-in terminating failures. |
New-LogContext |
Creates an explicit context when a log path already exists |
PSLogging2 now uses atomic append logic for log writes.
- Safer concurrent writes for
Simple,Standard, andDaily - Daily mode can be shared across multiple runs without the earlier append race
- Header and separator creation are also protected through the same log I/O helper approach
The repo includes a basic concurrency test:
Set-Location .\Tests
.\Test-ConcurrentDaily.ps1 -Jobs 8 -LinesPerJob 250Send-Log sends a completed log through .NET SmtpClient. Pass either the LogContext returned by Start-Log -ReturnContext or an explicit -LogPath.
$ctx = Start-Log -Style Standard -LogDir .\log -Title 'Nightly Job' -ReturnContext
# Write log entries, then finish the run before delivery.
Stop-Log -LogContext $ctx
Send-Log `
-SMTPServer 'smtp.example.com' `
-LogContext $ctx `
-EmailFrom 'automation@example.com' `
-EmailTo 'ops@example.com','oncall@example.com' `
-EmailSubject 'Nightly Job Log'The default sends logs up to 5 MB inline. Larger logs are attached; set -MaxInlineSizeMB to choose a different threshold. To redact sensitive content from the sent copy without changing the original log, use -RedactRegex. By default delivery failure writes an error and returns $false; add -ThrowOnFailure when a failed notification must stop automation.
$sent = Send-Log `
-SMTPServer 'smtp.example.com' `
-LogPath .\log\run.log `
-EmailFrom 'automation@example.com' `
-EmailTo 'ops@example.com, oncall@example.com' `
-EmailSubject 'Deployment Log' `
-MaxInlineSizeMB 2 `
-RedactRegex 'password=\S+', 'token=\S+'
if (-not $sent) { Write-Error 'Log notification was not delivered.' }SmtpClient does not support the planned modern authentication path. The current design and implementation roadmap are in Docs/SendLog-Auth-Modernization.md; detailed current-API examples are in Docs/Send-Log.md.
-
Writers and
Send-Logrequire a single explicitLogContextreturned byStart-Log -ReturnContextor created withNew-LogContext, or an explicit-LogPath. -
Send-Loguses legacy SMTP authentication. Modern authentication and Microsoft Graph support are planned but are not implemented. -
Pipeline input is not supported for
LogContext; pass a single context or path per command. -
Stop-Logdoes not exit by default after writing the footer; pass-Exitto terminate the caller. -
Write-LogError -ExitGracefullywrites the footer and exits the calling process whenStop-Log -Exitis invoked. -
Timestamp switches were replaced with
-TimestampPosition, and writer functions validateMessageinput.
Import-Module .\PSLogging2.psm1 -Force
Invoke-Pester .\Tests\PesterImport-Module .\PSLogging2.psm1 -Force
Invoke-Pester .\Tests\Pester\Timestamp.Tests.ps1Set-Location .\Tests
.\Test-ConcurrentDaily.ps1This launches separate pwsh processes and validates the expected write count.
.\Tests\Stress\HighLoadStress.ps1 -Jobs 10 -LinesPerJob 500Set PSLOG_TEST_SHARE to an accessible UNC share. The test skips when this variable is not set.
$env:PSLOG_TEST_SHARE = '\\server\share'
Invoke-Pester .\Tests\Env\NetworkShare.Tests.ps1PSLogging2 includes validation for:
- Concurrent multi-process writes
- Daily log initialization
- LogContext workflows
- SMTP delivery behavior
- Timestamp validation
- Failure path handling
- Stop-Log integration behavior
- High-load, multi-process write validation
- Opt-in network-share write validation
- Implementation roadmap:
Docs/plans.md - Review notes:
Docs/Review.md
Issues, fixes, and improvements are welcome. If you are planning a broader change, check Docs/plans.md first so the work lines up with the current roadmap.
This project is licensed under the terms in LICENSE.