Skip to content

PowerShell Appending to Files

How to append text to files in PowerShell using Add-Content and Out-File -Append for logging, auditing, and incremental file updates without overwriting existing content.

Appending data to files allows scripts to add new lines or log entries to existing files on disk without modifying or deleting historical content. PowerShell provides two primary mechanisms for appending: the dedicated content cmdlet Add-Content and the formatting cmdlet switch Out-File -Append (along with its shorthand redirection operator >>).

Appending Plain Text with Add-Content

The Add-Content cmdlet (alias: ac) appends content to a specified item or file. If the file already exists, PowerShell opens the file, moves the write pointer to the end of the file stream, writes the new content followed by a newline, and closes the file handle. If the file does not exist, Add-Content automatically creates it.

Basic Syntax

Add-Content -Path <String> -Value <Object[]> [-Encoding <String>] [-PassThru] [-NoNewline]
Consolepowershell
Add-Content -Path "C:\Logs\activity.log" -Value "Service started at $(Get-Date)"
Consolepowershell
Add-Content -Path "C:\Logs\activity.log" -Value "Connection established at $(Get-Date)"
Consolepowershell
Get-Content "C:\Logs\activity.log"
Outputplaintext
Service started at 09/27/2026 18:55:02
Connection established at 09/27/2026 18:55:08

Where:

  • Each Add-Content call adds a new line after the file's existing content, rather than replacing it.
  • If C:\Logs\activity.log doesn't exist yet, the first call creates it automatically.

Appending Multiple Lines at Once

Consolepowershell
Add-Content -Path "C:\Logs\activity.log" -Value @("Backup started", "Backup completed")

adn the file activity.log contains:

Outputplaintext
Service started at 09/27/2026 18:55:02
Connection established at 09/27/2026 18:55:08
Backup started
Backup completed

A more complete example with structured log entries:

add-content-demo.ps1powershell
$LogPath = "$PSScriptRoot\system-events.log"

Add-Content -Path $LogPath -Value "2024-10-24 10:00:00 [INFO] System service initialized."
Add-Content -Path $LogPath -Value "2024-10-24 10:01:15 [WARN] Storage pool capacity exceeded 80%."
Add-Content -Path $LogPath -Value "2024-10-24 10:02:30 [INFO] Garbage collection finished."

Get-Content -Path $LogPath
Consolepowershell
pwsh ./add-content-demo.ps1
Outputplaintext
2026-10-24 10:00:00 [INFO] System service initialized.
2026-10-24 10:01:15 [WARN] Storage pool capacity exceeded 80%.
2026-10-24 10:02:30 [INFO] Garbage collection finished.

Difference Between Set-Content and Add-Content

Both cmdlets write string data to a file, but they differ fundamentally in how they treat existing content.

Original File: [ Line A, Line B ]
                    │
          ┌─────────┴─────────┐
          ▼                   ▼
     Set-Content          Add-Content
          │                   │
          ▼                   ▼
  Replaces the file      Adds text after
  with new content       the existing text

Result:                  Result:
[ New Line C ]           [ Line A, Line B, New Line C ]

Behavioral Comparison

Feature Set-Content (alias: sc) Add-Content (alias: ac)
Existing File Action Overwrites; truncates existing content to 0 bytes before writing. Preserves; appends new content to the end of the file.
Missing File Action Creates the file. Creates the file.
Missing Directory Action Throws DirectoryNotFoundException. Throws DirectoryNotFoundException.
Stream Management Opens file with write/truncate access. Opens file with append access (seek-to-end).
Performance Slightly faster (single write). Slightly slower (must locate end of file).
Typical Use Case Writing configuration files, resetting state, initial exports. Event logging, accumulating batch job results, audit trails.
comparison.ps1powershell
Set-Content -Path "C:\Temp\demo.txt" -Value "First line"
Set-Content -Path "C:\Temp\demo.txt" -Value "Second line"
Write-Output "--- After Set-Content twice ---"
Get-Content "C:\Temp\demo.txt"

