A Primer on Special PowerShell Operators

powershell-hero-img
Over the course of a few articles, I’ve been introducing you to PowerShell operators. Most of them like -eq and -And are not that difficult to figure out if you see them in an example. PowerShell has several other operators that I describe as special use and may not be intuitive, but I think you will find them quite useful.

Range

The range operator (..) is a quick way to get a range of numbers in either ascending or descending order.

the PowerShell Range operator
the PowerShell Range operator (Image Credit: Jeff Hicks)

This operator only works with integer values.

Range failures
Range failures (Image Credit: Jeff Hicks)

I like using the range operator as a counter.

1..5 | foreach {
"do something here on pass $_"
}

This will run the code in the ForEach-Object loop five times.
Or you could use it like this to build a random password.

Function New-Password {
Param([int]$Length = 7)
-join (33..126 | Get-Random -count $length | foreach {$_ -as [char]} )
}

And maybe you want to generate a list of passwords

Creating a range of passwords
Creating a range of passwords (Image Credit: Jeff Hicks)

Call

The call operator (&) is used to invoke or run an expression. You might have a scriptblock you are using with Invoke-Command, but you will need to test it.

Calling a PowerShell scriptblock
Calling a PowerShell scriptblock (Image Credit: Jeff Hicks)

True, I could also have used Invoke-Command to test the scriptblock. But you can also use this operator to invoke commands stored as variables.

Invoking an PowerShell expression in a variable
Invoking an PowerShell expression in a variable (Image Credit: Jeff Hicks)

But it can’t parse an expression with parameters.

Invoke failure
Invoke failure (Image Credit: Jeff Hicks)

However, because the Call operator is simply invoking the command, you can still pass parameters like this:

Calling a PowerShell command with parameters
Calling a PowerShell command with parameters (Image Credit: Jeff Hicks)

Static Member

The static member operator (::) confuses newcomers. Part of the problem is that this is part of the .NET world. In .NET, sometimes you have to construct an instance of an object before you can invoke or run any of the object’s methods. In those situations you would use the . operator.

$now = Get-Date
$then = $now.AddDays(100)

I had to create a [Datetime] object before I could invoke the AddDays() method. But some .NET classes have methods that are considered static. In these situations, you don’t need to create an instance of the object. You can invoke the method directly from the class. The [math] class is a great example.

[math]::pi
[math]::Pow(2,3)

Or here is a more practical example:

Get-CimInstance win32_logicaldisk -filter "drivetype = 3" -ComputerName $c |
Select DeviceID,
@{Name="SizeGB";Expression = {($_.size/1GB) -as [int]}},
@{Name="FreeGB";Expression = { [math]::Round($_.freespace/1gb,4)}},
@{Name="PctFree";Expression = { [math]::Round(($_.freespace/$_.size) *100,2)}},
PSComputername | Out-GridView -Title "Drive Report"

You’ll also notice I’m using a few other operators I’ve discussed in previous articles. Invoking the static methods from the [Math] class produces a much nicer report.

Drive report with calculated values
Drive report with calculated values (Image Credit: Jeff Hicks)

Array

Most of the time you don’t need to define a PowerShell array ahead of time. But you can explicitly create an empty array using @().

Explicitly defining an array in PowerShell
Explicitly defining an array in PowerShell (Image Credit: Jeff Hicks)

Note that this technique will create an array of a fixed size so you can’t necessarily use all methods of an array object.

Testing array methods
Testing array methods (Image Credit: Jeff Hicks)

Notice at the end the Clear() method removed the values of the array, but didn’t erase the array.  It is now an array with three null values. Just something to be aware of.
But while we are looking at arrays, let me give you another special operator, the single comma. The problem is you might have code like this:

Array problems
Array problems (Image Credit: Jeff Hicks)

You want to create an array like you did before instead $b is an integer. The , operator can solve that problem.

Using the comma operator to define an array (Image Credit: Jeff Hicks)
Using the comma operator to define an array (Image Credit: Jeff Hicks)

Now $b is automatically an array.

Subexpression

The last special operator I want to demonstrate is the subexpression or $(). Knowing how this works and when to use it indicates that you have moved  beyond absolute PowerShell beginner.
Beginners will try to build a string like this:

"The computer $env:computername is running PowerShell version $psversiontable.psversion"

Beginners will expect this to show the PowerShell version, but instead they get a result like this:

The computer WIN81-ENT-01 is running PowerShell version System.Collections.Hashtable.psversion

That’s not what they expected. Instead they need to use a subexpression. Think of a subexpression like this: PowerShell will run the commands inside the parentheses and the $ sign tells PowerShell to treat the result like a temporary variable. Here is the correct solution using a subexpression:

"The computer $env:computername is running PowerShell version $($psversiontable.psversion)"

I use subexpressions, often in verbose messages in my scripts. Let’s revisit my New-Password function.

Function New-Password {
[cmdletbinding()]
Param([int]$Length = 7)
Begin {
    Write-Verbose "[BEGIN  ] Starting: $($MyInvocation.Mycommand)"
    Write-Verbose "[BEGIN  ] Using Parameter set $($pscmdlet.ParameterSetName)"
    Write-Verbose "[BEGIN  ] $env:computername $((Get-WmiObject Win32_operatingsystem).Caption) PS v$($PSVersionTable.PSVersion)"
} #begin
Process {
    Write-Verbose "[PROCESS] Creating password with length $length"
    -join (33..126 | Get-Random -count $length | foreach {$_ -as [char]} )
}
End {
    Write-Verbose "[END    ] Ending: $($MyInvocation.Mycommand)"
} #end
}

With subexpressions, I can include some useful information in my verbose output.

Subexpression output
Subexpression output (Image Credit: Jeff Hicks)


So if you are trying to nest some type of value or result and aren’t getting the results you expect, see if you need to use a subexpression. Once you get your head around this idea, I think you’ll use subexpressions often.
As with most PowerShell topics I cover, I encourage you to try them out on your own and don’t forget to read the associated PowerShell help topics.