Essential PowerShell: Know your operator and enclosure precedence

PowerShell version 1 comes with a lot of operators, and the list becomes even longer in version 2 with cool new operators like -split and -join.  Whether you’re writing scripts or using PowerShell interactively, dealing with multiple operators in an expression that possibly contains different enclosures (brackets, quotation marks, etc.) as well can be very tricky.  It is very important to know how the PowerShell interpreter processes the expression so that you can get your expressions right the first time or, if you’re not so lucky, so that you can identify the problem in your expressions later and fix them. 

Recently there have been several posts on the forums where the problem has been a lack of understanding of the operator and enclosure precedence in PowerShell.  That’s not too surprising because the precedence order used by the PowerShell interpreter doesn’t seem to be documented at this time.  You can find the precedence order of arithmetic operators through the about_arithmetic_operators help file, you can find out some precedence details for specific operators in various operator help files, and you can find out the precedence of command types through the about_command_precedence help file, but that’s about it.  There is no single help file that documents the overall operator and enclosure precedence.  It doesn’t seem to be listed in any of the PowerShell books I have read either. 

Fortunately through some ad hoc experimentation and through some reading of the help documentation that does exist it is possible to figure out how all of this works.  I’ve gone through that exercise recently and the resulting table of operator and enclosure precedence is below.  Before getting to the table though there are a few important things I should mention, as follows: 

  1. Any items that share the same row in the table have the same precedence and are evaluated from left to right when adjacent within an expression unless otherwise indicated.
  2. The intent of this table is to identify a precedence that can be used to create or troubleshoot more complicated expressions without a lot of guesswork.  It is not intended to explain what each of the operators are and how you can use them (although to help understand expressions you might have to deal with I do mention a few details about some operators that function differently than the majority of operators in PowerShell).
  3. If you want to learn about the individual operators and see examples showing how they can be used I recommend you consult the about_operators help file and all of its related files.

With that out of the way, here is the operator and enclosure precedence table for PowerShell:

[] Type enclosures
Any character placed inside of these enclosures is treated as part of a literal type name.  The contents are not evaluated like an expression would be.
” “ Double-quoted string enclosures
‘ ‘ Single-quoted string enclosures
@” “@ Double-quoted here-string enclosures
@’ ‘@ Single-quoted here-string enclosures
 
{} Script block enclosures
 
() Nested expression enclosures
@() Array subexpression enclosures
$() Subexpression enclosures
 
. Property dereference operator
:: Static member operator
 
[] Index operator
 
[int]
[string[]]
etc.
Cast operators
Multiple adjacent operators in this row have a right-to-left evaluation.
-split (unary) Split operator (unary)
-join (unary) Join operator (unary)
These operators can be used as unary or binary operators.  Their precedence varies depending on how they are used.
, Comma operator
This operator is the array element separator.  It can be used as an unary or binary operator.
++ Increment operator
– – Decrement operator
These unary operators can be used before or after a variable or property.  When used before the variable or property (as a prefix operator), the value is incremented or decremented first and then the result is passed into the expression in which it is contained.  When used after the variable or property (as a postfix operator), the value is passed into the expression in which it is contained and then the variable or property is immediately incremented or decremented.
Negate operator
-not Not operator
! Not operator
-bnot Bitwise not operator
Multiple adjacent operators in this row have a right-to-left evaluation.
.. Range operator
 
-f Format operator
 
* Multiplication operator
/ Division operator
% Modulus operator
 
+ Addition operator
Subtraction operator
 
-split
-isplit
-csplit (binary)
Split operator (binary)
-join (binary) Join operator (binary)
-is Type is operator
-isnot Type is not operator
-as Type as operator
-eq
-ieq
-ceq
Equal to operator
-ne
-ine
-cne
Not equal to operator
-gt
-igt
-cgt
Greater than operator
-ge
-ige
-cge
Greater than or equal to operator
-lt
-ilt
-clt
Less than operator
-le
-ile
-cle
Less than or equal to operator
-like
-ilike
-clike
Like operator
-notlike
-inotlike
-cnotlike
Not like operator
-match
-imatch
-cmatch
Match operator
-notmatch
-inotmatch
-cnotmatch
Not match operator
-contains
-icontains
-ccontains
Contains operator
-notcontains
-inotcontains
-cnotcontains
Does not contain operator
-replace
-ireplace
-creplace
Replace operator
With the exception of the join operator and the type operators (-is, -isnot, and –as), each of the operators in this row has a case-sensitive and an explicit case-insensitive variant.  Case-sensitive variants are prefixed with c (e.g. -ceq) and case-insensitive variants are prefixed with i (e.g. –ireplace).
-band Bitwise and operator
-bor Bitwise or operator
-bxor Bitwise exclusive or operator
 
-and Logical and operator
-or Logical or operator
-xor Logical exclusive or operator
 
. Dot-sourcing operator
& Call operator
Unary operators that are only valid at the beginning of an expression, a nested expression, or a subexpression.
= Assignment operator
+= Assignment by addition operator
-= Assignment by subtraction operator
*= Assignment by multiplication operator
/= Assignment by division operator
%= Assignment by modulus operator
Multiple adjacent operators in this row have a right-to-left evaluation.

Since this table is created through experimentation and through snippets of information about precedence that I was able to find in the help files, it may not be entirely accurate.  If you find any problems with the precedence information provided here, please let me know and I’ll update this table accordingly. 

[Update 09-July-2009: Fixed table formatting, added an index operator, added all case-sensitive and case-insensitive variants and adjusted the precedence for the property dereference and static member operators.] 

Thanks, 

Kirk out. 

Share this post:

11 thoughts on “Essential PowerShell: Know your operator and enclosure precedence

  1. Great, I was always wondering, what’s the precedence of operators. It is very well defined e.g. for C#, but I haven’t found anything for PowerShell.
    You saved my time!

  2. There’s a subtle gotcha with the bitwise and logical operators.

    AND operators should have a higher precedence than OR operators (much like * happens before +). However, in PowerShell v2.0 (and probably v1.0) -band and -bor are evaluated left to right.

    Compare this PowerShell snippet:

    PS> 1 -bor 0 -band 0
    0

    …with Python:

    >>> 1 | 0 & 0
    1

    When in doubt, use parentheses!

    1. Nice catch, I didn’t pick up that one. You’re right about parentheses though, I use them simply because it eliminates the guesswork for someone reading the script later. Thanks for sharing!

      Kirk out.

    2. The same is true for -and and -or
      PS> $true -or $true -and $false
      False
      PS> $true -or ($true -and $false)
      True

Leave a comment