diff --git a/reference/docs-conceptual/toc.yml b/reference/docs-conceptual/toc.yml index 183726c559e..0cd9337cba2 100644 --- a/reference/docs-conceptual/toc.yml +++ b/reference/docs-conceptual/toc.yml @@ -228,6 +228,21 @@ items: href: whats-new/what-s-new-in-powershell-72.md - name: Migrating from Windows PowerShell 5.1 to PowerShell 7 href: whats-new/Migrating-from-Windows-PowerShell-51-to-PowerShell-7.md + items: + - name: Script compatibility audit + href: whats-new/migration/script-compatibility-audit.md + - name: Module compatibility strategy + href: whats-new/migration/module-compatibility-strategy.md + - name: Encoding changes + href: whats-new/migration/encoding-changes.md + - name: Profile migration + href: whats-new/migration/profile-migration.md + - name: Enterprise deployment + href: whats-new/migration/enterprise-deployment.md + - name: Scheduled tasks and automation + href: whats-new/migration/scheduled-tasks-automation.md + - name: Testing and rollback + href: whats-new/migration/testing-and-rollback.md - name: Differences between Windows PowerShell 5.1 and PowerShell 7.x href: whats-new/differences-from-windows-powershell.md - name: PowerShell differences on non-Windows platforms diff --git a/reference/docs-conceptual/whats-new/Migrating-from-Windows-PowerShell-51-to-PowerShell-7.md b/reference/docs-conceptual/whats-new/Migrating-from-Windows-PowerShell-51-to-PowerShell-7.md index fce71d608bb..86de2c56c46 100644 --- a/reference/docs-conceptual/whats-new/Migrating-from-Windows-PowerShell-51-to-PowerShell-7.md +++ b/reference/docs-conceptual/whats-new/Migrating-from-Windows-PowerShell-51-to-PowerShell-7.md @@ -1,350 +1,365 @@ --- -description: Update from PowerShell 5.1 to PowerShell 7 for your Windows platforms. -ms.date: 04/02/2024 +description: >- + A phased migration guide for moving from Windows PowerShell 5.1 to PowerShell 7 + on Windows, covering assessment, installation, script migration, and validation. +ms.date: 04/15/2026 title: Migrating from Windows PowerShell 5.1 to PowerShell 7 --- # Migrating from Windows PowerShell 5.1 to PowerShell 7 -Designed for cloud, on-premises, and hybrid environments, PowerShell 7 is packed with enhancements -and [new features][09]. +PowerShell 7 is the successor to Windows PowerShell 5.1 and runs side-by-side +with it on Windows. It's built on .NET (rather than .NET Framework), bringing +improved performance, new language features like ternary operators and +`ForEach-Object -Parallel`, SSH-based remoting, and cross-platform support. -- Installs and runs side-by-side with Windows PowerShell -- Improved compatibility with existing Windows PowerShell modules -- New language features, like ternary operators and `ForEach-Object -Parallel` -- Improved performance -- SSH-based remoting -- Cross-platform interoperability -- Support for Docker containers +This guide walks you through a phased migration from Windows PowerShell 5.1 +to PowerShell 7 on Windows 10, Windows 11, and Windows Server 2016 and later. +PowerShell 7 also runs on macOS and Linux. For information about the support +lifecycle, see [PowerShell Support Lifecycle][lifecycle]. -PowerShell 7 works side-by-side with Windows PowerShell letting you easily test and compare between -editions before deployment. Migration is simple, quick, and safe. +For a complete reference of breaking changes and behavioral differences, see +[Differences between Windows PowerShell 5.1 and PowerShell 7.x][differences]. -PowerShell 7 is supported on the following Windows operating systems: +## Phase 1: Assess your environment -- Windows 10, and 11 -- Windows Server 2016, 2019, and 2022 +Before installing PowerShell 7, audit your existing scripts, modules, and +automation to understand what needs to change. -PowerShell 7 also runs on macOS and several Linux distributions. For a list of supported operating -systems and information about the support lifecycle, see the [PowerShell Support Lifecycle][06]. +### Audit your scripts -## Installing PowerShell 7 +Scan your `.ps1` and `.psm1` files for patterns that are removed or changed in +PowerShell 7. Common breaking patterns include: -For flexibility and to support the needs of IT, DevOps engineers, and developers, there are several -options available to install PowerShell 7. In most cases, the installation options can be reduced to -the following methods: +- WMI v1 cmdlets (`Get-WmiObject`, `Invoke-WmiMethod`) replaced by CIM cmdlets +- `*-EventLog` cmdlets replaced by `Get-WinEvent` and `New-WinEvent` +- PowerShell Workflow (`workflow` keyword) removed entirely +- `New-WebServiceProxy` removed (no SOAP client in .NET Core) +- Encoding defaults changed from locale-dependent to UTF-8 without BOM -- Deploy PowerShell using the [MSI package][03] -- Deploy PowerShell using the [ZIP package][05] +For a complete list of removed cmdlets and automated scanning instructions, see +[Audit scripts for PowerShell 7 compatibility][script-audit]. -> [!NOTE] -> The MSI package can be deployed and updated with management products such as -> [Microsoft Configuration Manager][12]. Download the packages from -> [GitHub Release page][24]. +### Identify module dependencies -Deploying the MSI package requires Administrator permission. The ZIP package can be deployed by any -user. The ZIP package is the easiest way to install PowerShell 7 for testing, before committing to a -full installation. +Most Windows PowerShell 5.1 modules work in PowerShell 7. Some require the +Windows PowerShell compatibility layer or have known issues. Test your module +inventory before migrating production scripts. -You may also install PowerShell 7 via the Windows Store or `winget`. For more information about both -of these methods, see the detailed instructions in [Installing PowerShell on Windows][04]. +For module testing strategies and known compatibility issues, see +[Module compatibility strategy for PowerShell 7][module-strategy]. -## Using PowerShell 7 side-by-side with Windows PowerShell 5.1 +### Catalog encoding-sensitive scripts -PowerShell 7 is designed to coexist with Windows PowerShell 5.1. The following features ensure that -your investment in PowerShell is protected and your migration to PowerShell 7 is simple. +If your scripts generate files consumed by other tools, or parse files that +assume a specific encoding or byte order mark (BOM), review the encoding changes +in PowerShell 7. The default output encoding changed from locale-dependent +(often Windows-1252 or UTF-16) to UTF-8 without BOM. -- Separate installation path and executable name -- Separate PSModulePath -- Separate profiles for each version -- Improved module compatibility -- New remoting endpoints -- Group policy support -- Separate Event logs +For a complete encoding comparison and migration strategies, see +[Encoding changes in PowerShell 7][encoding-changes]. -### Differences in .NET versions +### Inventory your automation -PowerShell 7.4 is built on .NET 8.0. Windows PowerShell 5.1 is built on .NET Framework 4.x. The -differences between the .NET versions might affect the behavior of your scripts, especially if you -are calling .NET method directly. For more information, -[Differences between Windows PowerShell 5.1 and PowerShell 7.x][10]. +Catalog all scheduled tasks, CI/CD pipelines, Group Policy scripts, and +remoting endpoints that invoke `powershell.exe`. Each of these needs to be +updated to call `pwsh.exe` with the correct argument syntax. -### Separate installation path and executable name +## Phase 2: Install and configure -PowerShell 7 installs to a new directory, enabling side-by-side execution with Windows PowerShell -5.1. +PowerShell 7 installs to a separate directory and runs a separate executable. +It doesn't replace Windows PowerShell 5.1. -Install locations by version: +### Installation methods -- Windows PowerShell 5.1: `$Env:windir\System32\WindowsPowerShell\v1.0` -- PowerShell 6.x: `$Env:ProgramFiles\PowerShell\6` -- PowerShell 7: `$Env:ProgramFiles\PowerShell\7` +| Method | Best for | Requires admin | +| ------ | -------- | -------------- | +| [MSI package][install-msi] | Servers, enterprise deployment via SCCM/Intune | Yes | +| [winget][install-winget] | Developer workstations on Windows 10/11 | No | +| [ZIP package][install-zip] | Side-loading, testing, Nano Server, IoT | No | +| [Microsoft Store][install-store] | Casual exploration (has limitations) | No | -The new location is added to your PATH allowing you to run both Windows PowerShell 5.1 and -PowerShell 7. If you're migrating from PowerShell 6.x to PowerShell 7, PowerShell 6 is removed and -the PATH replaced. - -In Windows PowerShell, the PowerShell executable is named `powershell.exe`. In version 6 and above, -the executable is named `pwsh.exe`. The new name makes it easy to support side-by-side execution of -both versions. +> [!NOTE] +> The MSI package can be deployed and updated with management products such as +> [Microsoft Configuration Manager][sccm]. Download the packages from the +> [GitHub Releases page][gh-releases]. -### Separate PSModulePath +For enterprise-scale deployment guidance including SCCM, Intune, air-gapped +networks, and Group Policy, see +[Deploy PowerShell 7 in enterprise environments][enterprise]. -By default, Windows PowerShell and PowerShell 7 store modules in different locations. PowerShell 7 -combines those locations in the `$Env:PSModulePath` environment variable. When importing a module by -name, PowerShell checks the location specified by `$Env:PSModulePath`. This allows PowerShell 7 to -load both Core and Desktop modules. +### Side-by-side installation paths -| Install Scope | Windows PowerShell 5.1 | PowerShell 7.0 | -| ----------------------------------- | ----------------------------------------------------- | ---------------------------------------- | -| PowerShell modules | `$Env:windir\system32\WindowsPowerShell\v1.0\Modules` | `$Env:ProgramFiles\PowerShell\7\Modules` | -| User installed
AllUsers scope | `$Env:ProgramFiles\WindowsPowerShell\Modules` | `$Env:ProgramFiles\PowerShell\Modules` | -| User installed
CurrentUser scope | `$HOME\Documents\WindowsPowerShell\Modules` | `$HOME\Documents\PowerShell\Modules` | +PowerShell 7 and Windows PowerShell 5.1 coexist on the same machine: -The following examples show the default values of `$Env:PSModulePath` for each version. +| Version | Executable | Install path | +| ------- | ---------- | ------------ | +| Windows PowerShell 5.1 | `powershell.exe` | `$Env:windir\System32\WindowsPowerShell\v1.0` | +| PowerShell 7 | `pwsh.exe` | `$Env:ProgramFiles\PowerShell\7` | -- For Windows PowerShell 5.1: +The PowerShell 7 directory is added to your `PATH`. Both executables are +available from any terminal. If you're migrating from PowerShell 6.x, +PowerShell 6 is removed and its `PATH` entry is replaced. - ```powershell - $Env:PSModulePath -split (';') - ``` +### Separate PSModulePath - ```Output - C:\Users\\Documents\WindowsPowerShell\Modules - C:\Program Files\WindowsPowerShell\Modules - C:\WINDOWS\System32\WindowsPowerShell\v1.0\Modules - ``` +Windows PowerShell and PowerShell 7 store modules in different locations. +PowerShell 7 combines both sets of paths in `$Env:PSModulePath`, so it can +load modules from either location: -- For PowerShell 7: +| Install scope | Windows PowerShell 5.1 | PowerShell 7 | +| ------------- | ---------------------- | ------------ | +| Built-in modules | `$Env:windir\system32\WindowsPowerShell\v1.0\Modules` | `$Env:ProgramFiles\PowerShell\7\Modules` | +| AllUsers | `$Env:ProgramFiles\WindowsPowerShell\Modules` | `$Env:ProgramFiles\PowerShell\Modules` | +| CurrentUser | `$HOME\Documents\WindowsPowerShell\Modules` | `$HOME\Documents\PowerShell\Modules` | - ```powershell - $Env:PSModulePath -split (';') - ``` +PowerShell 7's `$Env:PSModulePath` includes _both_ the PowerShell 7 paths and +the Windows PowerShell paths: - ```Output - C:\Users\\Documents\PowerShell\Modules - C:\Program Files\PowerShell\Modules - C:\Program Files\PowerShell\7\Modules - C:\Program Files\WindowsPowerShell\Modules - C:\WINDOWS\System32\WindowsPowerShell\v1.0\Modules - ``` +```powershell +$Env:PSModulePath -split (';') +``` -Notice that PowerShell 7 includes the Windows PowerShell paths and the PowerShell 7 paths to provide -autoloading of modules. +```Output +C:\Users\\Documents\PowerShell\Modules +C:\Program Files\PowerShell\Modules +C:\Program Files\PowerShell\7\Modules +C:\Program Files\WindowsPowerShell\Modules +C:\WINDOWS\System32\WindowsPowerShell\v1.0\Modules +``` > [!NOTE] -> Additional paths may exist if you have changed the PSModulePath environment variable or installed -> custom modules or applications. - -For more information, see [about_PSModulePath][17]. +> Additional paths may exist if you changed the **PSModulePath** environment +> variable or installed custom modules or applications. For more information, +> see [about_PSModulePath][about-psmodulepath]. -For more information about Modules, see [about_Modules][15]. +## Phase 3: Migrate profiles and scripts -### Separate profiles +### Migrate your profiles -A PowerShell profile is a script that executes when PowerShell starts. This script customizes your -environment by adding commands, aliases, functions, variables, modules, and PowerShell drives. The -profile script makes these customizations available in every session without having to manually -recreate them. +PowerShell profiles execute when a session starts and customize your +environment with aliases, functions, variables, and module imports. The profile +location changed in PowerShell 7: -The path to the location of the profile has changed in PowerShell 7. +| Scope | Windows PowerShell 5.1 | PowerShell 7 | +| ----- | ---------------------- | ------------ | +| CurrentUser, CurrentHost | `$HOME\Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1` | `$HOME\Documents\PowerShell\Microsoft.PowerShell_profile.ps1` | +| CurrentUser, AllHosts | `$HOME\Documents\WindowsPowerShell\profile.ps1` | `$HOME\Documents\PowerShell\profile.ps1` | +| AllUsers, CurrentHost | `$PSHOME\Microsoft.PowerShell_profile.ps1` | `$Env:ProgramFiles\PowerShell\7\Microsoft.PowerShell_profile.ps1` | +| AllUsers, AllHosts | `$PSHOME\profile.ps1` | `$Env:ProgramFiles\PowerShell\7\profile.ps1` | -- In Windows PowerShell 5.1, the location of the profile is `$HOME\Documents\WindowsPowerShell`. -- In PowerShell 7, the location of the profile is `$HOME\Documents\PowerShell`. +You can verify the profile paths in any session: -The profile filenames have also changed: +```powershell +$PROFILE | Select-Object *Host* | Format-List +``` - ```powershell - $PROFILE | Select-Object *Host* | Format-List - ``` +For strategies on sharing profiles between editions, handling OneDrive document +redirection, and avoiding common pitfalls, see +[Migrate PowerShell profiles][profile-migration]. - ```Output - AllUsersAllHosts : C:\Program Files\PowerShell\7\profile.ps1 - AllUsersCurrentHost : C:\Program Files\PowerShell\7\Microsoft.PowerShell_profile.ps1 - CurrentUserAllHosts : C:\Users\\Documents\PowerShell\profile.ps1 - CurrentUserCurrentHost : C:\Users\\Documents\PowerShell\Microsoft.PowerShell_profile.ps1 - ``` +### Fix incompatible scripts -For more information -[about_Profiles][16]. +Update scripts to replace removed cmdlets and handle behavioral differences. +The most common changes are: -### PowerShell 7 compatibility with Windows PowerShell 5.1 modules +| Windows PowerShell 5.1 pattern | PowerShell 7 replacement | +| ------------------------------ | ------------------------ | +| `Get-WmiObject Win32_Process` | `Get-CimInstance Win32_Process` | +| `Get-EventLog -LogName Application` | `Get-WinEvent -LogName Application` | +| `Invoke-WmiMethod` | `Invoke-CimMethod` | +| `New-WebServiceProxy` | Use `Invoke-RestMethod` or a .NET HTTP client | +| `powershell.exe -Command "..."` | `pwsh.exe -Command "..."` | -Most of the modules you use in Windows PowerShell 5.1 already work with PowerShell 7, including -Azure PowerShell and Active Directory. We're continuing to work with other teams to add native -PowerShell 7 support for more modules including Microsoft Graph, Office 365, and others. For the -current list of supported modules, see [PowerShell 7 module compatibility][11]. +For the complete cmdlet replacement map, `.NET` method changes, and automated +scanning instructions, see +[Audit scripts for PowerShell 7 compatibility][script-audit]. -> [!NOTE] -> On Windows, we've also added a **UseWindowsPowerShell** switch to `Import-Module` to ease the -> transition to PowerShell 7 for those using incompatible modules. For more information on this -> functionality, see [about_Windows_PowerShell_Compatibility][20]. +### Use the Windows PowerShell compatibility layer -## PowerShell Remoting +For modules that don't work natively in PowerShell 7, use the +**UseWindowsPowerShell** switch on `Import-Module`. This creates a hidden +remoting session to Windows PowerShell 5.1 and proxies module commands into +your PowerShell 7 session. -PowerShell remoting lets you run any PowerShell command on one or more remote computers. You can -establish persistent connections, start interactive sessions, and run scripts on remote computers. +```powershell +Import-Module ActiveDirectory -UseWindowsPowerShell +``` -### WS-Management remoting +For more information, see +[about_Windows_PowerShell_Compatibility][about-compat]. -Windows PowerShell 5.1 and below use the WS-Management (WSMAN) protocol for connection negotiation -and data transport. Windows Remote Management (WinRM) uses the WSMAN protocol. If WinRM has been -enabled, PowerShell 7 uses the existing Windows PowerShell 5.1 endpoint named `Microsoft.PowerShell` -for remoting connections. To update PowerShell 7 to include its own endpoint, run the -`Enable-PSRemoting` cmdlet. For information about connecting to specific endpoints, see -[WS-Management Remoting in PowerShell][08] +> [!IMPORTANT] +> The compatibility layer has known limitations including performance overhead +> and temp file accumulation in long-running sessions. For details, see +> [Module compatibility strategy for PowerShell 7][module-strategy]. -To use Windows PowerShell remoting, the remote computer must be configured for remote management. -For more information, including instructions, see [About Remote Requirements][19]. +### Handle encoding changes -For more information about working with remoting, see [About Remote][18] +PowerShell 7 defaults to UTF-8 without BOM for all file output. If your +scripts generate files consumed by tools that expect a different encoding, +you need to specify the encoding explicitly or update the consuming tools. -### SSH-based remoting +For a full comparison of encoding defaults and migration strategies, see +[Encoding changes in PowerShell 7][encoding-changes]. -SSH-based remoting was added in PowerShell 6.x to support other operating systems that can't use -Windows native components like **WinRM**. SSH remoting creates a PowerShell host process on the -target computer as an SSH subsystem. For details and examples on setting up SSH-based remoting on -Windows or Linux, see: [PowerShell remoting over SSH][07]. +## Phase 4: Migrate infrastructure -> [!NOTE] -> The PowerShell Gallery (PSGallery) contains a module and cmdlet that automatically configures -> SSH-based remoting. Install the `Microsoft.PowerShell.RemotingTools` module from the -> [PSGallery][25] and run the `Enable-SSH` cmdlet. +### Update remoting endpoints -The `New-PSSession`, `Enter-PSSession`, and `Invoke-Command` cmdlets have new parameter sets to -support SSH connections. +Windows PowerShell 5.1 and PowerShell 7 use separate WinRM endpoints. By +default, PowerShell 7 connects to the existing Windows PowerShell 5.1 endpoint +named `Microsoft.PowerShell`. To create a PowerShell 7 endpoint, run: ```powershell -[-HostName ] [-UserName ] [-KeyFilePath ] +Enable-PSRemoting ``` -To create a remote session, specify the target computer with the **HostName** parameter and provide -the user name with **UserName**. When running the cmdlets interactively, you're prompted for a -password. +To connect to the PowerShell 7 endpoint from a remote machine: ```powershell -Enter-PSSession -HostName -UserName +Enter-PSSession -ComputerName Server01 -ConfigurationName PowerShell.7 ``` -Alternatively, when using the **HostName** parameter, provide the username information followed by -the at sign (`@`), followed by the computer name. +For more information about WS-Management remoting, see +[WS-Management Remoting in PowerShell][wsman-remoting]. For information about +remote requirements, see [About Remote Requirements][about-remote-req]. + +#### SSH-based remoting + +SSH remoting was added in PowerShell 6.x and is the recommended approach for +cross-platform scenarios. It creates a PowerShell host process on the target +as an SSH subsystem. ```powershell -Enter-PSSession -HostName @ +Enter-PSSession -HostName Server01 -UserName admin ``` -You may set up SSH key authentication using a private key file with the **KeyFilePath** parameter. -For more information, see [OpenSSH Key Management][21]. +> [!NOTE] +> The [Microsoft.PowerShell.RemotingTools][remoting-tools] module from the +> PowerShell Gallery includes the `Enable-SSH` cmdlet to help configure +> SSH-based remoting. -## Group Policy supported +For details and examples, see +[PowerShell remoting over SSH][ssh-remoting]. -PowerShell includes Group Policy settings to help you define consistent option values for servers in -an enterprise environment. These settings include: +### Update scheduled tasks and automation -- Console session configuration: Sets a configuration endpoint in which PowerShell is run. -- Turn on Module Logging: Sets the LogPipelineExecutionDetails property of modules. -- Turn on PowerShell Script Block Logging: Enables detailed logging of all PowerShell scripts. -- Turn on Script Execution: Sets the PowerShell execution policy. -- Turn on PowerShell Transcription: enables capturing of input and output of PowerShell commands - into text-based transcripts. -- Set the default source path for Update-Help: Sets the source for Updatable Help to a directory, - not the Internet. +Every scheduled task, CI/CD pipeline, or script that calls `powershell.exe` +must be updated to call `pwsh.exe`. The first positional parameter also +changed from `-Command` to `-File` in PowerShell 7. If your scheduled tasks +use positional arguments, add `-Command` explicitly. -For more information, see [about_Group_Policy_Settings][13]. +For step-by-step task migration instructions and audit scripts, see +[Migrate scheduled tasks and automation to PowerShell 7][scheduled-tasks]. -PowerShell 7 includes Group Policy templates and an installation script in `$PSHOME`. +### Configure Group Policy -Group Policy tools use administrative template files (`.admx`, `.adml`) to populate policy settings -in the user interface. This allows administrators to manage registry-based policy settings. The -`InstallPSCorePolicyDefinitions.ps1` script installs PowerShell Administrative Templates on the -local machine. +PowerShell 7 includes its own Group Policy templates, separate from Windows +PowerShell 5.1. Supported settings include: -```powershell -Get-ChildItem -Path $PSHOME -Filter *Core*Policy* -``` +- Console session configuration +- Module Logging +- Script Block Logging +- Script Execution (execution policy) +- Transcription +- Default source path for `Update-Help` -```Output - Directory: C:\Program Files\PowerShell\7 +PowerShell 7 ships `.admx` and `.adml` templates in `$PSHOME`. Install them +with the included script: -Mode LastWriteTime Length Name ----- ------------- ------ ---- --a--- 2/27/2020 12:38 AM 15861 InstallPSCorePolicyDefinitions.ps1 --a--- 2/27/2020 12:28 AM 9675 PowerShellCoreExecutionPolicy.adml --a--- 2/27/2020 12:28 AM 6201 PowerShellCoreExecutionPolicy.admx +```powershell +& "$PSHOME\InstallPSCorePolicyDefinitions.ps1" ``` -## Separate Event Logs +For more information, see [about_Group_Policy_Settings][about-gpo]. + +### Separate event logs -Windows PowerShell and PowerShell 7 log events to separate event logs. Use the following command to -get a list of the PowerShell logs. +Windows PowerShell and PowerShell 7 log events to separate event logs. Update +any monitoring or SIEM rules that reference PowerShell event logs: ```powershell Get-WinEvent -ListLog *PowerShell* ``` -For more information, see [about_Logging_Windows][14]. +For more information, see [about_Logging_Windows][about-logging]. -## Improved editing experience with Visual Studio Code +## Phase 5: Validate and roll back -[Visual Studio Code (VS Code)][22] with the [PowerShell Extension][23] is the supported scripting -environment for PowerShell 7. The Windows PowerShell Integrated Scripting Environment (ISE) only -supports Windows PowerShell. +### Test your migration -The updated PowerShell extension includes: +Run your scripts and modules in PowerShell 7 and compare behavior against +Windows PowerShell 5.1. Key areas to validate: -- New ISE compatibility mode -- PSReadLine in the Integrated Console, including syntax highlighting, multi-line editing, and back - search -- Stability and performance improvements -- New CodeLens integration -- Improved path autocompletion +- Module loading and cmdlet behavior +- File output encoding +- Remoting endpoint connectivity +- Scheduled task execution +- Error handling and `$ErrorActionPreference` behavior -To make the transition to Visual Studio Code easier, use the **Enable ISE Mode** function available -in the **Command Palette**. This function switches VS Code into an ISE-style layout. The ISE-style -layout gives you all the new features and capabilities of PowerShell in a familiar user experience. +For a validation checklist, cross-edition test matrix, and rollback procedures, +see [Test and validate your PowerShell 7 migration][testing-rollback]. -To switch to the new ISE layout, press Ctrl+Shift+P to open the -**Command Palette**, type `PowerShell` and select **PowerShell: Enable ISE Mode**. +### Plan for rollback -To set the layout to the original layout, open the **Command Palette**, select -**PowerShell: Disable ISE Mode (restore to defaults)**. +PowerShell 7 doesn't replace Windows PowerShell 5.1. If you encounter +issues, you can revert automation pointers from `pwsh.exe` back to +`powershell.exe` without uninstalling PowerShell 7. Plan for a +parallel-run period where both editions handle production workloads. -For details about customizing the VS Code layout to ISE, see -[How to Replicate the ISE Experience in Visual Studio Code][01] +### Editing experience -> [!NOTE] -> There are no plans to update the ISE with new features. In the latest versions of Windows 10 or -> Windows Server 2019 and higher, the ISE is now a user-uninstallable feature. There are no plans to -> permanently remove the ISE. The PowerShell Team and its partners are focused on improving the -> scripting experience in the PowerShell extension for Visual Studio Code. +[Visual Studio Code][vscode] with the [PowerShell Extension][ps-ext] is the +recommended editor for PowerShell 7. The Windows PowerShell ISE only supports +Windows PowerShell and is no longer being updated with new features. + +The PowerShell extension includes: + +- ISE compatibility mode +- PSReadLine in the Integrated Console with syntax highlighting and multi-line + editing +- CodeLens integration +- Improved path autocompletion + +To switch to an ISE-style layout, press +Ctrl+Shift+P, type `PowerShell`, and select +**PowerShell: Enable ISE Mode**. -## Next Steps +## Next steps -Armed with the knowledge to effectively migrate, [install PowerShell 7][02] now! +- [Audit scripts for PowerShell 7 compatibility][script-audit] +- [Module compatibility strategy for PowerShell 7][module-strategy] +- [Encoding changes in PowerShell 7][encoding-changes] +- [Migrate PowerShell profiles][profile-migration] +- [Deploy PowerShell 7 in enterprise environments][enterprise] +- [Migrate scheduled tasks and automation][scheduled-tasks] +- [Test and validate your migration][testing-rollback] +- [Differences between Windows PowerShell 5.1 and PowerShell 7.x][differences] -[01]: ../dev-cross-plat/vscode/how-to-replicate-the-ise-experience-in-vscode.md -[02]: ../install/installing-powershell-on-windows.md -[03]: ../install/installing-powershell-on-windows.md#msi -[04]: ../install/installing-powershell-on-windows.md#winget -[05]: ../install/installing-powershell-on-windows.md#zip -[06]: ../install/powershell-support-lifecycle.md -[07]: ../security/remoting/ssh-remoting-in-powershell.md -[08]: ../security/remoting/wsman-remoting-in-powershell.md -[09]: ../whats-new/What-s-New-in-PowerShell-70.md -[10]: ./differences-from-windows-powershell.md -[11]: ./module-compatibility.md -[12]: /configmgr/apps/ -[13]: /powershell/module/microsoft.powershell.core/about/about_group_policy_settings -[14]: /powershell/module/microsoft.powershell.core/about/about_logging_windows -[15]: /powershell/module/Microsoft.PowerShell.Core/About/about_Modules -[16]: /powershell/module/microsoft.powershell.core/about/about_profiles -[17]: /powershell/module/microsoft.powershell.core/about/about_psmodulepath -[18]: /powershell/module/microsoft.powershell.core/about/about_remote -[19]: /powershell/module/microsoft.powershell.core/about/about_remote_requirements -[20]: /powershell/module/Microsoft.PowerShell.Core/About/about_windows_powershell_compatibility -[21]: /windows-server/administration/openssh/openssh_keymanagement -[22]: https://code.visualstudio.com/ -[23]: https://code.visualstudio.com/docs/languages/powershell -[24]: https://github.com/PowerShell/PowerShell/releases -[25]: https://www.powershellgallery.com/packages/Microsoft.PowerShell.RemotingTools +[about-compat]: /powershell/module/Microsoft.PowerShell.Core/About/about_windows_powershell_compatibility +[about-gpo]: /powershell/module/microsoft.powershell.core/about/about_group_policy_settings +[about-logging]: /powershell/module/microsoft.powershell.core/about/about_logging_windows +[about-psmodulepath]: /powershell/module/microsoft.powershell.core/about/about_psmodulepath +[about-remote-req]: /powershell/module/microsoft.powershell.core/about/about_remote_requirements +[differences]: ./differences-from-windows-powershell.md +[encoding-changes]: ./migration/encoding-changes.md +[enterprise]: ./migration/enterprise-deployment.md +[gh-releases]: https://github.com/PowerShell/PowerShell/releases +[install-msi]: ../install/installing-powershell-on-windows.md#msi +[install-store]: ../install/installing-powershell-on-windows.md#msix +[install-winget]: ../install/installing-powershell-on-windows.md#winget +[install-zip]: ../install/installing-powershell-on-windows.md#zip +[lifecycle]: ../install/powershell-support-lifecycle.md +[module-strategy]: ./migration/module-compatibility-strategy.md +[profile-migration]: ./migration/profile-migration.md +[ps-ext]: https://code.visualstudio.com/docs/languages/powershell +[remoting-tools]: https://www.powershellgallery.com/packages/Microsoft.PowerShell.RemotingTools +[sccm]: /configmgr/apps/ +[scheduled-tasks]: ./migration/scheduled-tasks-automation.md +[script-audit]: ./migration/script-compatibility-audit.md +[ssh-remoting]: ../security/remoting/ssh-remoting-in-powershell.md +[testing-rollback]: ./migration/testing-and-rollback.md +[vscode]: https://code.visualstudio.com/ +[wsman-remoting]: ../security/remoting/wsman-remoting-in-powershell.md diff --git a/reference/docs-conceptual/whats-new/differences-from-windows-powershell.md b/reference/docs-conceptual/whats-new/differences-from-windows-powershell.md index 6355e8e42a3..f53252beea8 100644 --- a/reference/docs-conceptual/whats-new/differences-from-windows-powershell.md +++ b/reference/docs-conceptual/whats-new/differences-from-windows-powershell.md @@ -5,6 +5,11 @@ description: This article summarizes the differences and breaking changes from W --- # Differences between Windows PowerShell 5.1 and PowerShell 7.x +> [!TIP] +> This article is a technical reference of all differences between editions. +> For a step-by-step migration guide, see +> [Migrating from Windows PowerShell 5.1 to PowerShell 7][migration-guide]. + Windows PowerShell 5.1 is built on top of the .NET Framework v4.5. With the release of PowerShell 6.0, PowerShell became an open source project built on .NET Core 2.0. Moving from the .NET Framework 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 [34]: What-s-New-in-PowerShell-73.md [35]: What-s-New-in-PowerShell-74.md [36]: What-s-New-in-PowerShell-75.md +[migration-guide]: ./Migrating-from-Windows-PowerShell-51-to-PowerShell-7.md diff --git a/reference/docs-conceptual/whats-new/migration/encoding-changes.md b/reference/docs-conceptual/whats-new/migration/encoding-changes.md new file mode 100644 index 00000000000..96377a3cd48 --- /dev/null +++ b/reference/docs-conceptual/whats-new/migration/encoding-changes.md @@ -0,0 +1,260 @@ +--- +description: >- + Understand how default encoding changed from Windows PowerShell 5.1 to + PowerShell 7 and choose a migration strategy for your scripts. +ms.date: 04/15/2026 +title: Encoding changes in PowerShell 7 +--- + +# Encoding changes in PowerShell 7 + +PowerShell 7 changed the default encoding for file output from +locale-dependent encodings (such as Windows-1252) and UTF-16LE to UTF-8 +without a byte order mark (BOM). This change aligns with modern tooling and +cross-platform expectations, but it can break scripts that depend on specific +encodings. + +## What changed + +### Default encoding comparison + +The following table shows the default encoding for common cmdlets and +features in each edition: + +| Cmdlet or feature | Windows PowerShell 5.1 | PowerShell 7 | +| ----------------- | ---------------------- | ------------ | +| `Out-File` / `>` operator | UTF-16LE with BOM | UTF-8 without BOM | +| `Set-Content` | System locale (often Windows-1252) | UTF-8 without BOM | +| `Add-Content` | System locale | UTF-8 without BOM | +| `Export-Csv` | ASCII | UTF-8 without BOM | +| `Export-Clixml` | UTF-8 with BOM | UTF-8 without BOM | +| `New-ModuleManifest` | UTF-16LE with BOM | UTF-8 without BOM | +| `Start-Transcript` | UTF-8 with BOM | UTF-8 without BOM | +| `$OutputEncoding` (pipe to native) | ASCII | UTF-8 without BOM | + +### The -Encoding parameter + +In Windows PowerShell 5.1, the `-Encoding` parameter accepted string values +such as `UTF8`, which produced UTF-8 _with_ BOM. In PowerShell 7, the +parameter accepts `System.Text.Encoding` objects and string values with +updated meanings: + +| Value | PowerShell 7 behavior | +| ----- | --------------------- | +| `utf8` | UTF-8 without BOM | +| `utf8BOM` | UTF-8 with BOM | +| `utf8NoBOM` | UTF-8 without BOM (same as `utf8`) | +| `utf16` or `unicode` | UTF-16LE with BOM | +| `utf16BE` or `bigendianunicode` | UTF-16BE with BOM | +| `ascii` | ASCII (7-bit) | +| `oem` | OEM code page | +| `ansi` | ANSI code page | + +### Removed: -Encoding Byte + +The `Byte` encoding value was removed in PowerShell 7. Use the +`-AsByteStream` parameter instead: + +**Before (Windows PowerShell 5.1)**: + +```powershell +Get-Content -Path file.bin -Encoding Byte +``` + +**After (PowerShell 7)**: + +```powershell +Get-Content -Path file.bin -AsByteStream +``` + +## Impact assessment + +### Scripts that generate files for other tools + +If your scripts use `Out-File`, `Set-Content`, `Export-Csv`, or the `>` +operator to create files that are consumed by other tools, check whether +those tools expect a specific encoding. + +Common scenarios that break: + +- **SIEM or log analysis tools** that detect file type by BOM. UTF-16LE + files have a `0xFF 0xFE` BOM; PowerShell 7's UTF-8 files have no BOM. +- **Legacy Windows tools** that expect the system locale encoding + (such as Windows-1252 for Western European systems). +- **Signed scripts** where the encoding affects the digital signature. + Re-sign scripts after changing encoding. + +### Scripts that read files from Windows PowerShell + +If your PowerShell 7 scripts read files that were created by Windows +PowerShell 5.1, encoding detection generally works correctly. PowerShell 7 +detects the BOM in UTF-16LE files and reads them without issues. Files +without a BOM are read as UTF-8. + +### Pipe-to-native-command changes + +The `$OutputEncoding` variable controls the encoding when PowerShell pipes +text to native commands. It changed from ASCII to UTF-8: + +- **ASCII** (Windows PowerShell 5.1): Characters outside the 7-bit ASCII + range were replaced with `?`. +- **UTF-8** (PowerShell 7): Extended characters are preserved but may + appear garbled if the native command doesn't support UTF-8. + +If you pipe output to legacy tools like `cmd.exe /c findstr` and see +garbled characters, set `$OutputEncoding` to ASCII in your session or +profile: + +```powershell +$OutputEncoding = [System.Text.Encoding]::ASCII +``` + +## Migration strategies + +### Strategy 1: Embrace UTF-8 + +UTF-8 is the dominant encoding for modern tools, web APIs, cross-platform +scripts, and version-controlled files. If possible, update all consumers to +expect UTF-8 without BOM. + +To re-encode existing files in bulk: + +```powershell +Get-ChildItem -Path .\output -Filter *.csv -Recurse | ForEach-Object { + $content = Get-Content -Path $_.FullName -Raw + [System.IO.File]::WriteAllText( + $_.FullName, + $content, + [System.Text.UTF8Encoding]::new($false) + ) +} +``` + +### Strategy 2: Force legacy encoding in PowerShell 7 + +If you can't update consuming tools, force the old encoding defaults in your +PowerShell 7 profile using `$PSDefaultParameterValues`: + +```powershell +# Restore Windows PowerShell 5.1 encoding behavior +$PSDefaultParameterValues['Out-File:Encoding'] = 'utf8BOM' +$PSDefaultParameterValues['Set-Content:Encoding'] = 'utf8BOM' +$PSDefaultParameterValues['Add-Content:Encoding'] = 'utf8BOM' +$PSDefaultParameterValues['Export-Csv:Encoding'] = 'utf8BOM' +$PSDefaultParameterValues['Export-Clixml:Encoding'] = 'utf8BOM' +``` + +> [!IMPORTANT] +> Setting `$PSDefaultParameterValues` in a profile affects all scripts in +> that session. For targeted control, set the encoding per-script instead. + +### Strategy 3: Explicit encoding per script + +For scripts that must work in both Windows PowerShell 5.1 and PowerShell 7, +always specify the `-Encoding` parameter explicitly: + +```powershell +$data | Export-Csv -Path report.csv -Encoding UTF8 -NoTypeInformation +``` + +> [!NOTE] +> The value `UTF8` produces UTF-8 _with_ BOM in Windows PowerShell 5.1 and +> UTF-8 _without_ BOM in PowerShell 7. If you need identical output in both +> editions, use `[System.Text.UTF8Encoding]::new($true)` (with BOM) or +> `[System.Text.UTF8Encoding]::new($false)` (without BOM) as the +> `-Encoding` value. + +## BOM considerations + +### When BOMs are required + +- XML files consumed by tools that require a BOM to detect encoding +- Signed PowerShell scripts (re-encode and re-sign after migration) +- Interop with older Java versions that expect a UTF-8 BOM +- Files read by applications that default to the system locale without BOM + detection + +### When BOMs cause problems + +- Unix and Linux tools (many treat the BOM as visible characters) +- Git diff output (BOM appears as invisible changes at the start of files) +- JSON parsers (the JSON specification prohibits BOMs) +- Shell scripts on non-Windows platforms + +### PowerShell 7 reads BOMs correctly + +Regardless of the default output encoding, PowerShell 7 detects and +respects BOMs when _reading_ files. A file created with UTF-16LE BOM by +Windows PowerShell 5.1 is read correctly by PowerShell 7. + +## Verify encoding in your environment + +Use the following function to check the encoding of a file by inspecting +its first few bytes: + +```powershell +function Get-FileEncoding { + param( + [Parameter(Mandatory)] + [string]$Path + ) + + $bytes = [byte[]]( + Get-Content -Path $Path -AsByteStream -TotalCount 4 + ) + + if ($bytes.Length -ge 3 -and + $bytes[0] -eq 0xEF -and + $bytes[1] -eq 0xBB -and + $bytes[2] -eq 0xBF) { + 'UTF-8 with BOM' + } + elseif ($bytes.Length -ge 2 -and + $bytes[0] -eq 0xFF -and + $bytes[1] -eq 0xFE) { + 'UTF-16 LE (BOM)' + } + elseif ($bytes.Length -ge 2 -and + $bytes[0] -eq 0xFE -and + $bytes[1] -eq 0xFF) { + 'UTF-16 BE (BOM)' + } + else { + 'No BOM (UTF-8 or ASCII)' + } +} +``` + +Scan a directory of output files: + +```powershell +Get-ChildItem -Path .\output -File | ForEach-Object { + [PSCustomObject]@{ + File = $_.Name + Encoding = Get-FileEncoding -Path $_.FullName + } +} +``` + +## Quick reference + +| I need to... | Use this | +| ------------ | -------- | +| Write UTF-8 without BOM (PS 7 default) | `Out-File -Path file.txt` | +| Write UTF-8 with BOM (match WinPS default) | `Out-File -Path file.txt -Encoding utf8BOM` | +| Write UTF-16LE with BOM (match WinPS `>`) | `Out-File -Path file.txt -Encoding unicode` | +| Read binary data | `Get-Content -Path file.bin -AsByteStream` | +| Force ASCII for native pipe | `$OutputEncoding = [System.Text.Encoding]::ASCII` | + +## Next steps + +- [Migrate PowerShell profiles][profile-migration] +- [Audit scripts for PowerShell 7 compatibility][script-audit] +- [Migrating from Windows PowerShell 5.1 to PowerShell 7][migration-guide] +- [Differences between Windows PowerShell 5.1 and PowerShell 7.x][differences] + + +[differences]: ../differences-from-windows-powershell.md +[migration-guide]: ../Migrating-from-Windows-PowerShell-51-to-PowerShell-7.md +[profile-migration]: ./profile-migration.md +[script-audit]: ./script-compatibility-audit.md diff --git a/reference/docs-conceptual/whats-new/migration/enterprise-deployment.md b/reference/docs-conceptual/whats-new/migration/enterprise-deployment.md new file mode 100644 index 00000000000..5b108ba0663 --- /dev/null +++ b/reference/docs-conceptual/whats-new/migration/enterprise-deployment.md @@ -0,0 +1,264 @@ +--- +description: >- + Deploy PowerShell 7 across enterprise environments using MSI, SCCM, Intune, + winget, and Group Policy, including air-gapped network considerations. +ms.date: 04/15/2026 +title: Deploy PowerShell 7 in enterprise environments +--- + +# Deploy PowerShell 7 in enterprise environments + +This article covers deployment methods, network considerations, Group Policy +configuration, and coexistence planning for organizations migrating from +Windows PowerShell 5.1 to PowerShell 7. + +## Deployment methods + +### MSI package + +The MSI package is the recommended method for enterprise deployment. It +supports silent installation, Group Policy Software Installation, Microsoft +Configuration Manager (SCCM), and Microsoft Intune. + +```powershell +msiexec.exe /i PowerShell-7.5.4-win-x64.msi /quiet /norestart ` + ADD_EXPLORER_CONTEXT_MENU_OPENPOWERSHELL=1 ` + ADD_FILE_CONTEXT_MENU_RUNPOWERSHELL=1 ` + ENABLE_PSREMOTING=1 ` + REGISTER_MANIFEST=1 ` + USE_MU=1 ` + ENABLE_MU=1 ` + ADD_PATH=1 +``` + +Key MSI properties: + +| Property | Effect | +| -------- | ------ | +| `ENABLE_PSREMOTING=1` | Enable WinRM remoting during install | +| `REGISTER_MANIFEST=1` | Register Windows Event Logging manifest | +| `USE_MU=1` | Enable checking for updates via Microsoft Update | +| `ENABLE_MU=1` | Opt in to Microsoft Update | +| `ADD_PATH=1` | Add PowerShell 7 to the system `PATH` | + +> [!NOTE] +> Download MSI packages from the +> [PowerShell GitHub Releases page][gh-releases]. Choose the `-win-x64.msi` +> package for 64-bit Windows or `-win-x86.msi` for 32-bit environments. + +### Microsoft Configuration Manager (SCCM) + +Deploy the MSI as an application in SCCM: + +1. Create a new application with the MSI as the deployment type +1. Set the install command to the silent install string shown above +1. Create a detection rule for `$Env:ProgramFiles\PowerShell\7\pwsh.exe` +1. Deploy to the target device collection + +### Microsoft Intune + +For Intune-managed devices: + +1. Upload the MSI as a **Line-of-business app** in the Intune portal +1. Set command-line arguments for silent install +1. Configure the detection rule to check for `pwsh.exe` in the install + directory +1. Assign the app to device groups + +### winget + +For developer workstations and environments where winget is available: + +```powershell +winget install --id Microsoft.PowerShell --source winget --silent +``` + +> [!NOTE] +> winget is available on Windows 10 1809 and later, Windows 11, and Windows +> Server 2025 (Desktop Experience). For Server Core or earlier Windows Server +> versions, use the MSI package. + +### ZIP package + +The ZIP package doesn't require administrator privileges and is useful for: + +- Testing before committing to a full installation +- Environments where MSI deployment is restricted +- Running multiple PowerShell 7 versions side by side +- Nano Server and IoT deployments + +Extract the ZIP to a directory and add it to `PATH` manually or run +`pwsh.exe` from the extracted location. + +## Network considerations + +### Air-gapped and restricted networks + +PowerShell 7 makes network calls during startup for update checks and +certificate revocation list (CRL) validation. On air-gapped or restricted +networks, these calls time out and can delay startup by 6 to 10 seconds. + +To resolve startup delays on isolated networks: + +1. **Disable update notifications** by setting an environment variable: + + ```powershell + [Environment]::SetEnvironmentVariable( + 'POWERSHELL_UPDATECHECK', 'Off', 'Machine' + ) + ``` + +1. **Disable telemetry** if not needed: + + ```powershell + [Environment]::SetEnvironmentVariable( + 'POWERSHELL_TELEMETRY_OPTOUT', '1', 'Machine' + ) + ``` + +1. **Configure CRL caching** to avoid repeated timeout delays. If your + environment blocks `ctldl.windowsupdate.com`, configure a local CRL + distribution point or disable CRL checking for the PowerShell certificate + chain through Group Policy. + +For more background on this issue, see +[PowerShell/PowerShell#10983][issue-10983]. + +### Proxy configuration + +If your network requires a proxy for internet access, configure the proxy +for PowerShell module management: + +```powershell +[System.Net.WebRequest]::DefaultWebProxy = New-Object ` + System.Net.WebProxy('http://proxy.corp:8080') +[System.Net.WebRequest]::DefaultWebProxy.Credentials = ` + [System.Net.CredentialCache]::DefaultCredentials +``` + +For persistent configuration, add the proxy settings to the AllUsers profile +or set the `HTTP_PROXY` and `HTTPS_PROXY` environment variables. + +### Microsoft Update integration + +PowerShell 7.2 and later supports updates through Microsoft Update and +Windows Server Update Services (WSUS). Enable this during install with the +`USE_MU=1` and `ENABLE_MU=1` MSI properties, or configure it after +installation through Windows Update settings. + +## Group Policy configuration + +PowerShell 7 ships its own Group Policy templates, separate from Windows +PowerShell 5.1. If you use Group Policy to manage PowerShell settings, you +must configure policies for both editions during the migration period. + +### Install policy templates + +PowerShell 7 includes `.admx` and `.adml` files in `$PSHOME`. Copy them to +the Group Policy central store or install locally: + +```powershell +& "$PSHOME\InstallPSCorePolicyDefinitions.ps1" +``` + +### Supported policy settings + +| Setting | Description | +| ------- | ----------- | +| Console session configuration | Set the configuration endpoint for PowerShell sessions | +| Module Logging | Log pipeline execution details for specified modules | +| Script Block Logging | Log the content of all script blocks that are processed | +| Script Execution | Set the execution policy | +| Transcription | Capture input and output to text-based transcripts | +| Default source path for `Update-Help` | Redirect help updates to a local share | + +> [!IMPORTANT] +> Group Policy settings for PowerShell 7 are stored in a different registry +> path than Windows PowerShell 5.1. Existing GPOs for Windows PowerShell +> don't apply to PowerShell 7 automatically. You must create separate GPOs +> or duplicate settings in both policy templates. + +For more information, see [about_Group_Policy_Settings][about-gpo]. + +## Coexistence planning + +### Timeline + +Plan for a parallel-run period where both editions handle production +workloads. A typical migration timeline: + +1. **Weeks 1-2**: Install PowerShell 7, test scripts and modules +1. **Weeks 3-4**: Migrate non-critical automation (dev/test environments) +1. **Weeks 5-8**: Migrate production automation with monitoring +1. **Ongoing**: Maintain both editions until all workloads are validated + +### Default shell selection + +PowerShell 7 can be set as the default shell in several contexts: + +- **Windows Terminal**: Set the default profile to PowerShell 7 in + Terminal settings +- **OpenSSH**: Set `pwsh.exe` as the default shell for SSH connections: + + ```powershell + New-ItemProperty -Path 'HKLM:\SOFTWARE\OpenSSH' ` + -Name DefaultShell ` + -Value "$Env:ProgramFiles\PowerShell\7\pwsh.exe" ` + -PropertyType String -Force + ``` + +- **WinRM remoting**: Run `Enable-PSRemoting` in PowerShell 7 to register + the `PowerShell.7` endpoint. Remote sessions still default to the Windows + PowerShell endpoint unless the caller specifies + `-ConfigurationName PowerShell.7`. + +### PATH order + +When both editions are installed, the system `PATH` determines which +`powershell.exe` or `pwsh.exe` is found first. The MSI installer adds +PowerShell 7 to `PATH` automatically. Verify the order: + +```powershell +$Env:PATH -split ';' | Where-Object { $_ -match 'PowerShell' } +``` + +## CI/CD pipeline updates + +Update your CI/CD pipelines to use PowerShell 7: + +### Azure DevOps + +In Azure Pipelines, use the `pwsh` task instead of `powershell`: + +```yaml +- pwsh: | + Write-Host "Running in PowerShell 7" + displayName: 'Run PowerShell 7 script' +``` + +### GitHub Actions + +GitHub-hosted runners include PowerShell 7. Specify the shell: + +```yaml +- name: Run script + shell: pwsh + run: | + Write-Host "Running in PowerShell 7" +``` + +## Next steps + +- [Migrating from Windows PowerShell 5.1 to PowerShell 7][migration-guide] +- [Migrate scheduled tasks and automation][scheduled-tasks] +- [Test and validate your PowerShell 7 migration][testing-rollback] +- [Installing PowerShell on Windows][install-windows] + + +[about-gpo]: /powershell/module/microsoft.powershell.core/about/about_group_policy_settings +[gh-releases]: https://github.com/PowerShell/PowerShell/releases +[install-windows]: ../../install/installing-powershell-on-windows.md +[issue-10983]: https://github.com/PowerShell/PowerShell/issues/10983 +[migration-guide]: ../Migrating-from-Windows-PowerShell-51-to-PowerShell-7.md +[scheduled-tasks]: ./scheduled-tasks-automation.md +[testing-rollback]: ./testing-and-rollback.md diff --git a/reference/docs-conceptual/whats-new/migration/module-compatibility-strategy.md b/reference/docs-conceptual/whats-new/migration/module-compatibility-strategy.md new file mode 100644 index 00000000000..6cfc1ed778f --- /dev/null +++ b/reference/docs-conceptual/whats-new/migration/module-compatibility-strategy.md @@ -0,0 +1,279 @@ +--- +description: >- + Strategies for testing and resolving module compatibility issues when + migrating from Windows PowerShell 5.1 to PowerShell 7. +ms.date: 04/15/2026 +title: Module compatibility strategy for PowerShell 7 +--- + +# Module compatibility strategy for PowerShell 7 + +Most Windows PowerShell 5.1 modules work in PowerShell 7 due to .NET +Standard 2.0 compatibility and the Windows PowerShell compatibility +layer. This article helps you test your module inventory, resolve +compatibility issues, and choose the right strategy for each module. + +## How module loading works across editions + +PowerShell 7 includes the Windows PowerShell module paths in +`$Env:PSModulePath`, so modules installed for Windows PowerShell 5.1 are +visible in PowerShell 7 sessions. + +How PowerShell 7 decides whether to load a module: + +- **Script modules** (`.psm1`): Load if they don't use removed cmdlets, + snap-ins, or .NET Framework-only types. +- **Binary modules** (`.dll`): Load if they target .NET Standard 2.0, + .NET Core, or .NET 5+. Modules targeting .NET Framework 4.x may fail + with type-load exceptions. +- **CompatiblePSEditions** in the module manifest: If the manifest + declares `CompatiblePSEditions = @('Desktop')` only, PowerShell 7 skips + the module during auto-loading. You can still force-load it with + `Import-Module -SkipEditionCheck` or use the compatibility layer. +- **Missing CompatiblePSEditions**: PowerShell 7 assumes compatibility + and attempts to load the module. + +For more information, see [about_PSModulePath][about-psmodulepath]. + +## Test your module inventory + +Run the following script in PowerShell 7 to test which of your installed +modules load successfully: + +```powershell +$results = Get-Module -ListAvailable | + Sort-Object Name -Unique | + ForEach-Object { + $status = 'Compatible' + $errorMsg = '' + try { + Import-Module $_.Name -ErrorAction Stop -Force + } + catch { + $status = 'Incompatible' + $errorMsg = $_.Exception.Message + } + [PSCustomObject]@{ + Name = $_.Name + Version = $_.Version + Status = $status + Error = $errorMsg + } + } + +$results | Sort-Object Status, Name | + Format-Table Name, Version, Status -AutoSize +``` + +Review the `Incompatible` entries and decide on a strategy for each one. + +## The Windows PowerShell compatibility layer + +### How it works + +The `Import-Module -UseWindowsPowerShell` switch (available in +PowerShell 7 on Windows) creates a hidden WinRM loopback session to +Windows PowerShell 5.1 and generates proxy functions for the module's +exported commands. When you call a proxy function, the command runs in +the Windows PowerShell session and the results are serialized back to +your PowerShell 7 session. + +```powershell +Import-Module ActiveDirectory -UseWindowsPowerShell +Get-ADUser -Filter * -ResultSetSize 10 +``` + +For more information, see +[about_Windows_PowerShell_Compatibility][about-compat]. + +### When to use it + +Use the compatibility layer when: + +- The module has no PowerShell 7-native equivalent +- The module loads .NET Framework-only assemblies +- The module uses WMI provider interfaces (such as the DISM module) +- You need a temporary bridge while planning a full migration + +### Known limitations + +The compatibility layer has several known issues that affect long-running +sessions and specific scenarios: + +- **Performance overhead**: Every command call goes through WinRM + serialization and deserialization, which is slower than a native call. +- **Object fidelity loss**: Objects cross a remoting boundary. Rich .NET + objects become deserialized `PSObject` instances with limited methods + and no live .NET type information. +- **Memory accumulation**: In long-running sessions, the hidden session + accumulates memory that isn't freed on `Remove-Module`. For details, + see [PowerShell/PowerShell#21097][issue-21097]. +- **Temp file accumulation**: The proxy generates `remoteIpMoProxy_*` + files in `$Env:TEMP`. In scheduled tasks or long-running services, + these files can grow to millions. For details, see + [PowerShell/PowerShell#13198][issue-13198]. +- **Bracket characters in paths**: After loading a compatibility module, + `Set-Content -LiteralPath` with `[` or `]` characters may fail. For + details, see [PowerShell/PowerShell#24541][issue-24541]. +- **WinRM must be enabled**: The compatibility layer uses a local WinRM + loopback session. Run `Enable-PSRemoting` if WinRM isn't already + configured. + +### Clean up temp files + +If you use the compatibility layer in scheduled tasks or services, clean +up proxy files periodically: + +```powershell +Get-ChildItem -Path $Env:TEMP -Filter 'remoteIpMoProxy_*' | + Where-Object { + $_.LastWriteTime -lt (Get-Date).AddDays(-1) + } | + Remove-Item -Force +``` + +## PSModulePath conflicts + +### OneDrive document redirection + +On Windows 10 and 11, the Documents folder is often redirected to +OneDrive. This means your user module path +(`$HOME\Documents\PowerShell\Modules`) is synced to the cloud. Large +module folders (Az PowerShell: 53 MB+, AWS Tools: 81 MB+) consume +OneDrive storage quota and sync bandwidth. + +For more background, see +[PowerShell/PowerShell#15552][issue-15552]. + +**Workaround:** Redirect the user module path to local storage in your +PowerShell 7 profile: + +```powershell +$localModules = "$Env:LOCALAPPDATA\PowerShell\Modules" +if (-not (Test-Path $localModules)) { + New-Item -Path $localModules -ItemType Directory -Force +} +$Env:PSModulePath = $localModules + ';' + $Env:PSModulePath +``` + +### Corporate folder redirection + +Group Policy-based folder redirection to a network share causes the same +issue, with the additional risk of slow module loading over the network. +Use the same workaround pattern to redirect the user module path to a +local directory. + +## Strategies by module type + +### Microsoft-published modules + +The following Microsoft modules have native PowerShell 7 support: + +| Module | Minimum PowerShell version | +| ------ | ------------------------- | +| Az (Azure PowerShell) | 7.0.6 LTS | +| Microsoft.Graph | 7.0 | +| ExchangeOnlineManagement (V3) | 7.0.3 | +| SqlServer | 5.0 (works in both editions) | + +For the full list, see [PowerShell 7 module compatibility][module-compat]. + +### Windows management modules + +Windows ships management modules for system features. Their PowerShell 7 +compatibility varies: + +| Module | PowerShell 7 status | +| ------ | ------------------- | +| ActiveDirectory | Works natively (RSAT required) | +| GroupPolicy | Partial (some cmdlets fail); use compatibility layer | +| DISM | Fails natively ("Class not registered"); use compatibility layer | +| ScheduledTasks | Works natively | +| Hyper-V | Works natively | +| NetAdapter | Works natively | +| Storage | Works natively | +| Defender | Works natively | + +> [!NOTE] +> The DISM module is the most common compatibility issue. The +> `Get-WindowsCapability` and `Get-WindowsOptionalFeature` cmdlets +> require .NET Framework COM interop that isn't available in .NET Core. +> Use `Import-Module DISM -UseWindowsPowerShell` or run these cmdlets +> in Windows PowerShell 5.1 directly. + +### Third-party and custom modules + +For modules not listed above: + +1. **Try importing** the module in PowerShell 7 and test its commands. +1. **Check the module manifest** for `CompatiblePSEditions`. If it lists + only `Desktop`, the module was designed for Windows PowerShell. +1. **Check binary module targets**: If the module includes a `.dll`, use + `[Reflection.AssemblyName]::GetAssemblyName($dllPath)` to check the + target framework. Assemblies targeting `.NETFramework` may not load. +1. **Use the compatibility layer** as a fallback. +1. **Contact the module author** or check for a newer version that + supports PowerShell 7. + +## Create cross-edition modules + +If you maintain your own modules and need them to work in both Windows +PowerShell 5.1 and PowerShell 7: + +### Set CompatiblePSEditions + +Declare both editions in the module manifest: + +```powershell +@{ + RootModule = 'MyModule.psm1' + ModuleVersion = '1.0.0' + CompatiblePSEditions = @('Desktop', 'Core') + PowerShellVersion = '5.1' +} +``` + +### Target .NET Standard 2.0 for binary modules + +If the module includes compiled C# code, target .NET Standard 2.0 +in the project file: + +```xml +netstandard2.0 +``` + +.NET Standard 2.0 assemblies load in both .NET Framework 4.6.1+ and +.NET Core 2.0+. + +### Use conditional logic for edition differences + +Use the `$PSEdition` automatic variable to handle edition-specific logic +in script modules: + +```powershell +if ($PSEdition -eq 'Core') { + # PowerShell 7 code path +} +else { + # Windows PowerShell 5.1 code path +} +``` + +## Next steps + +- [Audit scripts for PowerShell 7 compatibility][script-audit] +- [Encoding changes in PowerShell 7][encoding-changes] +- [PowerShell 7 module compatibility][module-compat] +- [Migrating from Windows PowerShell 5.1 to PowerShell 7][migration-guide] + + +[about-compat]: /powershell/module/Microsoft.PowerShell.Core/About/about_windows_powershell_compatibility +[about-psmodulepath]: /powershell/module/microsoft.powershell.core/about/about_psmodulepath +[encoding-changes]: ./encoding-changes.md +[issue-13198]: https://github.com/PowerShell/PowerShell/issues/13198 +[issue-15552]: https://github.com/PowerShell/PowerShell/issues/15552 +[issue-21097]: https://github.com/PowerShell/PowerShell/issues/21097 +[issue-24541]: https://github.com/PowerShell/PowerShell/issues/24541 +[migration-guide]: ../Migrating-from-Windows-PowerShell-51-to-PowerShell-7.md +[module-compat]: ../module-compatibility.md +[script-audit]: ./script-compatibility-audit.md diff --git a/reference/docs-conceptual/whats-new/migration/profile-migration.md b/reference/docs-conceptual/whats-new/migration/profile-migration.md new file mode 100644 index 00000000000..edf3f98ac43 --- /dev/null +++ b/reference/docs-conceptual/whats-new/migration/profile-migration.md @@ -0,0 +1,243 @@ +--- +description: >- + How to migrate PowerShell profiles from Windows PowerShell 5.1 to + PowerShell 7, including shared profile strategies and common pitfalls. +ms.date: 04/15/2026 +title: Migrate PowerShell profiles from Windows PowerShell 5.1 to PowerShell 7 +--- + +# Migrate PowerShell profiles from Windows PowerShell 5.1 to PowerShell 7 + +A PowerShell profile is a script that runs when a session starts. It sets up +your environment with aliases, functions, variables, and module imports. +Windows PowerShell 5.1 and PowerShell 7 use different profile paths, so your +existing profile doesn't carry over automatically. + +This article explains the path differences and describes three strategies for +sharing or migrating your profile content. + +## Profile path differences + +Each PowerShell edition maintains separate profile files. The `$PROFILE` +automatic variable points to the **CurrentUser, CurrentHost** profile for the +running edition. + +| Scope | Windows PowerShell 5.1 | PowerShell 7 | +| ----- | ---------------------- | ------------ | +| CurrentUser, CurrentHost | `$HOME\Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1` | `$HOME\Documents\PowerShell\Microsoft.PowerShell_profile.ps1` | +| CurrentUser, AllHosts | `$HOME\Documents\WindowsPowerShell\profile.ps1` | `$HOME\Documents\PowerShell\profile.ps1` | +| AllUsers, CurrentHost | `$PSHOME\Microsoft.PowerShell_profile.ps1` | `$Env:ProgramFiles\PowerShell\7\Microsoft.PowerShell_profile.ps1` | +| AllUsers, AllHosts | `$PSHOME\profile.ps1` | `$Env:ProgramFiles\PowerShell\7\profile.ps1` | + +To see all profile paths for the current session: + +```powershell +$PROFILE | Select-Object *Host* | Format-List +``` + +> [!NOTE] +> PowerShell 7 doesn't create the profile directory or file by default. You +> may need to create the directory before saving a profile: +> +> ```powershell +> New-Item -Path (Split-Path $PROFILE) -ItemType Directory -Force +> New-Item -Path $PROFILE -ItemType File -Force +> ``` + +## Option 1: Shared profile with edition detection + +Create a single profile file and dot-source it from both Windows PowerShell +and PowerShell 7 profiles. Use the `$PSEdition` automatic variable to run +edition-specific code conditionally. + +1. Create a shared profile at a location both editions can reach: + + ```powershell + $sharedProfile = "$HOME\.powershell\shared-profile.ps1" + New-Item -Path (Split-Path $sharedProfile) -ItemType Directory -Force + ``` + +1. Add your common configuration to the shared profile. Use `$PSEdition` to + guard edition-specific code: + + ```powershell + # Common configuration + Set-PSReadLineOption -PredictionSource History + + if ($PSEdition -eq 'Core') { + # PowerShell 7 only + Set-PSReadLineOption -PredictionViewStyle ListView + } + + if ($PSEdition -eq 'Desktop') { + # Windows PowerShell 5.1 only + Import-Module PSReadLine + } + ``` + +1. Dot-source the shared profile from each edition's profile. Add this line + to both `$PROFILE` paths: + + ```powershell + . "$HOME\.powershell\shared-profile.ps1" + ``` + +This approach keeps all profile logic in one place while allowing +edition-specific behavior. + +## Option 2: Separate profiles with a shared module + +Instead of sharing a profile script, put shared functions and aliases into +a PowerShell module that both editions can import. + +1. Create a module directory in a path shared by both editions: + + ```powershell + $modulePath = "$HOME\Documents\PowerShell\Modules\MyProfile" + New-Item -Path $modulePath -ItemType Directory -Force + ``` + +1. Create `MyProfile.psm1` with your shared functions: + + ```powershell + function prompt { + "$($executionContext.SessionState.Path.CurrentLocation)> " + } + + Set-Alias -Name ll -Value Get-ChildItem + ``` + +1. Import the module from each edition's profile: + + ```powershell + Import-Module MyProfile + ``` + +> [!NOTE] +> PowerShell 7 includes the Windows PowerShell module paths in +> `$Env:PSModulePath`, so a module installed in the PowerShell 7 user path +> is reachable from both editions. However, if the module uses features +> specific to one edition, set `CompatiblePSEditions` in the module manifest. + +## Option 3: Symbolic links + +Create a symbolic link from the PowerShell 7 profile path to the Windows +PowerShell profile so both editions read the same file. This requires +administrator privileges. + +```powershell +$source = "$HOME\Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1" +$target = "$HOME\Documents\PowerShell\Microsoft.PowerShell_profile.ps1" + +New-Item -Path (Split-Path $target) -ItemType Directory -Force +New-Item -ItemType SymbolicLink -Path $target -Target $source +``` + +> [!IMPORTANT] +> Symbolic links share the exact same file. If your profile contains code +> that only works in one edition (such as ISE-specific commands or snap-in +> loading), you must add `$PSEdition` guards or the profile will produce +> errors in the other edition. + +## Common profile migration issues + +### ISE-specific code + +If your Windows PowerShell profile references `$psISE`, `$Host.Name` checks +for `Windows PowerShell ISE Host`, or ISE add-ons, those references fail in +PowerShell 7. Guard ISE-specific code: + +```powershell +if ($Host.Name -eq 'Windows PowerShell ISE Host') { + # ISE-only customization + $psISE.Options.FontSize = 14 +} +``` + +### Snap-in loading + +PowerShell snap-ins (`Add-PSSnapin`) were removed in PowerShell 7. If your +profile loads snap-ins, replace them with module equivalents or guard with an +edition check: + +```powershell +if ($PSEdition -eq 'Desktop') { + Add-PSSnapin Microsoft.Exchange.Management.SnapIn +} +``` + +### PSReadLine version differences + +PowerShell 7 ships a newer version of PSReadLine than Windows PowerShell +5.1. Some options and key bindings behave differently. If you set PSReadLine +options in your profile, test them in both editions. Use `Get-PSReadLineOption` +to verify available settings. + +### Oh My Posh and prompt customization + +[Oh My Posh][oh-my-posh] works in both editions. If you use it, the profile +initialization is the same: + +```powershell +oh-my-posh init pwsh --config "$HOME/.mytheme.omp.json" | Invoke-Expression +``` + +### Module import errors + +A profile that imports a module unavailable in PowerShell 7 causes startup +errors. Use `Get-Module -ListAvailable` to check before importing, or +wrap the import in a `try`/`catch`: + +```powershell +try { + Import-Module SomeModule -ErrorAction Stop +} +catch { + Write-Warning "SomeModule not available in this edition." +} +``` + +## OneDrive and folder redirection + +When your Documents folder is redirected to OneDrive (common on Windows 10 +and 11), both profile paths point to cloud-synced storage. This causes: + +- Sync conflicts if you edit profiles on multiple machines +- Unnecessary bandwidth for module folders inside Documents +- Slow profile loading on metered connections + +To avoid these issues, store your profile or shared module outside the +OneDrive-synced path (for example, `$HOME\.powershell\`) and dot-source +from the cloud-synced profile location. + +## Measure profile load time + +A slow profile delays every new session. Measure load time to identify +bottlenecks: + +```powershell +Measure-Command { pwsh -NoProfile -Command ". $PROFILE" } +``` + +Compare against a session with no profile: + +```powershell +Measure-Command { pwsh -NoProfile -Command "exit" } +``` + +If the difference is large, review your profile for slow operations such as +unconditional module imports, network calls, or heavy initialization scripts. + +## Next steps + +- [Migrating from Windows PowerShell 5.1 to PowerShell 7][migration-guide] +- [Audit scripts for PowerShell 7 compatibility][script-audit] +- [Encoding changes in PowerShell 7][encoding-changes] +- [about_Profiles][about-profiles] + + +[about-profiles]: /powershell/module/microsoft.powershell.core/about/about_profiles +[encoding-changes]: ./encoding-changes.md +[migration-guide]: ../Migrating-from-Windows-PowerShell-51-to-PowerShell-7.md +[oh-my-posh]: https://ohmyposh.dev/ +[script-audit]: ./script-compatibility-audit.md diff --git a/reference/docs-conceptual/whats-new/migration/scheduled-tasks-automation.md b/reference/docs-conceptual/whats-new/migration/scheduled-tasks-automation.md new file mode 100644 index 00000000000..b9d608bb072 --- /dev/null +++ b/reference/docs-conceptual/whats-new/migration/scheduled-tasks-automation.md @@ -0,0 +1,213 @@ +--- +description: >- + Migrate scheduled tasks, PSScheduledJob scripts, and automation from + Windows PowerShell 5.1 to PowerShell 7. +ms.date: 04/15/2026 +title: Migrate scheduled tasks and automation to PowerShell 7 +--- + +# Migrate scheduled tasks and automation to PowerShell 7 + +Many organizations run PowerShell scripts through Windows Task Scheduler, +`PSScheduledJob`, or automation platforms. This article covers how to update +these configurations for PowerShell 7. + +## PSScheduledJob removal + +The `PSScheduledJob` module (`Register-ScheduledJob`, `Get-ScheduledJob`, +`Set-ScheduledJob`, and related cmdlets) was removed in PowerShell 7. This +module depended on PowerShell Workflow, which isn't available in .NET Core. + +### Replacement: ScheduledTasks module + +Use the `ScheduledTasks` module with `pwsh.exe` as the executable. The +`ScheduledTasks` module works in both Windows PowerShell 5.1 and +PowerShell 7. + +**Before (Windows PowerShell 5.1)**: + +```powershell +Register-ScheduledJob -Name 'DailyCleanup' ` + -ScriptBlock { Remove-Item "$env:TEMP\*.tmp" -Force } ` + -Trigger (New-JobTrigger -Daily -At '3:00 AM') +``` + +**After (PowerShell 7)**: + +```powershell +$action = New-ScheduledTaskAction ` + -Execute "$Env:ProgramFiles\PowerShell\7\pwsh.exe" ` + -Argument '-NoProfile -File "C:\Scripts\DailyCleanup.ps1"' + +$trigger = New-ScheduledTaskTrigger -Daily -At '3:00 AM' + +Register-ScheduledTask -TaskName 'DailyCleanup' ` + -Action $action ` + -Trigger $trigger ` + -RunLevel Highest ` + -User 'SYSTEM' +``` + +> [!IMPORTANT] +> Always use the full path to `pwsh.exe` in scheduled task actions. Relying +> on `PATH` resolution can break when the system `PATH` changes during +> updates. + +## Task Scheduler with PowerShell 7 + +### Correct executable path + +Use the full path to the PowerShell 7 executable: + +``` +C:\Program Files\PowerShell\7\pwsh.exe +``` + +### Argument format + +In PowerShell 7, the first positional parameter is `-File` (not `-Command` +as in Windows PowerShell 5.1). This affects how you specify arguments in +Task Scheduler: + +| Scenario | Argument string | +| -------- | --------------- | +| Run a script file | `-NoProfile -File "C:\Scripts\task.ps1"` | +| Run an inline command | `-NoProfile -Command "Get-Process \| Export-Csv C:\logs\procs.csv"` | +| Run a script with parameters | `-NoProfile -File "C:\Scripts\task.ps1" -Param1 Value1` | + +> [!NOTE] +> If your existing tasks use `powershell.exe "Get-Date"` (relying on the +> default `-Command` positional parameter), you must add `-Command` +> explicitly when switching to `pwsh.exe`. Without it, PowerShell 7 treats +> the argument as a file path. + +### Exit code handling + +PowerShell 7 passes the script's exit code to Task Scheduler. Use +`exit $code` in your scripts to return meaningful exit codes. Task Scheduler +shows the **Last Run Result** as the process exit code. + +## Audit existing scheduled tasks + +Use the following script to find all scheduled tasks that reference +`powershell.exe`: + +```powershell +Get-ScheduledTask | ForEach-Object { + $actions = $_.Actions | Where-Object { + $_.Execute -match 'powershell\.exe' + } + if ($actions) { + [PSCustomObject]@{ + TaskName = $_.TaskName + TaskPath = $_.TaskPath + Execute = ($actions.Execute -join '; ') + Arguments = ($actions.Arguments -join '; ') + State = $_.State + } + } +} | Format-Table -AutoSize +``` + +This lists every task that needs to be updated to use `pwsh.exe`. + +## Update tasks in bulk + +After auditing, update tasks programmatically. The following script creates +a backup of each task's XML definition, then updates the executable path: + +```powershell +$backupDir = 'C:\TaskBackups' +New-Item -Path $backupDir -ItemType Directory -Force + +$tasks = Get-ScheduledTask | Where-Object { + $_.Actions.Execute -match 'powershell\.exe' +} + +foreach ($task in $tasks) { + # Export backup + $exportPath = Join-Path $backupDir "$($task.TaskName).xml" + Export-ScheduledTask -TaskName $task.TaskName ` + -TaskPath $task.TaskPath | + Set-Content -Path $exportPath + + # Update each action + foreach ($action in $task.Actions) { + if ($action.Execute -match 'powershell\.exe') { + $action.Execute = ` + "$Env:ProgramFiles\PowerShell\7\pwsh.exe" + # Add -Command if arguments don't start with + # a flag + if ($action.Arguments -and + $action.Arguments -notmatch '^\s*-') { + $action.Arguments = + "-Command $($action.Arguments)" + } + } + } + + Set-ScheduledTask -InputObject $task + Write-Host "Updated: $($task.TaskPath)$($task.TaskName)" +} +``` + +> [!IMPORTANT] +> Test in a non-production environment before running bulk updates. Always +> back up task definitions first so you can roll back if scripts behave +> differently under PowerShell 7. + +## Rollback to Windows PowerShell + +If a task fails under PowerShell 7, restore it from the XML backup: + +```powershell +Register-ScheduledTask -TaskName 'DailyCleanup' ` + -Xml (Get-Content 'C:\TaskBackups\DailyCleanup.xml' -Raw) ` + -Force +``` + +## Azure Automation + +Azure Automation supports PowerShell 7 runbooks. When creating or updating +a runbook: + +1. Set the **Runtime version** to **7.2** or later in the runbook properties +1. Update any `Get-WmiObject` calls to `Get-CimInstance` +1. Test the runbook in the Azure portal before publishing + +> [!NOTE] +> Hybrid Runbook Workers use the locally installed PowerShell version. If +> you need PowerShell 7 on hybrid workers, install it on the worker machines +> and update the worker configuration to use `pwsh.exe`. + +## Other automation platforms + +### System Center Orchestrator + +Orchestrator runbook activities that call `powershell.exe` can be updated +to call `pwsh.exe`. Update the program path in the **Run .NET Script** or +**Run Program** activity properties. + +### Jenkins + +In Jenkins pipeline scripts, specify the PowerShell 7 executable: + +```groovy +bat '"C:\\Program Files\\PowerShell\\7\\pwsh.exe" -NoProfile -File script.ps1' +``` + +Or use the PowerShell plugin configured to use `pwsh.exe` as the +executable. + +## Next steps + +- [Migrating from Windows PowerShell 5.1 to PowerShell 7][migration-guide] +- [Deploy PowerShell 7 in enterprise environments][enterprise] +- [Test and validate your PowerShell 7 migration][testing-rollback] +- [Audit scripts for PowerShell 7 compatibility][script-audit] + + +[enterprise]: ./enterprise-deployment.md +[migration-guide]: ../Migrating-from-Windows-PowerShell-51-to-PowerShell-7.md +[script-audit]: ./script-compatibility-audit.md +[testing-rollback]: ./testing-and-rollback.md diff --git a/reference/docs-conceptual/whats-new/migration/script-compatibility-audit.md b/reference/docs-conceptual/whats-new/migration/script-compatibility-audit.md new file mode 100644 index 00000000000..b4b6685d0a6 --- /dev/null +++ b/reference/docs-conceptual/whats-new/migration/script-compatibility-audit.md @@ -0,0 +1,387 @@ +--- +description: >- + How to audit PowerShell scripts for compatibility with PowerShell 7 when + migrating from Windows PowerShell 5.1, including removed cmdlets, .NET + changes, and cross-version patterns. +ms.date: 04/15/2026 +title: Audit scripts for PowerShell 7 compatibility +--- + +# Audit scripts for PowerShell 7 compatibility + +Scripts written for Windows PowerShell 5.1 may use cmdlets, .NET types, or +language patterns that changed or were removed in PowerShell 7. Before you +migrate, audit your scripts to find these breaking patterns and fix them. + +This article walks through the most common compatibility problems and shows +how to fix each one. For the full technical reference of differences between +editions, see [Differences between Windows PowerShell 5.1 and +PowerShell 7.x][differences]. + +## Scan scripts with PSScriptAnalyzer + +[PSScriptAnalyzer][pssa] is a static analysis tool that checks PowerShell +code against a set of rules. The **PSUseCompatibleCmdlets** rule flags +cmdlets that don't exist in a target PowerShell version. + +### Install PSScriptAnalyzer + +```powershell +Install-PSResource PSScriptAnalyzer +``` + +### Run a basic scan + +Point the analyzer at your script directory to get a report of all rule +violations: + +```powershell +Invoke-ScriptAnalyzer -Path ./scripts -Recurse | + Format-Table -AutoSize +``` + +### Create a settings file for PowerShell 7 + +To enable the compatibility rule and target a specific PowerShell version, +create a settings file: + +```powershell +# PSScriptAnalyzerSettings.psd1 +@{ + Rules = @{ + PSUseCompatibleCmdlets = @{ + Enable = $true + TargetProfiles = @( + 'win-8_x64_10.0.17763.0_7.0.0_x64_3.1.2_core' + ) + } + } +} +``` + +Then run the analyzer with that settings file: + +```powershell +Invoke-ScriptAnalyzer -Path ./scripts -Recurse ` + -Settings ./PSScriptAnalyzerSettings.psd1 +``` + +> [!NOTE] +> The profile string names are documented in the +> [PSUseCompatibleCmdlets rule reference][pssa-profiles]. Use the profile +> that matches your target operating system and PowerShell version. + +## Removed cmdlets and replacements + +PowerShell 7 removed several cmdlet families that depended on +Windows-only .NET Framework APIs. The following sections list each family +and its replacement. + +### WMI v1 cmdlets + +The WMI v1 cmdlets are not available in PowerShell 7. Use the +**CimCmdlets** module instead. + +| Windows PowerShell 5.1 | PowerShell 7 replacement | +| ----------------------- | ------------------------ | +| `Get-WmiObject` | `Get-CimInstance` | +| `Set-WmiInstance` | `Set-CimInstance` | +| `Remove-WmiObject` | `Remove-CimInstance` | +| `Invoke-WmiMethod` | `Invoke-CimMethod` | +| `Register-WmiEvent` | `Register-CimIndicationEvent` | + +**Before (Windows PowerShell 5.1)**: + +```powershell +Get-WmiObject -Class Win32_OperatingSystem | + Select-Object Caption, Version +``` + +**After (PowerShell 7)**: + +```powershell +Get-CimInstance -ClassName Win32_OperatingSystem | + Select-Object Caption, Version +``` + +The CIM cmdlets use WS-Man (WinRM) by default instead of DCOM. You can +also create a DCOM session option if your environment requires it: + +```powershell +$option = New-CimSessionOption -Protocol Dcom +$session = New-CimSession -ComputerName Server01 ` + -SessionOption $option +Get-CimInstance -CimSession $session ` + -ClassName Win32_Service +``` + +### EventLog cmdlets + +The classic EventLog cmdlets are not available in PowerShell 7. Use the +cmdlets that query Event Tracing for Windows (ETW) logs. + +| Windows PowerShell 5.1 | PowerShell 7 replacement | +| ----------------------- | ------------------------ | +| `Get-EventLog` | `Get-WinEvent` | +| `Write-EventLog` | `New-WinEvent` | +| `Clear-EventLog` | `wevtutil cl ` | +| `Limit-EventLog` | `wevtutil sl /ms:` | +| `New-EventLog` | `New-WinEvent` or `wevtutil` | + +**Before (Windows PowerShell 5.1)**: + +```powershell +Get-EventLog -LogName Application -Newest 10 +``` + +**After (PowerShell 7)**: + +```powershell +Get-WinEvent -LogName Application -MaxEvents 10 +``` + +### PowerShell Workflow + +The `workflow` keyword and all Workflow-related cmdlets were removed in +PowerShell 7. There is no direct replacement. Consider these alternatives +depending on what the workflow did: + +- **Parallel execution**: Use `ForEach-Object -Parallel` (PowerShell 7.1 + and later) or `Start-ThreadJob` from the **ThreadJob** module. +- **Checkpointing and suspend-resume**: Use durable orchestration + frameworks such as Azure Durable Functions. +- **Remote fan-out**: Use `Invoke-Command` with multiple computer names. + +```powershell +# Replace a simple parallel workflow +$servers = 'Srv01', 'Srv02', 'Srv03' +$servers | ForEach-Object -Parallel { + Invoke-Command -ComputerName $_ -ScriptBlock { + Get-Service -Name wuauserv + } +} -ThrottleLimit 5 +``` + +### PSScheduledJob cmdlets + +The `PSScheduledJob` module (`Register-ScheduledJob`, `Get-ScheduledJob`, +and related cmdlets) is not available in PowerShell 7. Use the +**ScheduledTasks** module to create a task that runs `pwsh.exe`. + +For a detailed walkthrough, see +[Migrate scheduled tasks and automation to PowerShell 7][scheduled-tasks]. + +### Web service proxy + +`New-WebServiceProxy` depended on the Windows Communication Foundation +(WCF), which is not available in .NET Core. If the remote service offers +a REST API, use `Invoke-RestMethod` instead: + +**Before (Windows PowerShell 5.1)**: + +```powershell +$proxy = New-WebServiceProxy -Uri $wsdlUrl +$result = $proxy.GetWeather('Seattle') +``` + +**After (PowerShell 7)**: + +```powershell +$response = Invoke-RestMethod -Uri $restUrl +$response.weather +``` + +If you must consume a SOAP service, consider the +[System.ServiceModel][servicemodel] compatibility package on NuGet. + +### Other removed cmdlets + +The following cmdlets were removed because they depend on .NET Framework +APIs or Windows-only features not ported to .NET Core: + +| Removed cmdlet | Alternative | +| -------------- | ----------- | +| `Add-Computer` | Use the compatibility layer or `netdom join` | +| `Remove-Computer` | `netdom remove` or the compatibility layer | +| `Checkpoint-Computer` | System Restore via `vssadmin` or manual snapshots | +| `Restore-Computer` | System Restore control panel or `rstrui.exe` | +| `Get-PSSnapin` / `Add-PSSnapin` | Use modules instead (`Import-Module`) | +| `*-Transaction` | No replacement (transactions were rarely used) | +| `Export-Console` | No replacement (console files are obsolete) | + +## .NET method and type changes + +PowerShell 7 runs on .NET Core (and later .NET 5+), which introduced +breaking changes in some .NET APIs that PowerShell scripts may call +directly. + +### String.Split overload resolution + +In Windows PowerShell 5.1, calling `Split()` with a string argument +treated each character as a separate delimiter because the only matching +overload accepted `char[]`. In .NET Core, a new `Split(String)` overload +was added, so the string is treated as a single delimiter. + +```powershell +# Windows PowerShell 5.1: splits on 'a' and 'b' separately +'ca]b[d'.Split('ab') +# Output: c, ], [, d + +# PowerShell 7: splits on the literal string 'ab' +'ca]b[d'.Split('ab') +# Output: ca]b[d (no match, returns original) +``` + +**Fix:** Cast to `[char[]]` to get the Windows PowerShell behavior: + +```powershell +'ca]b[d'.Split([char[]]'ab') +``` + +### BinaryFormatter serialization + +.NET 8 and later disabled `BinaryFormatter` by default for security +reasons. This change affects: + +- `Export-Clixml` and `Import-Clixml` when serializing types that rely on + `BinaryFormatter` internally +- PowerShell remoting of complex custom objects +- Third-party modules that use binary serialization + +> [!IMPORTANT] +> Do not re-enable `BinaryFormatter` in production. Switch to JSON-based +> serialization with `ConvertTo-Json` and `ConvertFrom-Json`, or use +> `Export-Clixml` with types that support the PowerShell Extended Type +> System (ETS) serialization natively. + +### String comparison behavior + +Starting with .NET 5, culture-aware string comparisons using +`CurrentCulture` or `InvariantCulture` ignore certain control characters +(such as the soft hyphen `\u00AD`). This can cause `-eq`, `-match`, and +`Sort-Object` to produce different results on strings containing invisible +Unicode characters. + +**Fix:** Use `[StringComparison]::Ordinal` for byte-exact comparisons: + +```powershell +[string]::Compare( + $a, $b, [StringComparison]::Ordinal +) +``` + +## Executable and argument changes + +### Executable rename + +PowerShell 7 uses `pwsh.exe` instead of `powershell.exe`. Update every +reference in: + +- Scheduled tasks and Task Scheduler XML +- CI/CD pipeline definitions +- Batch files and shell scripts +- Windows shortcuts and registry entries + +Find references in your script files: + +```powershell +Get-ChildItem -Path ./scripts -Recurse -Include *.ps1 | + Select-String -Pattern 'powershell\.exe' +``` + +### Default positional parameter + +The default positional parameter changed between editions: + +| Edition | First positional parameter | +| ------- | ------------------------- | +| Windows PowerShell 5.1 | `-Command` | +| PowerShell 7 | `-File` | + +This means `pwsh "Get-Date"` tries to find a _file_ named `Get-Date`. +Always specify the parameter explicitly: + +```powershell +# Run a command string +pwsh -Command "Get-Date" + +# Run a script file +pwsh -File ./deploy.ps1 +``` + +> [!IMPORTANT] +> Scheduled tasks and CI/CD steps that relied on +> `powershell "Some-Command"` without an explicit `-Command` flag break +> when you switch to `pwsh`. Always add `-Command` or `-File` explicitly. + +### Native command argument passing + +PowerShell 7.3 and later changed how arguments are passed to native +executables. The `$PSNativeCommandArgumentPassing` preference variable +controls the behavior. The new default mode (`Windows` on Windows, +`Standard` on other platforms) preserves quotes and special characters +more faithfully. + +If your scripts relied on legacy quoting workarounds, test them after +migration. For details, see [about_Parsing][about-parsing]. + +## Cross-version compatible patterns + +When you need a single script that runs in _both_ Windows PowerShell 5.1 +and PowerShell 7, use these patterns. + +### Branch on edition + +The `$PSVersionTable.PSEdition` property returns `Desktop` for Windows +PowerShell and `Core` for PowerShell 7: + +```powershell +if ($PSVersionTable.PSEdition -eq 'Desktop') { + $os = Get-WmiObject -Class Win32_OperatingSystem +} +else { + $os = Get-CimInstance -ClassName Win32_OperatingSystem +} +$os | Select-Object Caption, Version +``` + +### Require a minimum version + +Use the `#Requires` statement to prevent a script from running on an +unsupported version: + +```powershell +#Requires -Version 7.0 +# This script uses ForEach-Object -Parallel +``` + +### Guard module imports + +If a module is only available in one edition, guard the import: + +```powershell +if (Get-Module -ListAvailable -Name PSScheduledJob) { + Import-Module PSScheduledJob +} +else { + Write-Warning 'PSScheduledJob is not available.' +} +``` + +## Next steps + +- [Module compatibility strategy for PowerShell 7][module-strategy] +- [Encoding changes in PowerShell 7][encoding-changes] +- [Migrating from Windows PowerShell 5.1 to PowerShell 7][migration-guide] +- [Differences between Windows PowerShell 5.1 and PowerShell 7.x][differences] + + +[about-parsing]: /powershell/module/microsoft.powershell.core/about/about_parsing +[differences]: ../differences-from-windows-powershell.md +[encoding-changes]: ./encoding-changes.md +[migration-guide]: ../Migrating-from-Windows-PowerShell-51-to-PowerShell-7.md +[module-strategy]: ./module-compatibility-strategy.md +[pssa]: /powershell/utility-modules/psscriptanalyzer/overview +[pssa-profiles]: /powershell/utility-modules/psscriptanalyzer/rules/usecompatiblecmdlets +[scheduled-tasks]: ./scheduled-tasks-automation.md +[servicemodel]: https://www.nuget.org/packages/System.ServiceModel.Http diff --git a/reference/docs-conceptual/whats-new/migration/testing-and-rollback.md b/reference/docs-conceptual/whats-new/migration/testing-and-rollback.md new file mode 100644 index 00000000000..3ab2697b7e2 --- /dev/null +++ b/reference/docs-conceptual/whats-new/migration/testing-and-rollback.md @@ -0,0 +1,232 @@ +--- +description: >- + Validate your PowerShell 7 migration with cross-edition testing, a + verification checklist, and rollback procedures. +ms.date: 04/15/2026 +title: Test and validate your PowerShell 7 migration +--- + +# Test and validate your PowerShell 7 migration + +After migrating scripts, modules, and automation from Windows PowerShell 5.1 +to PowerShell 7, validate that everything works correctly before +decommissioning your Windows PowerShell dependencies. This article provides a +testing strategy, validation checklist, and rollback procedures. + +## Testing strategy + +### Run scripts in both editions + +PowerShell 7 runs side-by-side with Windows PowerShell 5.1. Use this to +compare behavior by running the same script in both editions: + +```powershell +# Run in Windows PowerShell 5.1 +powershell.exe -NoProfile -File .\script.ps1 > output-51.txt + +# Run in PowerShell 7 +pwsh.exe -NoProfile -File .\script.ps1 > output-7.txt + +# Compare output +Compare-Object (Get-Content output-51.txt) (Get-Content output-7.txt) +``` + +### Pester test compatibility + +If your scripts have [Pester][pester] tests, run them in PowerShell 7. +Pester 5.x ships with PowerShell 7 and has significant changes from +Pester 3.x (which shipped with Windows PowerShell 5.1): + +| Feature | Pester 3.x (WinPS 5.1) | Pester 5.x (PS 7) | +| ------- | ----------------------- | ------------------ | +| Test structure | `Describe` / `It` | `Describe` / `It` (same syntax) | +| Assertions | `Should Be`, `Should Throw` | `Should -Be`, `Should -Throw` | +| Mocking | `Mock` (global scope) | `Mock` (scoped to `Describe` / `Context`) | +| Test discovery | Implicit | Explicit with `Run` configuration | +| Output | Text-based | `TestResult` object | + +If your tests use Pester 3.x syntax, the most common update is changing +`Should Be` to `Should -Be` (with a hyphen before the operator). + +### Cross-edition test matrix + +For critical scripts, test across a matrix of scenarios: + +| Scenario | What to verify | +| -------- | -------------- | +| Module loading | All modules import without errors | +| File output | Encoding matches expectations (see [Encoding changes][encoding]) | +| Remoting | Sessions connect to the correct endpoint | +| Scheduled tasks | Tasks run and return expected exit codes | +| Error handling | `try`/`catch` blocks catch the same exceptions | +| Native commands | Command output parses correctly | +| COM objects | Excel, Word, or other COM automation still works | + +## Validation checklist + +Use this checklist after completing your migration. Run each check in +PowerShell 7 and verify the result. + +### Module loading + +```powershell +# List modules that fail to import +Get-Module -ListAvailable | ForEach-Object { + try { + Import-Module $_.Name -ErrorAction Stop -Force + } + catch { + [PSCustomObject]@{ + Module = $_.Name + Error = $_.Exception.Message + } + } +} | Where-Object { $_.Error } +``` + +### Encoding verification + +```powershell +# Generate a test file and check its encoding +'Test output' | Out-File test-encoding.txt +$bytes = [System.IO.File]::ReadAllBytes( + (Resolve-Path test-encoding.txt) +) +if ($bytes[0] -eq 0xEF -and $bytes[1] -eq 0xBB) { + Write-Host 'UTF-8 with BOM' +} +elseif ($bytes[0] -eq 0xFF -and $bytes[1] -eq 0xFE) { + Write-Host 'UTF-16 LE' +} +else { + Write-Host 'UTF-8 without BOM (PowerShell 7 default)' +} +Remove-Item test-encoding.txt +``` + +### Remoting endpoints + +```powershell +# Verify PowerShell 7 endpoint exists +Get-PSSessionConfiguration | Where-Object { + $_.Name -match 'PowerShell\.\d' +} | Select-Object Name, PSVersion +``` + +### Scheduled task status + +```powershell +# Check for tasks still using powershell.exe +Get-ScheduledTask | Where-Object { + $_.Actions.Execute -match 'powershell\.exe' +} | Select-Object TaskName, TaskPath, State +``` + +### Profile loading + +```powershell +# Verify profile loads without errors +pwsh -NoProfile -Command { + try { + . $PROFILE -ErrorAction Stop + Write-Host 'Profile loaded successfully' + } + catch { + Write-Warning "Profile error: $_" + } +} +``` + +## Rollback procedures + +PowerShell 7 doesn't replace Windows PowerShell 5.1. Rolling back means +reverting your automation pointers, not uninstalling PowerShell 7. + +### Roll back scheduled tasks + +If you backed up task definitions before migrating (see +[Migrate scheduled tasks][scheduled-tasks]), restore from XML: + +```powershell +Get-ChildItem 'C:\TaskBackups\*.xml' | ForEach-Object { + $xml = Get-Content $_.FullName -Raw + $taskName = $_.BaseName + Register-ScheduledTask -TaskName $taskName -Xml $xml -Force + Write-Host "Restored: $taskName" +} +``` + +### Roll back remoting endpoints + +If you configured PowerShell 7 as the default SSH shell, revert the +registry setting: + +```powershell +Set-ItemProperty -Path 'HKLM:\SOFTWARE\OpenSSH' ` + -Name DefaultShell ` + -Value "$Env:windir\System32\WindowsPowerShell\v1.0\powershell.exe" +``` + +For WinRM, remote sessions default to the Windows PowerShell endpoint +unless the caller specifies `-ConfigurationName PowerShell.7`, so no +rollback is needed for WinRM. + +### Roll back profiles + +If you symlinked profiles, remove the symbolic link and create a +PowerShell 7-specific profile: + +```powershell +$ps7Profile = "$HOME\Documents\PowerShell\Microsoft.PowerShell_profile.ps1" +if ((Get-Item $ps7Profile).LinkType -eq 'SymbolicLink') { + Remove-Item $ps7Profile + # Optionally create a minimal PS7 profile + Set-Content -Path $ps7Profile -Value '# PowerShell 7 profile' +} +``` + +## Coexistence timeline + +Plan for a period where both editions run production workloads. A +recommended approach: + +| Phase | Duration | What to do | +| ----- | -------- | ---------- | +| Parallel testing | 2 weeks | Run scripts in both editions, compare results | +| Gradual migration | 4 weeks | Move non-critical tasks to PowerShell 7 first | +| Monitoring | 2 weeks | Watch for errors in migrated tasks | +| Full cutover | 1 day | Move remaining tasks, update default shells | +| Post-cutover | Ongoing | Keep Windows PowerShell available as a fallback | + +### Cutover criteria + +Before fully cutting over to PowerShell 7, verify: + +- All scheduled tasks run successfully for at least two scheduled cycles +- Remoting endpoints respond correctly +- No encoding-related errors in log files +- Module imports succeed without falling back to the compatibility layer +- CI/CD pipelines pass with `pwsh` tasks +- Monitoring and alerting rules updated for PowerShell 7 event logs + +### Keeping Windows PowerShell available + +Windows PowerShell 5.1 ships with Windows and can't be uninstalled. Even +after cutting over to PowerShell 7, keep it available as a fallback for +scripts that can't be migrated and modules that require the .NET Framework. + +## Next steps + +- [Migrating from Windows PowerShell 5.1 to PowerShell 7][migration-guide] +- [Audit scripts for PowerShell 7 compatibility][script-audit] +- [Module compatibility strategy for PowerShell 7][module-strategy] +- [Encoding changes in PowerShell 7][encoding] +- [Migrate scheduled tasks and automation][scheduled-tasks] + + +[encoding]: ./encoding-changes.md +[migration-guide]: ../Migrating-from-Windows-PowerShell-51-to-PowerShell-7.md +[module-strategy]: ./module-compatibility-strategy.md +[pester]: https://pester.dev/ +[scheduled-tasks]: ./scheduled-tasks-automation.md +[script-audit]: ./script-compatibility-audit.md diff --git a/reference/docs-conceptual/whats-new/module-compatibility.md b/reference/docs-conceptual/whats-new/module-compatibility.md index fb8b2f8af1e..ef02893ce77 100644 --- a/reference/docs-conceptual/whats-new/module-compatibility.md +++ b/reference/docs-conceptual/whats-new/module-compatibility.md @@ -63,12 +63,45 @@ The SqlServer modules require PowerShell version 5.0 or greater. For more information, see [Install the SQL Server PowerShell module][06]. +## Windows management module compatibility details + +Several Windows management modules have been tested for compatibility with +PowerShell 7. Results vary depending on whether the module uses .NET +Framework-only APIs: + +| Module | PowerShell 7 status | +| ------ | ------------------- | +| ActiveDirectory | Works natively (RSAT required) | +| DISM | Requires the compatibility layer | +| GroupPolicy | Partial support; use the compatibility layer | +| Hyper-V | Works natively | +| NetAdapter | Works natively | +| ScheduledTasks | Works natively | +| Storage | Works natively | + +For modules that don't work natively, use +`Import-Module -UseWindowsPowerShell` to load them through the +Windows PowerShell compatibility layer. For limitations and known issues +with this approach, see +[Module compatibility strategy for PowerShell 7][07]. + ## Finding the status of other modules You can find a complete list of modules using the [PowerShell Module Browser][04]. Using the Module Browser, you can find documentation for other PowerShell modules to determine their PowerShell version requirements. +To test a specific module in PowerShell 7, try importing it: + +```powershell +Import-Module -ErrorAction Stop +Get-Command -Module +``` + +If the import fails, check whether the module manifest includes +`CompatiblePSEditions`. For a detailed testing strategy, see +[Module compatibility strategy for PowerShell 7][07]. + [01]: /powershell/microsoftgraph/overview#microsoft-graph-powershell-features--benefits [02]: /powershell/azure/new-azureps-module-az @@ -76,3 +109,4 @@ version requirements. [04]: /powershell/module [05]: /powershell/windows/module-compatibility [06]: /sql/powershell/download-sql-server-ps-module +[07]: ./migration/module-compatibility-strategy.md diff --git a/reference/docs-conceptual/whats-new/overview.yml b/reference/docs-conceptual/whats-new/overview.yml index d9b4fa22257..c11bba1e56f 100644 --- a/reference/docs-conceptual/whats-new/overview.yml +++ b/reference/docs-conceptual/whats-new/overview.yml @@ -43,6 +43,21 @@ landingContent: - text: Migrating from Windows PowerShell 5.1 to PowerShell 7 url: ./migrating-from-windows-powershell-51-to-powershell-7.md + - title: Migration deep dives + linkLists: + - linkListType: how-to-guide + links: + - text: Script compatibility audit + url: ./migration/script-compatibility-audit.md + - text: Module compatibility strategy + url: ./migration/module-compatibility-strategy.md + - text: Encoding changes + url: ./migration/encoding-changes.md + - text: Profile migration + url: ./migration/profile-migration.md + - text: Enterprise deployment + url: ./migration/enterprise-deployment.md + - title: History & Compatibility linkLists: - linkListType: whats-new