Add-Content -Path "C:\Temp\demo2.txt" -Value "First line"
Add-Content -Path "C:\Temp\demo2.txt" -Value "Second line"
Write-Output "--- After Add-Content twice ---"
Get-Content "C:\Temp\demo2.txt"
Consolepowershell
./comparison.ps1
Outputplaintext
--- After Set-Content twice ---
Second line
--- After Add-Content twice ---
First line
Second line

Where:

  • The second Set-Content call overwrites the first line entirely, leaving only "Second line" in the file.
  • Both Add-Content calls preserved prior content, resulting in both lines appearing in the file.

Practical Examples

Daily Log Rotation Pattern

A common pattern combines both cmdlets: Add-Content for ongoing log entries, and Set-Content (or Move-Item) to start a fresh log periodically.

daily-log.ps1powershell
$logPath = "C:\Logs\daily-activity.log"
$timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"

Add-Content -Path $logPath -Value "[$timestamp] Task executed successfully."
Consolepowershell
./daily-log.ps1
./daily-log.ps1
Get-Content "C:\Logs\daily-activity.log"
Outputplaintext
[2026-09-27 18:59:33] Task executed successfully.
[2026-09-27 18:59:39] Task executed successfully.

Transaction Log with Automated Rotation Check

The following script appends operational status records to a persistent transaction log file, evaluates the file size after writing, and rotates the log file if it exceeds a specified size limit.

append-transaction-log.ps1powershell
param (
    [string]$LogFile       = "$PSScriptRoot\transactions.log",
    [double]$MaxSizeBytes  = 500KB
)

$ParentDir = Split-Path -Path $LogFile -Parent
if ($ParentDir -and -not (Test-Path -Path $ParentDir -PathType Container)) {
    $null = New-Item -ItemType Directory -Path $ParentDir -Force
}

$Timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss.fff"
$Machine   = $env:COMPUTERNAME
$Action    = "HEALTH_PROBE"
$Status    = "SUCCESS"

$LogPayload = "{0} | Node: {1,-15} | Action: {2,-12} | Status: {3}" -f `
    $Timestamp, $Machine, $Action, $Status

Add-Content -Path $LogFile -Value $LogPayload -Encoding utf8

$CurrentFile = Get-Item -Path $LogFile
$NeedsRotation = $CurrentFile.Length -ge $MaxSizeBytes

if ($NeedsRotation) {
    $ArchiveStamp = Get-Date -Format "yyyyMMdd_HHmmss"
    $ArchivedName = "$LogFile.$ArchiveStamp.bak"

    Rename-Item -Path $LogFile -NewName $ArchivedName
    Write-Warning "Log file exceeded threshold ($($CurrentFile.Length) bytes). Rotated to: $ArchivedName"
}

[PSCustomObject]@{
    LogTarget      = $LogFile
    CurrentBytes   = if (Test-Path $LogFile) { (Get-Item $LogFile).Length } else { 0 }
    Rotated        = $NeedsRotation
    LastEntryAdded = $LogPayload
}

Where:

  • Split-Path and New-Item -ItemType Directory ensure parent directories exist before writing.
  • "{0} | Node: {1,-15}..." -f ... uses composite formatting to align log fields into fixed-width columns.
  • Add-Content -Path $LogFile -Value $LogPayload appends the formatted string safely using UTF-8.
  • Get-Item $LogFile | Length checks whether the file size exceeds the configured threshold.
  • Rename-Item rotates the log file into a backup archive if the size limit is reached.

Execute the script from the console:

Consolepowershell
pwsh ./append-transaction-log.ps1
Outputplaintext
LogTarget      : C:\Scripts\transactions.log
CurrentBytes   : 88
Rotated        : False
LastEntryAdded : 2026-10-24 23:55:10.124 | Node: WORKSTATION-01  | Action: HEALTH_PROBE | Status: SUCCESS

Verify that consecutive script runs preserve historical entries:

Consolepowershell
pwsh ./append-transaction-log.ps1
Get-Content -Path "$PSScriptRoot\transactions.log"
Outputplaintext
2026-10-24 23:55:10.124 | Node: WORKSTATION-01  | Action: HEALTH_PROBE | Status: SUCCESS
2026-10-24 23:55:12.458 | Node: WORKSTATION-01  | Action: HEALTH_PROBE | Status: SUCCESS
Navigation