|
| 1 | +--- |
| 2 | +description: >- |
| 3 | + Understand how default encoding changed from Windows PowerShell 5.1 to |
| 4 | + PowerShell 7 and choose a migration strategy for your scripts. |
| 5 | +ms.date: 04/15/2026 |
| 6 | +title: Encoding changes in PowerShell 7 |
| 7 | +--- |
| 8 | + |
| 9 | +# Encoding changes in PowerShell 7 |
| 10 | + |
| 11 | +PowerShell 7 changed the default encoding for file output from |
| 12 | +locale-dependent encodings (such as Windows-1252) and UTF-16LE to UTF-8 |
| 13 | +without a byte order mark (BOM). This change aligns with modern tooling and |
| 14 | +cross-platform expectations, but it can break scripts that depend on specific |
| 15 | +encodings. |
| 16 | + |
| 17 | +## What changed |
| 18 | + |
| 19 | +### Default encoding comparison |
| 20 | + |
| 21 | +The following table shows the default encoding for common cmdlets and |
| 22 | +features in each edition: |
| 23 | + |
| 24 | +| Cmdlet or feature | Windows PowerShell 5.1 | PowerShell 7 | |
| 25 | +| ----------------- | ---------------------- | ------------ | |
| 26 | +| `Out-File` / `>` operator | UTF-16LE with BOM | UTF-8 without BOM | |
| 27 | +| `Set-Content` | System locale (often Windows-1252) | UTF-8 without BOM | |
| 28 | +| `Add-Content` | System locale | UTF-8 without BOM | |
| 29 | +| `Export-Csv` | ASCII | UTF-8 without BOM | |
| 30 | +| `Export-Clixml` | UTF-8 with BOM | UTF-8 without BOM | |
| 31 | +| `New-ModuleManifest` | UTF-16LE with BOM | UTF-8 without BOM | |
| 32 | +| `Start-Transcript` | UTF-8 with BOM | UTF-8 without BOM | |
| 33 | +| `$OutputEncoding` (pipe to native) | ASCII | UTF-8 without BOM | |
| 34 | + |
| 35 | +### The -Encoding parameter |
| 36 | + |
| 37 | +In Windows PowerShell 5.1, the `-Encoding` parameter accepted string values |
| 38 | +such as `UTF8`, which produced UTF-8 _with_ BOM. In PowerShell 7, the |
| 39 | +parameter accepts `System.Text.Encoding` objects and string values with |
| 40 | +updated meanings: |
| 41 | + |
| 42 | +| Value | PowerShell 7 behavior | |
| 43 | +| ----- | --------------------- | |
| 44 | +| `utf8` | UTF-8 without BOM | |
| 45 | +| `utf8BOM` | UTF-8 with BOM | |
| 46 | +| `utf8NoBOM` | UTF-8 without BOM (same as `utf8`) | |
| 47 | +| `utf16` or `unicode` | UTF-16LE with BOM | |
| 48 | +| `utf16BE` or `bigendianunicode` | UTF-16BE with BOM | |
| 49 | +| `ascii` | ASCII (7-bit) | |
| 50 | +| `oem` | OEM code page | |
| 51 | +| `ansi` | ANSI code page | |
| 52 | + |
| 53 | +### Removed: -Encoding Byte |
| 54 | + |
| 55 | +The `Byte` encoding value was removed in PowerShell 7. Use the |
| 56 | +`-AsByteStream` parameter instead: |
| 57 | + |
| 58 | +**Before (Windows PowerShell 5.1)**: |
| 59 | + |
| 60 | +```powershell |
| 61 | +Get-Content -Path file.bin -Encoding Byte |
| 62 | +``` |
| 63 | + |
| 64 | +**After (PowerShell 7)**: |
| 65 | + |
| 66 | +```powershell |
| 67 | +Get-Content -Path file.bin -AsByteStream |
| 68 | +``` |
| 69 | + |
| 70 | +## Impact assessment |
| 71 | + |
| 72 | +### Scripts that generate files for other tools |
| 73 | + |
| 74 | +If your scripts use `Out-File`, `Set-Content`, `Export-Csv`, or the `>` |
| 75 | +operator to create files that are consumed by other tools, check whether |
| 76 | +those tools expect a specific encoding. |
| 77 | + |
| 78 | +Common scenarios that break: |
| 79 | + |
| 80 | +- **SIEM or log analysis tools** that detect file type by BOM. UTF-16LE |
| 81 | + files have a `0xFF 0xFE` BOM; PowerShell 7's UTF-8 files have no BOM. |
| 82 | +- **Legacy Windows tools** that expect the system locale encoding |
| 83 | + (such as Windows-1252 for Western European systems). |
| 84 | +- **Signed scripts** where the encoding affects the digital signature. |
| 85 | + Re-sign scripts after changing encoding. |
| 86 | + |
| 87 | +### Scripts that read files from Windows PowerShell |
| 88 | + |
| 89 | +If your PowerShell 7 scripts read files that were created by Windows |
| 90 | +PowerShell 5.1, encoding detection generally works correctly. PowerShell 7 |
| 91 | +detects the BOM in UTF-16LE files and reads them without issues. Files |
| 92 | +without a BOM are read as UTF-8. |
| 93 | + |
| 94 | +### Pipe-to-native-command changes |
| 95 | + |
| 96 | +The `$OutputEncoding` variable controls the encoding when PowerShell pipes |
| 97 | +text to native commands. It changed from ASCII to UTF-8: |
| 98 | + |
| 99 | +- **ASCII** (Windows PowerShell 5.1): Characters outside the 7-bit ASCII |
| 100 | + range were replaced with `?`. |
| 101 | +- **UTF-8** (PowerShell 7): Extended characters are preserved but may |
| 102 | + appear garbled if the native command doesn't support UTF-8. |
| 103 | + |
| 104 | +If you pipe output to legacy tools like `cmd.exe /c findstr` and see |
| 105 | +garbled characters, set `$OutputEncoding` to ASCII in your session or |
| 106 | +profile: |
| 107 | + |
| 108 | +```powershell |
| 109 | +$OutputEncoding = [System.Text.Encoding]::ASCII |
| 110 | +``` |
| 111 | + |
| 112 | +## Migration strategies |
| 113 | + |
| 114 | +### Strategy 1: Embrace UTF-8 |
| 115 | + |
| 116 | +UTF-8 is the dominant encoding for modern tools, web APIs, cross-platform |
| 117 | +scripts, and version-controlled files. If possible, update all consumers to |
| 118 | +expect UTF-8 without BOM. |
| 119 | + |
| 120 | +To re-encode existing files in bulk: |
| 121 | + |
| 122 | +```powershell |
| 123 | +Get-ChildItem -Path .\output -Filter *.csv -Recurse | ForEach-Object { |
| 124 | + $content = Get-Content -Path $_.FullName -Raw |
| 125 | + [System.IO.File]::WriteAllText( |
| 126 | + $_.FullName, |
| 127 | + $content, |
| 128 | + [System.Text.UTF8Encoding]::new($false) |
| 129 | + ) |
| 130 | +} |
| 131 | +``` |
| 132 | + |
| 133 | +### Strategy 2: Force legacy encoding in PowerShell 7 |
| 134 | + |
| 135 | +If you can't update consuming tools, force the old encoding defaults in your |
| 136 | +PowerShell 7 profile using `$PSDefaultParameterValues`: |
| 137 | + |
| 138 | +```powershell |
| 139 | +# Restore Windows PowerShell 5.1 encoding behavior |
| 140 | +$PSDefaultParameterValues['Out-File:Encoding'] = 'utf8BOM' |
| 141 | +$PSDefaultParameterValues['Set-Content:Encoding'] = 'utf8BOM' |
| 142 | +$PSDefaultParameterValues['Add-Content:Encoding'] = 'utf8BOM' |
| 143 | +$PSDefaultParameterValues['Export-Csv:Encoding'] = 'utf8BOM' |
| 144 | +$PSDefaultParameterValues['Export-Clixml:Encoding'] = 'utf8BOM' |
| 145 | +``` |
| 146 | + |
| 147 | +> [!IMPORTANT] |
| 148 | +> Setting `$PSDefaultParameterValues` in a profile affects all scripts in |
| 149 | +> that session. For targeted control, set the encoding per-script instead. |
| 150 | +
|
| 151 | +### Strategy 3: Explicit encoding per script |
| 152 | + |
| 153 | +For scripts that must work in both Windows PowerShell 5.1 and PowerShell 7, |
| 154 | +always specify the `-Encoding` parameter explicitly: |
| 155 | + |
| 156 | +```powershell |
| 157 | +$data | Export-Csv -Path report.csv -Encoding UTF8 -NoTypeInformation |
| 158 | +``` |
| 159 | + |
| 160 | +> [!NOTE] |
| 161 | +> The value `UTF8` produces UTF-8 _with_ BOM in Windows PowerShell 5.1 and |
| 162 | +> UTF-8 _without_ BOM in PowerShell 7. If you need identical output in both |
| 163 | +> editions, use `[System.Text.UTF8Encoding]::new($true)` (with BOM) or |
| 164 | +> `[System.Text.UTF8Encoding]::new($false)` (without BOM) as the |
| 165 | +> `-Encoding` value. |
| 166 | +
|
| 167 | +## BOM considerations |
| 168 | + |
| 169 | +### When BOMs are required |
| 170 | + |
| 171 | +- XML files consumed by tools that require a BOM to detect encoding |
| 172 | +- Signed PowerShell scripts (re-encode and re-sign after migration) |
| 173 | +- Interop with older Java versions that expect a UTF-8 BOM |
| 174 | +- Files read by applications that default to the system locale without BOM |
| 175 | + detection |
| 176 | + |
| 177 | +### When BOMs cause problems |
| 178 | + |
| 179 | +- Unix and Linux tools (many treat the BOM as visible characters) |
| 180 | +- Git diff output (BOM appears as invisible changes at the start of files) |
| 181 | +- JSON parsers (the JSON specification prohibits BOMs) |
| 182 | +- Shell scripts on non-Windows platforms |
| 183 | + |
| 184 | +### PowerShell 7 reads BOMs correctly |
| 185 | + |
| 186 | +Regardless of the default output encoding, PowerShell 7 detects and |
| 187 | +respects BOMs when _reading_ files. A file created with UTF-16LE BOM by |
| 188 | +Windows PowerShell 5.1 is read correctly by PowerShell 7. |
| 189 | + |
| 190 | +## Verify encoding in your environment |
| 191 | + |
| 192 | +Use the following function to check the encoding of a file by inspecting |
| 193 | +its first few bytes: |
| 194 | + |
| 195 | +```powershell |
| 196 | +function Get-FileEncoding { |
| 197 | + param( |
| 198 | + [Parameter(Mandatory)] |
| 199 | + [string]$Path |
| 200 | + ) |
| 201 | +
|
| 202 | + $bytes = [byte[]]( |
| 203 | + Get-Content -Path $Path -AsByteStream -TotalCount 4 |
| 204 | + ) |
| 205 | +
|
| 206 | + if ($bytes.Length -ge 3 -and |
| 207 | + $bytes[0] -eq 0xEF -and |
| 208 | + $bytes[1] -eq 0xBB -and |
| 209 | + $bytes[2] -eq 0xBF) { |
| 210 | + 'UTF-8 with BOM' |
| 211 | + } |
| 212 | + elseif ($bytes.Length -ge 2 -and |
| 213 | + $bytes[0] -eq 0xFF -and |
| 214 | + $bytes[1] -eq 0xFE) { |
| 215 | + 'UTF-16 LE (BOM)' |
| 216 | + } |
| 217 | + elseif ($bytes.Length -ge 2 -and |
| 218 | + $bytes[0] -eq 0xFE -and |
| 219 | + $bytes[1] -eq 0xFF) { |
| 220 | + 'UTF-16 BE (BOM)' |
| 221 | + } |
| 222 | + else { |
| 223 | + 'No BOM (UTF-8 or ASCII)' |
| 224 | + } |
| 225 | +} |
| 226 | +``` |
| 227 | + |
| 228 | +Scan a directory of output files: |
| 229 | + |
| 230 | +```powershell |
| 231 | +Get-ChildItem -Path .\output -File | ForEach-Object { |
| 232 | + [PSCustomObject]@{ |
| 233 | + File = $_.Name |
| 234 | + Encoding = Get-FileEncoding -Path $_.FullName |
| 235 | + } |
| 236 | +} |
| 237 | +``` |
| 238 | + |
| 239 | +## Quick reference |
| 240 | + |
| 241 | +| I need to... | Use this | |
| 242 | +| ------------ | -------- | |
| 243 | +| Write UTF-8 without BOM (PS 7 default) | `Out-File -Path file.txt` | |
| 244 | +| Write UTF-8 with BOM (match WinPS default) | `Out-File -Path file.txt -Encoding utf8BOM` | |
| 245 | +| Write UTF-16LE with BOM (match WinPS `>`) | `Out-File -Path file.txt -Encoding unicode` | |
| 246 | +| Read binary data | `Get-Content -Path file.bin -AsByteStream` | |
| 247 | +| Force ASCII for native pipe | `$OutputEncoding = [System.Text.Encoding]::ASCII` | |
| 248 | + |
| 249 | +## Next steps |
| 250 | + |
| 251 | +- [Migrate PowerShell profiles][profile-migration] |
| 252 | +- [Audit scripts for PowerShell 7 compatibility][script-audit] |
| 253 | +- [Migrating from Windows PowerShell 5.1 to PowerShell 7][migration-guide] |
| 254 | +- [Differences between Windows PowerShell 5.1 and PowerShell 7.x][differences] |
| 255 | + |
| 256 | +<!-- link references --> |
| 257 | +[differences]: ../differences-from-windows-powershell.md |
| 258 | +[migration-guide]: ../Migrating-from-Windows-PowerShell-51-to-PowerShell-7.md |
| 259 | +[profile-migration]: ./profile-migration.md |
| 260 | +[script-audit]: ./script-compatibility-audit.md |
0 commit comments