How to create a rotating log file in PowerShell: step by step
This tutorial shows how to create a simple rotating log system in PowerShell to record application or script messages, useful to avoid huge log files and keep a history by number or by size. It explains the why and gives a practical example of size-based rotation with numbered backups.
Prerequisites
- Windows with PowerShell 5.1+ or PowerShell 7+
- Write permission on the folder where logs will be stored
- Text editor to create the script (e.g.: Notepad, VS Code)
Step 1: decide the rotation strategy
Before coding, choose whether rotation will be by size, by date, or by number of entries. In this example we implement size-based rotation with a fixed number of copies (e.g.: we keep 5 backups). The logic is: when the main file exceeds the limit, rename to .1, shift .1 to .2, etc., and create a new file.
Step 2: create basic log writing functions
Create a simple function that writes entries with a timestamp. This separates writing from rotation logic and eases testing.
function Write-LogEntry {
param(
[string]$Message,
[string]$LogPath = "C:\Logs\app.log"
)
$time = Get-Date -Format 'yyyy-MM-dd HH:mm:ss'
"$time - $Message" | Out-File -FilePath $LogPath -Encoding UTF8 -Append
}
Step 3: implement the size-based rotation function
The function checks the file size and, if it exceeds the limit, rotates the existing files up to the defined maximum. We use file manipulation with Test-Path, Get-Item and Move-Item.
function Rotate-LogIfNeeded {
param(
[string]$LogPath = "C:\Logs\app.log",
[int]$MaxBytes = 1048576, # 1 MB
[int]$MaxBackups = 5
)
if (-not (Test-Path $LogPath)) { return }
$size = (Get-Item $LogPath).Length
if ($size -lt $MaxBytes) { return }
# Remove the oldest backup if it exists
$oldest = "$LogPath.$MaxBackups"
if (Test-Path $oldest) { Remove-Item -Path $oldest -Force }
# Shift backups (e.g.: app.log.4 -> app.log.5)
for ($i = $MaxBackups - 1; $i -ge 1; $i--) {
$src = "$LogPath.$i"
$dst = "$LogPath." + ($i + 1)
if (Test-Path $src) { Move-Item -Path $src -Destination $dst -Force }
}
# Rename the current file to .1
Move-Item -Path $LogPath -Destination "$LogPath.1" -Force
# Optional: create a new empty file
"" | Out-File -FilePath $LogPath -Encoding UTF8
}
Step 4: combine rotation with writing (usage example)
Call Rotate-LogIfNeeded before writing a new entry. This ensures the first entry of the new file will go into the empty file created.
# Simple usage example
$log = 'C:\Logs\app.log'
$maxBytes = 500000 # 500 KB
$maxBackups = 3
# Ensure the folder exists
$dir = Split-Path $log
if (-not (Test-Path $dir)) { New-Item -Path $dir -ItemType Directory | Out-Null }
# Rotate if needed and write several entries
Rotate-LogIfNeeded -LogPath $log -MaxBytes $maxBytes -MaxBackups $maxBackups
Write-LogEntry -Message 'Application started' -LogPath $log
Write-LogEntry -Message 'Test event' -LogPath $log
Step 5: integration with existing scripts and scheduling
To integrate, import the functions at the beginning of your scripts and call Rotate-LogIfNeeded before Write-LogEntry. For periodic execution use Task Scheduler or schedule via your execution system (e.g.: run the main script that writes logs).
Verify the result
Open the logs folder and verify that app.log and files app.log.1, app.log.2, etc., exist up to the number of backups. Confirm that app.log contains the most recent entries and that the numbered files contain previous entries. Check sizes with Get-ChildItem -Path C:\Logs | Select Name, Length.
Conclusion
With these functions you have a simple rotating log system in PowerShell that prevents excessively large files and keeps a limited history. Next steps: adapt rotation by date, compress backups (Compress-Archive) or send logs to a SIEM. Tip: always test with low limits to validate rotation before using in production — need help adding automatic compression?