What's New in PowerShell 7.6

PowerShell 7.6 has officially been released as the new Long-Term Support (LTS) version, and it’s built on .NET 10.
If you’re currently running PowerShell 7.4 (the previous LTS) or 7.5 (the current stable), this is the one you’ll want to move to for production workloads. Being an LTS release means you’ll get 3 years of support, so you can rely on this version without having to chase every new release.
This post covers the engine and language changes. PowerShell 7.6 also ships with PSResourceGet 1.2.0, which I’ve covered in a separate post since it’s a significant update to how you manage modules.
Let’s go through the highlights.
Built on .NET 10 (LTS)
This might sound like just a version bump, but it matters. .NET 10 is itself an LTS release, which means the foundation PowerShell 7.6 sits on is also getting long-term support. You get performance improvements, security patches, and API updates that come with the .NET platform — without having to think about it.
Tab Completion That Actually Works
If you’ve ever been frustrated by tab completion being inconsistent in PowerShell, this release addresses a lot of those pain points.
Registry and Provider Navigation
When browsing registry paths like HKLM:\Software\*, tab completion now correctly suggests subkeys. In earlier versions, this would often return incomplete results or just… nothing. This fix extends to other providers too, including the Certificate store (Cert:\) and environment variables (Env:\).
Array and Object Properties
This one’s nice. If you assign an array:
$servers = @("Server1", "Server2", "Server3")
And then type $servers. followed by Tab, PowerShell now actually suggests array methods like Count or Length. Same goes for command results — (Get-Process). now properly completes to properties like Name and CPU.
File Paths with Special Characters
Folders with spaces or double quotes in their names now complete reliably. If you’ve ever had a path just refuse to tab-complete because of a special character, you know how annoying that was.
New and Updated Cmdlet Features
Get-Command -ExcludeModule
A small but handy addition. You can now exclude specific modules from the results, which is great when you want to filter out commands you don’t need — or don’t want to accidentally run.
For example, say you want to see all formatting commands, but you’d rather not have Format-Volume from the Storage module show up in your results:
# Get all Format commands, excluding the Storage module ones
Get-Command -Verb Format -ExcludeModule Storage
This way you get the safe formatting commands like Format-List, Format-Table, Format-Wide and Format-Custom without the potentially destructive storage ones mixed in.
Join-Path Accepts Multiple Child Paths
The -ChildPath parameter now accepts a string[]. Before 7.6, if you wanted to join multiple path segments you had to use -AdditionalChildPath:
# The old way (PowerShell 7.5 and earlier)
Join-Path -Path "C:\Users" -ChildPath "robert" -AdditionalChildPath "Documents", "Scripts"
# Result: C:\Users\robert\Documents\Scripts
Now you can just pass everything to -ChildPath:
# The new way (PowerShell 7.6)
Join-Path -Path "C:\Users" -ChildPath "robert", "Documents", "Scripts"
# Result: C:\Users\robert\Documents\Scripts
Same result, less to remember. A minor quality-of-life improvement, but one of those things that just makes sense.
PSForEach() and PSWhere() Aliases
PowerShell has had the intrinsic .Where() and .ForEach() methods for a while now. They’re faster than piping to Where-Object or ForEach-Object because they operate directly on collections in memory — no pipeline overhead. The catch? Unless you already knew about them, they weren’t exactly easy to discover.
PowerShell 7.6 adds PSWhere() and PSForEach() as aliases, making them a bit more visible. Here’s how they compare:
# Get all running services — three ways to do the same thing
# The pipeline way (most common, but slowest on large collections)
Get-Service | Where-Object { $_.Status -eq 'Running' }
# The intrinsic method (faster, but easy to miss)
(Get-Service).Where({ $_.Status -eq 'Running' })
# The new alias (same performance as above, just more discoverable)
(Get-Service).PSWhere({ $_.Status -eq 'Running' })
Same idea applies to ForEach:
# Get all service display names — three ways
# Pipeline
Get-Service | ForEach-Object { $_.DisplayName }
# Intrinsic method
(Get-Service).ForEach({ $_.DisplayName })
# New alias
(Get-Service).PSForEach({ $_.DisplayName })
For a handful of items, the difference is negligible. But when you’re processing thousands of objects, the intrinsic methods (and their new aliases) can be noticeably faster since they skip the pipeline entirely.
Large Number Readability
You can now use comma separators in large numbers:
[bigint]'1,000,000'
Instead of staring at 1000000 trying to count zeros. Particularly useful when you’re dealing with disk space calculations or large counters.
Out-GridView is Back
If you’ve used Out-GridView on older PowerShell 7.x versions, you might have noticed it was… broken. The underlying issue was that recent .NET versions removed the legacy BinaryFormatter API for security reasons, and Out-GridView still depended on it.
PowerShell 7.6 replaces BinaryFormatter with a custom, secure implementation, so Out-GridView works properly again — including filtering and search.
Breaking Changes
There are a few breaking changes to be aware of. Nothing dramatic, but worth checking:
- Join-Path -ChildPath now takes
string[]— this shouldn’t break anything, but test your scripts if you’re passing values to it in unexpected ways - WildcardPattern.Escape() now correctly escapes lone backticks — if you had workarounds for this bug, you might need to remove them
- ThreadJob module renamed —
ThreadJobis nowMicrosoft.PowerShell.ThreadJob. If your scripts use the module-qualified nameThreadJob\Start-ThreadJob, update it toMicrosoft.PowerShell.ThreadJob\Start-ThreadJob
PSResourceGet 1.2.0
PowerShell 7.6 ships with PSResourceGet 1.2.0, which is a significant update to the module management experience. I’ve written a separate post about that, since it deserves its own spotlight.
How to Install or Upgrade
If you’re on Windows, the easiest way is through winget:
# Check if an upgrade is available
winget list --id Microsoft.PowerShell --upgrade-available
# Install or upgrade
winget install --id Microsoft.PowerShell --source winget
You can also grab it directly from the GitHub releases page or use whatever package manager you prefer on your platform.
Should You Upgrade?
If you’re on 7.4 (LTS): yes. 7.4 is supported until November 2026, so you have time, but 7.6 gives you everything 7.4 has plus all the improvements above — with another 3 years of support ahead of it.
If you’re on 7.5 (stable): also yes. 7.5 is the current stable release but doesn’t have LTS support. Moving to 7.6 gives you the stability guarantee you’d want for production.
If you’re on Windows PowerShell 5.1: it’s always worth evaluating the move to PowerShell 7.x. Most modules work fine on 7.x these days, and you get cross-platform support, better performance, and features like PSResourceGet that make module management significantly better.
For the full list of changes, check out the official announcement and the What’s New documentation.
Happy scripting 😊