Skip to content

Commit 4a72435

Browse files
Overhaul migration guide: phased playbook + 7 deep-dive articles
Restructure the migration story from a feature overview into an actionable, phased migration playbook (assess → install → migrate → validate → rollback). Add 7 new deep-dive articles covering the top community pain points: script auditing, module compatibility, encoding changes, profile migration, enterprise deployment, scheduled task automation, and testing/rollback. Hub-and-spoke architecture: the rewritten migration guide links to deep-dive articles for details, and every deep-dive links to the existing differences-from-windows-powershell.md for technical reference rather than duplicating it. Fixes #12948 New files: - whats-new/migration/script-compatibility-audit.md - whats-new/migration/module-compatibility-strategy.md - whats-new/migration/encoding-changes.md - whats-new/migration/profile-migration.md - whats-new/migration/enterprise-deployment.md - whats-new/migration/scheduled-tasks-automation.md - whats-new/migration/testing-and-rollback.md Updated files: - whats-new/Migrating-from-Windows-PowerShell-51-to-PowerShell-7.md - whats-new/differences-from-windows-powershell.md - whats-new/module-compatibility.md - whats-new/overview.yml - toc.yml Co-Authored-By: Claude Opus 4.6 <[email protected]>
1 parent 46dd905 commit 4a72435

12 files changed

Lines changed: 2209 additions & 246 deletions

reference/docs-conceptual/toc.yml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,21 @@ items:
228228
href: whats-new/what-s-new-in-powershell-72.md
229229
- name: Migrating from Windows PowerShell 5.1 to PowerShell 7
230230
href: whats-new/Migrating-from-Windows-PowerShell-51-to-PowerShell-7.md
231+
items:
232+
- name: Script compatibility audit
233+
href: whats-new/migration/script-compatibility-audit.md
234+
- name: Module compatibility strategy
235+
href: whats-new/migration/module-compatibility-strategy.md
236+
- name: Encoding changes
237+
href: whats-new/migration/encoding-changes.md
238+
- name: Profile migration
239+
href: whats-new/migration/profile-migration.md
240+
- name: Enterprise deployment
241+
href: whats-new/migration/enterprise-deployment.md
242+
- name: Scheduled tasks and automation
243+
href: whats-new/migration/scheduled-tasks-automation.md
244+
- name: Testing and rollback
245+
href: whats-new/migration/testing-and-rollback.md
231246
- name: Differences between Windows PowerShell 5.1 and PowerShell 7.x
232247
href: whats-new/differences-from-windows-powershell.md
233248
- name: PowerShell differences on non-Windows platforms

reference/docs-conceptual/whats-new/Migrating-from-Windows-PowerShell-51-to-PowerShell-7.md

Lines changed: 261 additions & 246 deletions
Large diffs are not rendered by default.

reference/docs-conceptual/whats-new/differences-from-windows-powershell.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,11 @@ description: This article summarizes the differences and breaking changes from W
55
---
66
# Differences between Windows PowerShell 5.1 and PowerShell 7.x
77

8+
> [!TIP]
9+
> This article is a technical reference of all differences between editions.
10+
> For a step-by-step migration guide, see
11+
> [Migrating from Windows PowerShell 5.1 to PowerShell 7][migration-guide].
12+
813
Windows PowerShell 5.1 is built on top of the .NET Framework v4.5. With the release of PowerShell
914
6.0, PowerShell became an open source project built on .NET Core 2.0. Moving from the .NET Framework
1015
to .NET Core allowed PowerShell to become a cross-platform solution. PowerShell runs on Windows,
@@ -1251,3 +1256,4 @@ To opt-out of this telemetry, set the environment variable `POWERSHELL_TELEMETRY
12511256
[34]: What-s-New-in-PowerShell-73.md
12521257
[35]: What-s-New-in-PowerShell-74.md
12531258
[36]: What-s-New-in-PowerShell-75.md
1259+
[migration-guide]: ./Migrating-from-Windows-PowerShell-51-to-PowerShell-7.md
Lines changed: 260 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,260 @@
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

Comments
 (0)