[powershell]2023-08-02~2 min read

Migrating to PowerShell 7 Was Painful and Worth It

PowerShell 7 has been available for three years. We finally migrated our automation platform from Windows PowerShell 5.1 to PowerShell 7. It took a month. Multiple things broke. It was absolutely the right decision.

Why we did it

Windows PowerShell 5.1 is frozen. Microsoft stopped adding features years ago, and the .NET Framework dependency limits what it can do. PowerShell 7 is built on .NET (Core), gets regular updates, runs on Linux and macOS, and has better performance for data-heavy operations.

The specific triggers for us:

Performance. A compliance script that took 40 minutes in 5.1 ran in 12 minutes in PowerShell 7. Parallel ForEach-Object -Parallel alone justified the migration for our bulk operation scripts.

Cross-platform. We had Linux servers with no Windows PowerShell. Our automation needed to manage both platforms from a single shell. PowerShell 7 runs everywhere.

New features. Ternary operators, null coalescing, improved error handling with Get-Error, pipeline chain operators (&& and ||). Small quality-of-life improvements that collectively made scripts cleaner and more maintainable.

What broke

Module compatibility. About 15% of our internal modules didn't load in PowerShell 7. Some used APIs only available in .NET Framework. Some had hardcoded paths to C:\Windows\System32\WindowsPowerShell. Some used deprecated cmdlets that were removed in PowerShell 7. Each module had to be individually assessed, updated, or replaced.

The AD module. The ActiveDirectory module for PowerShell 7 works differently than the 5.1 version. It uses the AD Web Services gateway instead of direct ADSI. This is more secure but requires configuration on the domain controller. Took a day to figure out why my AD scripts were suddenly failing with cryptic errors.

COM objects. Anything using COM (Excel automation, Internet Explorer automation, some legacy application integrations) doesn't work in PowerShell 7. COM is Windows-only and PowerShell 7 is cross-platform. We had to rewrite the COM-dependent scripts to use REST APIs or native modules. This was the hardest part.

Scheduled Tasks. Scheduled tasks configured to run powershell.exe need to be updated to run pwsh.exe. Every single one. We had 47 scheduled tasks. Three were missed. Two broke silently for a week before anyone noticed. Automate the migration validation.

How we managed the transition

We ran PowerShell 5.1 and 7 side by side for two months. New scripts in 7. Legacy scripts in 5.1 until they were validated on 7. The migration wasn't a cutover. It was a gradual translation, script by script, module by module.

The testing framework was simple: every automated script had to produce identical output in 5.1 and 7 before being cut over. If the output differed, investigate. If it can't be made identical, document the difference and get sign-off. This caught issues that would have been production incidents.

The result

All automation now runs on PowerShell 7. Scripts are faster. The codebase is cleaner. We can manage Windows and Linux from the same shell. The migration was a month of pain for years of benefit. Worth it.

[powershell][automation]