The Differences Between Windows PowerShell 5.1 and PowerShell 7 — A Practical Guide to Migrating In-House Scripts
· Go Komura · PowerShell, Windows, Migration, Automation, Operational Improvement, Script, Legacy Asset Reuse
“If I install PowerShell 7 on the server, won’t it break our current scripts?” “Is staying on 5.1 a problem?” — I get these questions more and more often from customers who carry in-house operational scripts. The PowerShell that comes with Windows out of the box (5.1) and the PowerShell 7 you install separately. Because the names are the same, people tend to assume that “upgrading replaces it” — but in reality they are separate products that coexist.
Introduce 7 without understanding this relationship correctly and you hit one of two things: “we installed it and nothing changed (the tasks are still running under 5.1)”, or conversely “we migrated and our Japanese file integration started producing garbage”. The latter in particular is an accident specific to Japanese-language environments, and its cause lies in the difference in default character encoding.
This article is aimed at IT and operations staff who own in-house scripts. It organises the relationship and differences between 5.1 and 7 from first principles, and sets out the procedure for actually carrying out a migration, with a decision table.
1. The Bottom Line First
- Windows PowerShell 5.1 and PowerShell 7 are separate products that coexist side by side. 5.1 ships with Windows and is built on .NET Framework; 7 is separately installed and built on .NET. Installing 7 does not remove 5.1.12
- Microsoft is not adding new features to 5.1. Support for 5.1 is tied to the lifecycle of Windows itself, and the main line of development is 7. New scripts should be written against 7.13
- The executables differ. 5.1 is
powershell.exe, 7 ispwsh.exe. Unless you rewrite the start commands in Task Scheduler and elsewhere, existing mechanisms carry on running under 5.1.45 - The default character encodings differ. In 5.1 they vary by cmdlet (Out-File is UTF-16LE, Get-Content is ANSI, and so on); in 7 it is uniformly UTF-8 without BOM. This is the first landmine you step on when migrating in a Japanese-language environment.6
- There is a Windows compatibility feature for modules that do not run under 7.
Import-Module -UseWindowsPowerShellloads them into a background 5.1 process and makes them usable via remoting — but what comes back are serialised objects whose methods cannot be called.7 - Use
#Requires -Versionand$PSVersionTableto state in the code which version a script should run under. That stops, before execution, the accident of running under an unintended version and quietly breaking.89 - Migrate in phases: inventory → test-run under 7 → update start commands. Install 7 via MSI or winget, and decide up front how updates will be distributed (whether via Microsoft Update).524
2. What Is the Relationship Between 5.1 and 7 — Coexistence, Not Replacement
First, the overall picture in a table.
| Item | Windows PowerShell 5.1 | PowerShell 7 |
|---|---|---|
| How you get it | Ships with Windows1 | Installed separately (MSI/winget etc.)2 |
| Foundation | .NET Framework 4.x5 | .NET (7.4 is on .NET 8.0, for instance)54 |
| Executable | powershell.exe | pwsh.exe4 |
| Install location | $Env:windir\System32\WindowsPowerShell\v1.05 | $Env:ProgramFiles\PowerShell\75 |
| Future development | No new features1 | The main line of development. LTS/Stable releases3 |
| Support period | Follows the lifecycle of Windows itself3 | Follows the support policy of the underlying .NET3 |
7 does not replace 5.1; it is installed into a different directory and runs side by side. Module locations (PSModulePath), profiles, and event logs are all managed separately, and because 7’s PSModulePath also includes 5.1’s module paths, most existing modules can be loaded from 7.52
You can check “which one am I in” at any time with these two lines. $PSVersionTable is an automatic variable holding PowerShell’s version information.9
# Check which PowerShell you are currently in
$PSVersionTable.PSVersion # 5.1.x means Windows PowerShell, 7.x means PowerShell 7
$PSVersionTable.PSEdition # Desktop = Windows PowerShell / Core = PowerShell 7
The official positioning is equally clear. Windows PowerShell is the edition bundled with Windows; Microsoft is not updating it with new features, and its support is tied to the version of Windows you are running. PowerShell (the 7 line), on the other hand, is built on the new .NET, and each release has a support period set in line with the support policy of the underlying .NET.13 5.1 is not going to vanish tomorrow, but the practical conclusion is that the baseline for “what you write from now on” and “what you will use for a long time” should be 7.
3. The First Landmine — Default Encoding Differences and Garbled Text
The most common migration trouble in Japanese-language environments is garbled text. The cause is plain: the default character encodings differ between the two.6
| Operation | Default in 5.1 | Default in 7 |
|---|---|---|
Out-File and redirection (>) |
UTF-16LE (with BOM)6 | UTF-8 without BOM6 |
| Set-Content / Add-Content | ANSI (Shift_JIS in a Japanese environment)6 | UTF-8 without BOM |
| Get-Content (file without BOM) | ANSI6 | UTF-8 without BOM |
| Export-Csv | ASCII (Japanese text is lost)6 | UTF-8 without BOM |
| Interpretation of the script itself (no BOM) | ANSI code page6 | UTF-8 |
# The same single line produces files with different byte sequences under 5.1 and 7
'こんにちは' | Out-File -FilePath C:\temp\hello.txt
# Run under 5.1 -> a UTF-16LE (with BOM) file
# Run under 7 -> a UTF-8 without BOM file
This means two things in practice.
First, file integration that assumes Shift_JIS can garble on both reads and writes the moment you move it onto 7. 5.1’s Get-Content reads a file without a BOM as ANSI (Shift_JIS in a Japanese environment), whereas 7 reads it as UTF-8. The remedy is to state -Encoding explicitly on all file I/O. In 7 you can specify a code page number (-Encoding 932) or a registered name, and from 7.4 onwards the value ansi is available too.6 Concrete techniques for CSV processing are collected in the simultaneously published “Automating Excel and CSV Work with PowerShell”.
Second, the save format of the script file itself. When 5.1 reads a script containing Japanese comments that was saved as UTF-8 without BOM, it misinterprets it as ANSI, producing garbled text or syntax errors. Follow the official documentation’s recommendation and save scripts containing non-ASCII characters as UTF-8 with BOM, and they will be interpreted correctly under both 5.1 and 7.6
4. Compatibility — What Stops Working, and How Good the Windows Compatibility Feature Really Is
4.1. What Stops Working
7 can load many existing modules as they are,5 but some will not load. Here are the representative cases listed officially.
- Modules no longer bundled: PSWorkflow/PSWorkflowUtility (workflows), PSScheduledJob, the ISE modules, Microsoft.PowerShell.LocalAccounts and others are not included in 7.4
- Snap-ins: snap-ins, the old extension format that predates modules, are not supported in 7.4
- Code welded to .NET Framework: because the underlying .NET is different in 7, scripts that call .NET methods directly may behave differently.54
- Small behavioural changes:
Export-Csvno longer emits the#TYPEline by default, andGroup-Objectnow returns groups sorted — changes that affect scripts which depend on output.4
There is incompatibility in the other direction too. Scripts that use syntax and features added in 7 — the ternary operator, ForEach-Object -Parallel and so on — will not run under 5.1.5 Which means you have to decide, script by script, whether to “write it so it runs under both” or to “state which one it runs under”.
The support status of Microsoft’s own modules can be checked on the official module compatibility page.10
4.2. How the Windows Compatibility Feature (-UseWindowsPowerShell) Works, and Its Constraints
7 has a Windows compatibility feature for modules that only run under 5.1.
# Load a module that does not support 7 via the compatibility feature (example from the official docs)
Import-Module -Name ScheduledTasks -UseWindowsPowerShell
The mechanism is an application of remoting. A Windows PowerShell 5.1 process starts in the background, the module is loaded into a session called WinPSCompatSession, and a proxy module generated by implicit remoting is imported on the 7 side. 5.1-only modules under System32 are loaded implicitly through this mechanism even when referenced by name or found by command auto-discovery.7
It is convenient, but using it without understanding its constraints leads to quiet breakage. The constraints stated officially are as follows.7
- What is exchanged are serialised values, not live objects. You cannot call methods on the objects that come back; only a snapshot of the properties reaches you.
- It works only on local Windows, and requires Windows PowerShell 5.1.
- All modules loaded through the compatibility feature share a single runspace (a single 5.1 process).
- Some modules (PSScheduledJob among them) are refused by default.
Processing such as “call a method on the result you retrieved” or “you need live objects partway down the pipeline” simply does not work through the compatibility feature. In that case you can also write it so that the entire pipeline executes on the 5.1 side and only the final result comes back,7 but my practical instinct is that if it is going to get complicated, leaving just that piece of processing on 5.1 is easier to maintain.
5. Writing Defensively — #Requires and Version Branching
During a migration period, a state of “we don’t know which one it will run under” inevitably arises. Running under an unintended version and breaking halfway through is the worst outcome, so put defences into the script itself.
Write a #Requires statement and PowerShell will refuse the script before it executes on any version that does not meet the condition.8
#Requires -Version 7.0
# This script is 7-only (it uses ForEach-Object -Parallel and so on).
# If it is started with powershell.exe (5.1), nothing beyond this point runs at all
Conversely, put #Requires -PSEdition Desktop in scripts that are 5.1-only. Desktop is the edition name for the 5.1 line and Core for the 7 line.89
If you want to change just part of the behaviour in a script that runs under both, branch at run time on $PSVersionTable.9
# In a script supporting both 5.1 and 7, branch only on the processing that differs by version
if ($PSVersionTable.PSVersion.Major -ge 6) {
$enc = 932 # 7: Shift_JIS can be specified by code page number
} else {
$enc = 'Default' # 5.1: Default = the system ANSI code page
}
Get-Content -LiteralPath $path -Encoding $enc
The key point is to put this declaration in at the inventory stage, not “once the migration is finished”. A single #Requires line makes it obvious to anyone which world that script belongs to.
6. How to Carry Out the Migration — From Inventory to Updating Task Scheduler
An actual migration proceeds in the following order. A big-bang switch invites accidents, so phased migration is the rule.
Step 1: Inventory. Comb through your script folders and Task Scheduler for the .ps1 files and start commands that are actually running.
# Comb Task Scheduler for tasks that launch PowerShell
Get-ScheduledTask | ForEach-Object {
foreach ($action in $_.Actions) {
# Look at both the executable and the arguments, to catch indirect launches like cmd.exe /c powershell ...
if ("$($action.Execute) $($action.Arguments)" -match 'powershell|pwsh') {
[pscustomobject]@{
TaskPath = $_.TaskPath # task names are only unique within a folder, so record the path too
TaskName = $_.TaskName
Execute = $action.Execute # powershell.exe or pwsh.exe
Arguments = $action.Arguments
}
}
}
} | Export-Csv -Path .\ps-tasks.csv -NoTypeInformation -Encoding UTF8
Step 2: Install 7. Install it via the MSI package (suited to deployment through distribution management tools) or with winget.52
# Installing with winget. Updates then ride the same route via winget upgrade
winget install --id Microsoft.PowerShell --source winget
Decide on update operations up front as well. The MSI from 7.2 onwards has an option to receive updates via Microsoft Update (enabled by default), which lets it ride your normal update flow through WSUS or a configuration management tool.4 The worst pattern is leaving stray installs alone so that old versions of 7 linger.
Step 3: Test-run under 7. Run each inventoried script with pwsh and check whether it works and whether the output files are garbled. Since 7 coexists with 5.1, you can test without stopping the production tasks — that is the benefit of the side-by-side design.2 If you hit errors, isolate the compatibility issues from Section 4 (modules, .NET APIs, behavioural changes).
Step 4: State which one it runs under. Add #Requires -Version 7.0 to what passed the tests, and #Requires -PSEdition Desktop to what stays on 5.1 (Section 5).
Step 5: Update the start commands. Rewrite the Task Scheduler actions. Forget this and you get “we thought we’d migrated to 7, but it’s still running under 5.1”.
# Before (runs under 5.1):
# powershell.exe -NoProfile -ExecutionPolicy RemoteSigned -File C:\scripts\daily-report.ps1
# After (runs under 7):
# "C:\Program Files\PowerShell\7\pwsh.exe" -NoProfile -File C:\scripts\daily-report.ps1
Note that in pwsh.exe the first positional parameter has changed from -Command to -File. Mechanically replacing calls equivalent to powershell.exe -Command "..." changes their interpretation, so always state -File / -Command explicitly.4
For the handling of execution policy and script signing, see the simultaneously published “PowerShell Execution Policy and Script Signing”; for the decision about migrating from batch files (.bat), see “Should You Migrate Batch Files to PowerShell?”.
7. Rules of Thumb in Practice (Decision Table)
| Issue | Options | Guide to the decision |
|---|---|---|
| Baseline for new scripts | 5.1 / 7 | 7 as a rule. 5.1 is in maintenance mode with no new features; the main line of development is 713 |
| Migrating existing scripts | Big-bang switch / phased migration | Inventory → test under 7 → update start commands for those that pass. Side-by-side is exactly what makes phased migration possible5 |
| You have 5.1-only modules | Give up on migrating / -UseWindowsPowerShell / leave just that processing on 5.1 | Use the compatibility feature only once you understand the serialisation constraint (no method calls). If it gets complicated, leaving it on 5.1 is easier to maintain7 |
| Declaring the version | Do nothing / #Requires | Put #Requires or a run-time check in every script. It stops execution on an unintended version before it starts8 |
| File I/O | Leave it to the defaults / state -Encoding | Always state it. This structurally prevents garbled text caused by the default differences between 5.1 and 76 |
| Update operations for 7 | Reinstall manually / the MSI’s Microsoft Update integration, or winget | Decide the update route before you distribute it. An abandoned, out-of-date 7 is the most dangerous outcome42 |
8. Summary
- 5.1 and 7 are separate products that coexist side by side. Installing 7 does not break existing mechanisms — but by the same token, nothing migrates until you change the start commands.
- 5.1 is in maintenance mode: no new features, support tied to Windows itself. 7 is the main line of development. Write new work against 7.
- The biggest landmine in Japanese-language environments is the difference in default encoding (5.1 varies, 7 is UTF-8 without BOM). Prevent it by stating -Encoding on I/O and saving scripts as UTF-8 with BOM.
- Modules that do not run under 7 can be rescued with the Windows compatibility feature, but with the constraint that only serialised values come back. If that will not do, leave just the affected processing on 5.1.
- Use #Requires and $PSVersionTable to state in the code which version a script runs under, and stop execution on an unintended version.
- Migrate in phases: inventory → install 7 (MSI/winget) → test-run → add #Requires → update the Task Scheduler start commands.
Related Articles
- PowerShell Command Basics — The Operations to Learn First and How to Use Them Safely
- Applied PowerShell Scripting — Safely Automating Log Investigation, Archiving, and Reporting
- Automating Excel and CSV Work with PowerShell — Practical Recipes for Aggregation, Reconciliation, and Report Output
- Preparing for VBScript Deprecation: An Audit Guide for VBA and Internal Tools
- Pre-Migration Checklist for Moving from .NET Framework to .NET
- Should You Migrate Batch Files to PowerShell?
Related Consulting Areas
KomuraSoft LLC handles inventories of in-house script assets and the planning and execution of phased migration to PowerShell 7, isolating processing that depends on 5.1-only modules, and investigating faults such as “after migrating, the text garbled” or “it stopped working”.
- Legacy Asset Reuse & Migration Support
- Maintenance & Modernization of Existing Windows Software
- Technical Consulting & Design Review
- Contact Us
References
-
Microsoft Learn, What is Windows PowerShell?. On Windows PowerShell and PowerShell being separate products, on Windows PowerShell shipping with Windows, being built on .NET Framework and having 5.1 as its latest version, and on Microsoft not updating it with new features while its support is tied to the version of Windows in use. ↩ ↩2 ↩3 ↩4 ↩5 ↩6
-
Microsoft Learn, Install PowerShell 7 on Windows. On PowerShell 7 not replacing Windows PowerShell 5.1 but being installed into a new directory and running side by side, on the default install location being $Env:ProgramFiles\PowerShell\7, and on installation methods such as winget and MSI. ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7
-
Microsoft Learn, PowerShell Support Lifecycle. On PowerShell 7 having LTS and Stable release categories with end-of-support dates following the support policy of the underlying .NET, and on Windows PowerShell following the Windows support lifecycle as a component of Windows. ↩ ↩2 ↩3 ↩4 ↩5 ↩6
-
Microsoft Learn, Differences between Windows PowerShell 5.1 and PowerShell 7.x. On the executable changing from powershell.exe to pwsh.exe to support side-by-side operation, on the first positional parameter changing from -Command to -File, on modules such as PSWorkflow, PSScheduledJob, and LocalAccounts as well as snap-ins not being included in 7, on behavioural changes such as Export-Csv omitting the #TYPE line by default and Group-Object returning sorted output, on the underlying .NET of each version, and on the Microsoft Update integration option in the MSI from 7.2 onwards. ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7 ↩8 ↩9 ↩10 ↩11
-
Microsoft Learn, Migrating from Windows PowerShell 5.1 to PowerShell 7. On PowerShell 7 being designed for side-by-side coexistence with 5.1 (separate install path, PSModulePath, profile, and event log), on the install locations of 5.1 and 7, on many existing modules working under 7 and compatibility being supplemented with UseWindowsPowerShell, on new features such as the ternary operator and ForEach-Object -Parallel, and on deployment via MSI/ZIP. ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7 ↩8 ↩9 ↩10 ↩11 ↩12
-
Microsoft Learn, about_Character_Encoding. On the default encodings in Windows PowerShell 5.1 being inconsistent across cmdlets (Out-File and redirection use UTF-16LE, Set-Content/Get-Content use ANSI, Export-Csv uses ASCII, and so on), on PowerShell 6 onwards defaulting uniformly to UTF-8 without BOM, on 5.1 misinterpreting BOM-less scripts as ANSI so that scripts containing non-ASCII characters should be saved as UTF-8 with BOM, and on code page number specification and the ansi value in 7.4. ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7 ↩8 ↩9 ↩10 ↩11
-
Microsoft Learn, about_Windows_PowerShell_Compatibility. On the compatibility feature loading modules into a background Windows PowerShell 5.1 process (WinPSCompatSession) and generating proxy modules through implicit remoting, on both explicit loading via UseWindowsPowerShell and automatic loading existing, and on the constraints — working with serialised values rather than live objects, being limited to local Windows, sharing a single runspace, and a default list of modules refused for loading. ↩ ↩2 ↩3 ↩4 ↩5
-
Microsoft Learn, about_Requires. On the #Requires statement refusing to execute the script at all unless prerequisites such as the specified PowerShell version (-Version), edition (-PSEdition Core or Desktop), and modules are met. ↩ ↩2 ↩3 ↩4
-
Microsoft Learn, about_Automatic_Variables. On $PSVersionTable being a read-only hash table holding details of the current session’s PowerShell version, and on the PSEdition property taking the value Desktop under 5.1 (the full-featured Windows edition) and Core from 6 onwards. ↩ ↩2 ↩3 ↩4
-
Microsoft Learn, PowerShell 7 module compatibility. On the PowerShell 7 support status of Microsoft’s individual modules (including the Windows management modules) being collected there. ↩
Related Articles
Recent articles sharing the same tags. Deepen your understanding with closely related topics.
Parameter Design and Modularization for PowerShell Scripts — From a Script That Works to a Script You Can Hand Over
A step-by-step procedure for raising a PowerShell script to a quality you can hand to someone else. Covers the param block and [CmdletBin...
Where to Look When a PowerShell Script Is Slow — Arrays, Pipelines and Matching
The classic causes of slow PowerShell scripts, laid out. Why += on an array is O(n^2), the difference between the pipeline and foreach, t...
Stop Using Write-Host — PowerShell Output Streams and Log Design
How to choose between PowerShell's six output streams, the problems with Write-Host and where it genuinely belongs, why function return v...
Parallel Processing in PowerShell — Choosing Between ForEach-Object -Parallel and Jobs
A practical rundown of the differences between ForEach-Object -Parallel, Start-ThreadJob and Start-Job and when to use each, $using: and ...
Calling External EXEs Correctly from PowerShell — The Pitfalls of Argument Quoting, Exit Codes, and Mojibake
Call robocopy or an in-house EXE from PowerShell and the arguments break, the exit code is unavailable, and the output turns into mojibak...
Related Topics
These topic pages place the article in a broader service and decision context.
Windows Technical Topics
Topic hub for KomuraSoft LLC's Windows development, investigation, and legacy-asset articles.
Where This Topic Connects
This article connects naturally to the following service pages.
Windows App Development
We support Windows desktop applications that involve resident processing, device integration, operational logging, and maintainable structure.
Windows Software Maintenance & Modernization
We support staged upgrades, feature additions, 64-bit readiness, and maintainable restructuring for existing Windows software.
Frequently Asked Questions
Common questions about the topic of this article.
- What is the difference between Windows PowerShell 5.1 and PowerShell 7?
- They are separate products. 5.1 ships with Windows and runs on .NET Framework; Microsoft has stopped adding new features to it, and its support follows the lifecycle of Windows itself. 7 is a separately installed product running on .NET (formerly .NET Core) and is the main line of development. 7 does not replace 5.1: it is installed into a different directory and coexists side by side, and the executables are distinguished as powershell.exe and pwsh.exe.
- Will installing PowerShell 7 break my existing 5.1 scripts?
- No. 7 is installed into a different directory (by default Program Files\PowerShell\7), and its module locations and profiles are managed separately from 5.1. Existing mechanisms that launch powershell.exe, such as Task Scheduler entries, carry on running under 5.1 as before. For that very reason, be aware of the flip side: installing 7 migrates nothing by itself, and any script you want to run under 7 needs its start command explicitly switched to pwsh.exe.
- Why does my existing script produce garbled text under PowerShell 7?
- Because the default character encoding changed. In 5.1 the defaults differ by cmdlet (Out-File is UTF-16LE, Get-Content is ANSI, and so on), whereas 7 uses UTF-8 without BOM uniformly. In Japanese-language environments a lot of file-based integration assumes Shift_JIS, so migrating with the defaults can garble both reads and writes. Two measures prevent nearly all of it: state -Encoding explicitly on file I/O, and save scripts that themselves contain non-ASCII characters as UTF-8 with BOM.
- What should I do about modules that do not work under PowerShell 7?
- First check whether they work when simply imported with Import-Module under 7. If they do not, the Windows compatibility feature (Import-Module -UseWindowsPowerShell) loads the module into a background 5.1 process and makes it usable from 7 via remoting. There are constraints, though: what comes back are serialised objects whose methods cannot be called, and it only works on local Windows. For processing that runs into those constraints, the realistic answer is not to force it — leave just that part on 5.1.
- How should I go about migrating in-house scripts from 5.1 to 7?
- Make it a phased migration rather than a big-bang switch. Start by taking an inventory of the .ps1 files in Task Scheduler and in your script folders, then test-run each one under 7 (pwsh) to see whether it works. For the ones that do, add #Requires -Version 7 and update the Task Scheduler start command from powershell.exe to pwsh.exe. Do not force anything that only runs under 5.1 — leave it in place, having stated explicitly which version it should run under. Install 7 itself via MSI or winget, and decide how updates will be distributed at the same time.
Author Profile
Profile page for the article author.
Go Komura
Representative of KomuraSoft LLC
Focused on Windows software development, technical consulting, and investigations into failures that are difficult to reproduce.
Public links