Tuesday, March 10, 2020

PowerShell 7 Chain and Ternary Operators

Introduction and Background

Welcome to this post as part of this PowerShell 7's #PSBlogWeek!   I hope you are enjoying the many posts.

As I started to think about this topic, an old Grateful Dead song kept running through my mind "Operator, Can you help m?  Help me if you please...For a live version, listen to https://www.youtube.com/watch?v=TytIqm_d7uE.

So here is some information about a couple of the great new features in PowerShell 7, in particular, the Pipeline Chain Operators and the Ternary Operators.

In the days of Windows PowerShell, extending the PowerShell language was done by the Microsoft Windows PowerShell team.  With the move to open source, more developers can, and have, made it possible to do a lot more in PowerShell 7. PowerShell's language was modelled on C# - Jeff Snover has often said that PowerShell is on the glide scope to C#.

With PowerShell 7 comes two new operator sets: The Pipeline Chain Operators and the Ternary operators.

The Pipeline Chain operators (|| and &&) enable you to allow conditional execution of commands depending on whether the previous command succeeded for failed. You use the Ternary operators (? and :) as a short-hand way of implementing if/else type statements. These are popular among C# developers and Bash users and have long been requested within PowerShell.

These operators add new functionality to PowerShell 7. They are nice when used carefully, but can reduce the clarity of production code. Let's look at them in more detail. 

PIpeline Chain Operators

The pipeline Chain operators enable conditional execution of commands depending on whether a previous command succeeded or failed. There are two pipeline chain operators: && and ||These operators were added to PowerShell 7 Preview 5.  Prior to PowerShell 7, you could have used If/Else to do the same thing,

These operators come originally from Posix. POSIX shells call this as AND-OR lists. The idea is that depending on whether a command is successful, you can do different things.

What is it used for?

If a pipeline is successful, this operator allows you to run some other pipeline. But if the first pipeline is unsuccessful, you can run a different pipeline. 

For example:

# Create an SSH key pair - if successful copy 
# the public key to clipboard
ssh-keygen -t rsa -b 2048 && Get-Content -Raw ~\.ssh\id_rsa.pub || clip

If the keys are generated successfully using SSH-KEYGEN (and content returned from Get-Content), then the command copies it to the clipboard. Without these operators you would have used if/else and/or try/catch - the chain operators make things a bit shorter.

Ternary Operators

The ternary operator evaluates a Boolean expression and returns the result of one of the two expressions, depending on whether the Boolean expression evaluates to true or false.
This sounds more complex than it is (see the example below!) These operators were added to PowerShell 7 Preview 4. 

What Is It Used For?
You typically use this operator mainly to create a string depending on the value of a boolean variable or expression. For example, you could create a string that displayed whether an AD user account was enabled based on the user's Enabled property or display whether a user is using PowerShell on a Mac. Like this:

# Is User Enabled?
# Create 2 strings
$UEMsg1         = "This user IS enabled in AD"
$UEMsg2         = "This user IS NOT enabled in AD"
# Get Details
$UserEnabled    = (Get-ADUser -Identity $UserName).Enabled
# Set Enabled/Disable String
$UserEnabledStr = $UserEnabled ? $UEMsg1 : $UEMsg2
# What does this show for an enabled user:
This user IS enabled in AD
# Anotehr example
$IsMacOS ? 'Yes' : 'No'

You Can but Should You?

I like these new operators but am not likely to use them in code I write.  Except maybe to demonstrate them.  I really do not, yet, see a great use case, except at the console. As an example of this, look at the chain operator example above. That snippet executes a command, and if successful copies a file to the clipboard. 

Personally, I'd have written it more like this:

# Create an SSH key pair - if successful, copy
# the public key to clipboard
try {
  ssh-keygen -t rsa -b 2048
Catch {
    # handle terminating error - left as an exercise for the reader
#  then    
Get-Content -Raw ~\.ssh\id_rsa.pub | clip

If I was running this from the console, I'd just run ssh-keygen. If it ran ok, then I'd type Get-Content and pipe the output to the clipboard. Typing longer lines of code is almost certain to introduce typos, especially given my lousy typing. I find doing things step by step is easiest - both to write and to understand months later when the code needs modification.

These operators have the potential to reduce the clarity of production code. Unless you know these operators, their meaning is not easy to discern. Operators like -Contains, -Eq, and -Match are both named so as to give at least some clue to their use. The '?' character an alias for Where-Object and the ':' used in PSDrive letters leading to overloaded operators.  And that can diminish the readability of production code. I am sure mileage varies - and would love to hear comments as well as seeing more great use cases.


TL;DR: Great new operators that bring requested C# Features to PowerShell - Just use them wisely.

No comments: