PowerShell’s logical operators are -and, -or, -xor, -not and !. They combine or flip True/False conditions, mostly inside if statements and Where-Object filters:
$age = 25
$state = 'TX'
if ($age -ge 21 -and $state -eq 'TX') { 'Both conditions are true' }
if ($state -eq 'CA' -or $state -eq 'TX') { 'At least one condition is true' }
if (-not ($state -eq 'NY')) { 'The condition is false, so -not makes it true' }
Output:
Both conditions are true
At least one condition is true
The condition is false, so -not makes it true
! is just a shorter spelling of -not. I ran every example in PowerShell 7.6 and Windows PowerShell 5.1, with the same results except the last section.
What each logical operator returns
This table runs every combination of two values through -and, -or and -xor:
'{0,-7} {1,-7} {2,-7} {3,-7} {4}' -f 'A', 'B', '-and', '-or', '-xor'
foreach ($a in $true, $false) {
foreach ($b in $true, $false) {
'{0,-7} {1,-7} {2,-7} {3,-7} {4}' -f $a, $b, ($a -and $b), ($a -or $b), ($a -xor $b)
}
}
Output:
A B -and -or -xor
True True True True False
True False False True True
False True False True True
False False False False False
-and needs both sides true, -or needs at least one, and -xor needs exactly one. Microsoft lists them in about_Logical_Operators.
-and and -or stop early (short-circuit)
PowerShell skips the right side when the left side already decides the answer. Only the third call runs here:
$script:checked = @()
function Test-Server {
param([string]$Name)
$script:checked += $Name
$true
}
$null = $false -and (Test-Server -Name WEB01)
$null = $true -or (Test-Server -Name WEB02)
$null = $true -and (Test-Server -Name WEB03)
"Test-Server ran for: $($script:checked -join ', ')"
Output:
Test-Server ran for: WEB03
That lets you guard a slow or risky check, like $server -and (Test-Connection $server -Quiet), so it only runs when the first part is true.
Operator precedence: -and doesn’t win over -or
In C# and JavaScript, && binds tighter than ||. In PowerShell, -and and -or have the same precedence and run left to right, which trips up a lot of people:
$isAdmin = $true
$isManager = $true
$isLocked = $true
"Without parentheses: $($isAdmin -or $isManager -and -not $isLocked)"
"With parentheses: $($isAdmin -or ($isManager -and -not $isLocked))"
Output:
Without parentheses: False
With parentheses: True

PowerShell read the first line as (admin or manager) and not locked. Whenever you mix -and and -or, add parentheses. The operator precedence table shows -and, -or and -xor on the same row.
The -not and ! operators
-not binds tighter than -eq
-not applies to the value right next to it, not to the whole comparison:
"-not 5 -eq 3 = $(-not 5 -eq 3)"
"-not (5 -eq 3) = $(-not (5 -eq 3))"
"!`$false = $(!$false)"
Output:
-not 5 -eq 3 = False
-not (5 -eq 3) = True
!$false = True
In the first line, PowerShell computed -not 5, which is False, and then compared False with 3. Wrap the comparison in parentheses.
Negate a command like Test-Path
Commands need their own parentheses. Without them, !Test-Path is read as a command named “!Test-Path”, and -not Test-Path is a syntax error:
$path = 'C:\psfaqs\Archive2026'
if (!(Test-Path -Path $path)) { "Missing: $path" }
if (-not (Test-Path -Path $path)) { 'Same check with -not' }
Output (the folder doesn’t exist):
Missing: C:\psfaqs\Archive2026
Same check with -not
Test-Path in PowerShell has more Test-Path examples.
What counts as true and false
Logical operators turn any value into True or False first. Some results surprise people, especially text:
$values = [ordered]@{
"'False' (text)" = 'False'
"'0' (text)" = '0'
"' ' (a space)" = ' '
'0' = 0
"'' (empty)" = ''
'$null' = $null
'@()' = @()
'@(0)' = @(0)
'@(0, 0)' = @(0, 0)
}
foreach ($name in $values.Keys) {
'{0,-16} counts as {1}' -f $name, [bool]$values[$name]
}
Output:
'False' (text) counts as True
'0' (text) counts as True
' ' (a space) counts as True
0 counts as False
'' (empty) counts as False
$null counts as False
@() counts as False
@(0) counts as False
@(0, 0) counts as True

So if ('False') runs, and a CSV value of “0” counts as true. Convert first with [int] or [bool]::Parse(). Microsoft explains these rules in about_Booleans.
Combine conditions in Where-Object
Inside a Where-Object script block, -and and -not work on each object’s properties:
$orders = @(
[pscustomobject]@{ Id = 1001; State = 'TX'; Total = 250.00; Paid = $true }
[pscustomobject]@{ Id = 1002; State = 'CA'; Total = 980.50; Paid = $false }
[pscustomobject]@{ Id = 1003; State = 'TX'; Total = 1200.00; Paid = $false }
[pscustomobject]@{ Id = 1004; State = 'FL'; Total = 75.25; Paid = $true }
)
$orders | Where-Object { $_.State -eq 'TX' -and -not $_.Paid } |
ForEach-Object { 'Unpaid Texas order {0}: {1:C}' -f $_.Id, $_.Total }
Output:
Unpaid Texas order 1003: $1,200.00
Where-Object covers the short syntax, which can’t combine conditions, and the script block form used here.
&& and || in PowerShell 7
PowerShell 7 added && and ||, but they’re pipeline chain operators, not logical ones. They check whether the previous command succeeded, not whether it returned True:
Test-Path -Path C:\psfaqs\NoSuchFolder && 'This still runs'
Get-Item -Path C:\psfaqs\NoSuchFolder -ErrorAction SilentlyContinue || 'Get-Item failed, so || ran this'
Output in PowerShell 7:
False
This still runs
Get-Item failed, so || ran this

In Windows PowerShell 5.1, the same line fails with “The token ‘&&’ is not a valid statement separator in this version.” Use -and and -or in conditions. Microsoft covers the chain operators in about_Pipeline_Chain_Operators.
Frequently Asked Questions
What are the logical operators in PowerShell?
-and, -or, -xor, -not and !. The ! operator is a shorter form of -not.
Does -and have higher precedence than -or in PowerShell?
No. They have the same precedence and run left to right, so $a -or $b -and $c means ($a -or $b) -and $c. Use parentheses.
How do I use not with Test-Path?
Wrap the command in parentheses: if (-not (Test-Path $path)) or if (!(Test-Path $path)).
What’s the difference between -and and && in PowerShell?
-and combines True/False values. && runs the next command only if the previous one succeeded, and it exists only in PowerShell 7.
Why is the string ‘False’ true in PowerShell?
Any non-empty string counts as true. Convert it first with [bool]::Parse('False'), which returns False.
Other operators and conditions worth knowing:
Bijay Kumar is an esteemed author and the mind behind PowerShellFAQs.com, where he shares his extensive knowledge and expertise in PowerShell, with a particular focus on SharePoint projects. Recognized for his contributions to the tech community, Bijay has been honored with the prestigious Microsoft MVP award. With over 15 years of experience in the software industry, he has a rich professional background, having worked with industry giants such as HP and TCS. His insights and guidance have made him a respected figure in the world of software development and administration. Read more.