PowerShell 7 for Programmers
First published . Updated .
Microsoft's PowerShell Team and countless members of the open-source community have worked hard on crafting and coding the seventh major version of PowerShell. Its predecessor, PowerShell Core 6, was a massive rewrite of Windows PowerShell 5.1 that saw (most of) the codebase changed to run on the cross-platform .NET Core framework, which brought PowerShell to macOS and Linux for the first time, along with new features and performance enhancements.
, work had all but completed on PowerShell 7, and the final version is available for download for supported Windows, macOS, and Linux systems. In addition to an optional long-term-servicing support model, Docker and NuGet inclusion, Desired State Configuration improvements, and good compatibility with modules that only claim to support Windows PowerShell, there are many improvements to the language and runtime that will benefit developers.
pwsh
is now supported as a login shell
While this isn't a language change, it is great news for many developers who don't use Windows full-time or at all. I tried to learn Bash shell scripting, but I didn't get far and I was never very good at it. Luckily for me, as of PowerShell 7.0.0-preview3, pwsh
is now fully supported as a login shell on macOS and Linux.
Parallel execution for for-each loops
Up until now, if you used the ForEach-Object
cmdlet, it would operate on each item sequentially, one at a time. New in PowerShell 7 is the -Parallel
switch and parameter set, which will operate on multiple items at once. You can also use the -ThrottleLimit
parameter to tell PowerShell how many statement blocks should be run in parallel at any given time; it defaults to five.
While this will usually increase performance, using a parallel for-each loop means that your items will no longer be processed in order. If order is important, use a normal for or for-each loop.
Example:
However, there is no way for this to fail gracefully on earlier versions of PowerShell. If you cannot guarantee your code will run on PowerShell 7, you'll have to wrap it in a try-catch block, or better yet, do an ugly version and edition check:
As far as I know, neither the .ForEach()
method nor the ForEach
statement/loop offer parallel execution.
ForEach-Object -Parallel
is not enabled by default, nor will it be. There are some times to use this, and some times to avoid it. For more information and some use cases, I'll refer you to Paul Higinbotham's blog post introducing it.
An earlier version of this article said that ForEach-Object -Parallel
was only supported on Windows. As of version 7.0.0-rc.2, it is indeed available on macOS and Linux.
Null coalescing operator
As someone who finds himself having to write a lot of checks for null values, this new operator is a major improvement, in my opinion. If the variable before the operator is $null
, the variable afterwards is returned; otherwise, the variable itself is returned. Let's see it in action.
Before PowerShell 7 | In PowerShell 7 |
---|---|
If ($null -Eq $x) { Write-Output 'nothing' } Else { Write-Output $x } |
Write-Output ($x ?? 'nothing')
|
$name = Read-Host -Prompt "File name" $file = Get-Item $name If ($null -Eq $file) { $file = Get-Item "default.txt" } |
$name = Read-Host -Prompt "File name" $file = Get-Item $name ?? Get-Item "default.txt" |
Null assignment operator
Similar to the above, the new null assignment operator will assign a value to a variable if and only if it is equal to $null
.
Before PowerShell 7 | In PowerShell 7 |
---|---|
$name = Read-Host -Prompt "Enter a file name" If ($null -Eq $name) { $name = "default.txt" } Get-Item $name |
$name = Read-Host -Prompt "Enter a file name" $name ??= "default.txt" Get-Item $name |
Null conditional member property and method access (PowerShell 7.1)
In previous versions of PowerShell, you would have to check if a variable is $null
before attempting to access its members, or wrap your code in try-catch blocks; if you failed to do so, your script might terminate unexpectedly when -ErrorAction Stop
is set. Now, put a question mark after your variable to silently continue and return $null
if something does not exist.
Unfortunately, because PowerShell allows question marks in variable names, using this operator means that you do have to include the optional braces around your variable name, so PowerShell knows where your variable name begins and ends.
Pipeline chaining operators
PowerShell 7 implements the pipeline chaining operators made famous by Bash. Previously, to run a command based on if the previous operation succeeded or failed, you would have to check the return code or the automatic variable $?
. Now, you can use &&
to run a second command if and only if the first one succeeds, and use ||
to run a second command if and only if the first one fails. For example:
No, you can't use &&
and ||
together to emulate an if-else statement. However, PowerShell 7 adds some popular shorthand:
Ternary operator
Many programming languages have what's called the ternary operator (sometimes called the conditional operator), which is just a shorter method of writing an if-else statement. While I believe it can lead people to write messy code, sometimes it's much cleaner-looking and easier for a human to read.
Before PowerShell 7 | In PowerShell 7 |
---|---|
If ($flag -Eq $true) { Write-Output "Yes" } Else { Write-Output "No" } |
Write-Output ($flag ? "Yes" : "No")
|
If ($user.isMember()) { $price += 2 } Else { $price += 5 } |
$price += $user.isMember() ? 2 : 5
|
$x = $items.Count If ($x -Eq 1) { $msg = "Found $x item." } Else { $msg = "Found $x items." } |
$x = $items.Count $msg = "Found $x item$($x -Eq 1 ? 's' : '')." |
Reverse operation for the -Split
operator
When you provide a matching limit to the -Split
operator, it normally works left-to-right. Now, it can operate right-to-left instead.
Skip error handling for web cmdlets
PowerShell does a pretty decent job of handling errors for you, but sometimes, you might want to do it yourself. The Invoke-WebRequest
and Invoke-RestMethod
cmdlets now support a new switch, -SkipHttpErrorCheck
.
Before this, the raw HTML code of the request would be returned, and you would have to parse the error object yourself. Use this switch, and those two cmdlets will return a "success" even when an HTTP error occurred. You, as the programmer, can now handle errors yourself without cumbersome try-catch blocks, by reading the response yourself.
Invoke-RestMethod
also includes a new parameter, -StatusCodeVariable
, to which you pass the name of a variable (confusingly, a string with the variable name, not the variable itself) that will contain the HTTP response code.
New $ErrorActionPreference
, Break
If you change your $ErrorActionPreference
preference variable to the new value "Break"
, you can then drop into a debugger as soon as an error happens. For example, let's try dividing by zero.
Neat!
Get-Clipboard
and Set-Clipboard
are back
After a hiatus in PowerShell Core 6, the two cmdlets, Get-Clipboard
and Set-Clipboard
, return. Though they can only manipulate plain text at this time, unlike their Windows PowerShell implementations, they are available for use on all platforms.
Linux users must make sure xclip
is installed.
Miscellaneous
There are many more little features you might find useful.
- After taking some time off during PowerShell Core 6, the following Windows PowerShell things return -- for Windows users only:
Clear-RecycleBin
Get-Help
's-ShowWindow
parameterOut-GridView
Out-Printer
Show-Command
- Enumerating files in OneDrive works, and when using files on demand, doing so won't trigger an automatic download.
Format-Hex
better handles custom types.Get-ChildItem
, when used on macOS or Linux, now returns the propertiesUnixMode
,User
, andGroup
.Send-MailMessage
is now deprecated. Unfortunately, there is no secure fix or replacement available.Test-Connection
never really went away, but it now behaves identically on Windows, macOS, and Linux.
There are also many improvements to Desired State Configuration. There is also a compatibility layer for loading modules not marked as compatible with Core editions; however, if you're a module developer, you should have already set CompatiblePSEditions
appropriately!
The final release of PowerShell 7 was released on , so download it, get coding, and happy developing!