How to Write to a File in UTF-8 with PowerShell (With or Without BOM)

To make PowerShell write to a file in UTF-8, add -Encoding utf8 to Out-File, Set-Content, or Add-Content:

Set-Content -Path .\notes.txt -Value 'Café in Austin' -Encoding utf8

The catch is the byte order mark (BOM). PowerShell 7 writes that file without a BOM, while Windows PowerShell 5.1 always adds one. I’ll show both results byte by byte, plus the clean ways to get BOM-less UTF-8 in 5.1.

Write a file in UTF-8 with Out-File, Set-Content, and Add-Content

To see what really lands on disk, I use a tiny helper that prints the first bytes of a file. Save it as Get-FileBytes.ps1:

function Get-FileBytes ($Path, $Count = 4) {
    $bytes = [System.IO.File]::ReadAllBytes((Resolve-Path -Path $Path).Path)
    ($bytes[0..($Count - 1)] | ForEach-Object { '{0:X2}' -f $_ }) -join ' '
}

Now write the same line with all three cmdlets. The text includes an é, so a wrong encoding would show up right away:

. .\Get-FileBytes.ps1
$text = 'Café in Austin, TX'
$text | Out-File -FilePath .\Utf8\out-file.txt -Encoding utf8
Set-Content -Path .\Utf8\set-content.txt -Value $text -Encoding utf8
Add-Content -Path .\Utf8\add-content.txt -Value $text -Encoding utf8

'Out-File:    ' + (Get-FileBytes .\Utf8\out-file.txt)
'Set-Content: ' + (Get-FileBytes .\Utf8\set-content.txt)
'Add-Content: ' + (Get-FileBytes .\Utf8\add-content.txt)

Output:

Out-File:    43 61 66 C3
Set-Content: 43 61 66 C3
Add-Content: 43 61 66 C3
PowerShell 7 Out-File, Set-Content and Add-Content write UTF-8 files without a BOM
With -Encoding utf8, all three files start with the text itself, no BOM (PowerShell 7)

The output above is from PowerShell 7: every file starts with 43 61 66, the letters C, a, f. Windows PowerShell 5.1 printed EF BB BF 43 for all three, because its utf8 value means UTF-8 with a BOM.

Use Out-File for formatted command output and Set-Content for plain strings. To add lines to a log, Add-Content appends text without rewriting the file.

utf8 vs utf8NoBOM vs utf8BOM in PowerShell 7

PowerShell 7 gives you three UTF-8 values, so you can choose the BOM on purpose. This one only runs in PowerShell 7:

. .\Get-FileBytes.ps1
$text = 'Café in Denver, CO'
foreach ($enc in 'utf8', 'utf8NoBOM', 'utf8BOM') {
    Set-Content -Path ".\Utf8\$enc.txt" -Value $text -Encoding $enc
    '{0,-10} {1}' -f $enc, (Get-FileBytes ".\Utf8\$enc.txt" 5)
}

Output:

utf8       43 61 66 C3 A9
utf8NoBOM  43 61 66 C3 A9
utf8BOM    EF BB BF 43 61

Plain utf8 and utf8NoBOM produce identical bytes. Only utf8BOM writes the EF BB BF signature first.

Windows PowerShell 5.1 doesn’t know the newer names and refuses them:

try {
    'Café' | Set-Content -Path .\Utf8\menu.txt -Encoding utf8NoBOM -ErrorAction Stop
}
catch { "Failed. $($_.Exception.Message.Split('.')[0])." }

Output:

Failed. Cannot bind parameter 'Encoding'.

If one script must run in both shells, check the PowerShell version first and pick the encoding in code. The table sums up what each value means:

-Encoding valuePowerShell 7Windows PowerShell 5.1
utf8UTF-8, no BOMUTF-8 with BOM
utf8NoBOMUTF-8, no BOMNot supported (error)
utf8BOMUTF-8 with BOMNot supported (error)
(none)UTF-8, no BOMUTF-16LE for Out-File and >, ANSI for Set-Content

What encoding does PowerShell use by default?

Leave out -Encoding and the two shells drift far apart. Here’s the same text written with Out-File, the > operator, and Set-Content:

. .\Get-FileBytes.ps1
$text = 'Café in Seattle, WA'
$text | Out-File -FilePath .\Utf8\out-file.txt
$text > .\Utf8\redirect.txt
$text | Set-Content -Path .\Utf8\set-content.txt

Get-ChildItem -Path .\Utf8\*.txt | ForEach-Object {
    '{0,-16} {1,3} bytes  {2}' -f $_.Name, $_.Length, (Get-FileBytes $_.FullName)
}

Output:

out-file.txt      22 bytes  43 61 66 C3
redirect.txt      22 bytes  43 61 66 C3
set-content.txt   22 bytes  43 61 66 C3