Quick Start • Log Styles • Functions • 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.
-TimestampPosition None(default): message is written as-is-TimestampPosition Front: timestamp is prepended-TimestampPosition Back: timestamp is appended
This behavior is covered by Pester tests for Write-LogInfo, Write-LogWarning, and Write-LogError, including invalid value rejection.
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 |
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 file through SMTP |
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 the full log body through .NET SmtpClient.
# Using explicit LogContext
$ctx = Start-Log -Style Standard -LogDir .\log -Title 'Nightly Job' -ReturnContext
Send-Log `
-SMTPServer 'smtp.example.com' `
-LogContext $ctx `
-EmailFrom 'me@example.com' `
-EmailTo 'team@example.com' `
-EmailSubject 'Nightly Job Log'Notes:
- This currently uses legacy
SmtpClient - The full log is read into memory before sending
- Modern auth and large-log handling are future hardening items
-
Writers and
Send-Logrequire a single explicitLogContextreturned byStart-Log -ReturnContextor created withNew-LogContext, or an explicit-LogPath. -
Send-Logis functional but not fully enterprise-hardened yet (modern auth, large-log handling) -
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 after a successful error entry. -
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.ps1- 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.