Hello. In the previous lesson, you created PowerShell variables holding strings, numbers, Booleans, arrays, and hash tables. Those values are useful only once a script can test them: Is the account enabled? Is the department eligible? Is a required group already present?
This lesson introduces the operators that produce those answers. You will use comparisons for individual values, membership tests for collections such as group lists, and logical operators to combine several identity conditions into one clear Boolean result. The next lesson will use these results to control if, elseif, and switch decisions.
A condition is a question with a Boolean answer
A condition is an expression that evaluates to either $true or $false.
"Finance" -eq "Finance"
This returns:
True
In PowerShell, comparison operators are written as hyphenated words. This differs from many languages:
| Question | PowerShell operator | Example |
|---|---|---|
| Are two values equal? | -eq | $department -eq "Finance" |
| Are they different? | -ne | $status -ne "Disabled" |
| Is a number greater? | -gt | $failedAttempts -gt 5 |
| Greater or equal? | -ge | $ageInDays -ge 90 |
| Less than? | -lt | $retryCount -lt 3 |
| Less or equal? | -le | $licenseCount -le 1 |
Do not use = to ask a question. As you saw last time, = assigns a value:
$department = "Finance"
Use -eq to compare values:
$department -eq "Finance"
PowerShell uses > and < for redirection in many contexts, so use -gt and -lt for numerical comparisons.
Here is a small in-memory identity record like the hash table from the previous lesson:
$user = @{
UserPrincipalName = "jordan.lee@contoso.com"
Department = "Finance"
Enabled = $true
LicenseCount = 1
}
You can turn its attributes into explicit Boolean facts:
$isEnabled = $user["Enabled"] -eq $true
$isFinanceUser = $user["Department"] -eq "Finance"
$hasAtLeastOneLicense = $user["LicenseCount"] -ge 1
$isEnabled
$isFinanceUser
$hasAtLeastOneLicense
Each expression returns $true. At this stage, the script has only evaluated data. It has not enabled an account, assigned a license, or changed a group.
PowerShell 7 Tutorials for Beginners #6 : If, ElseIf, Else (Conditional Statements)
Watch “PowerShell 7 Tutorials for Beginners #6: If, ElseIf, Else” by JackedProgrammer for a visual introduction to PowerShell’s hyphenated comparison operators, containment tests, and case sensitivity.
Watch basic comparisons to see -eq, -ne, -lt, -le, -gt, and -ge used with values. Then continue with containment and case, focusing on why a collection belongs on the left of -contains and how a c prefix makes a comparison case-sensitive.
Comparing identity attributes safely
For a single value on the left, comparison operators yield a Boolean:
$user["Department"] -eq "Finance" # True
$user["Department"] -ne "HR" # True
$user["LicenseCount"] -gt 1 # False
$user["LicenseCount"] -le 1 # True
Keep the values’ intended types consistent. LicenseCount is a number, so compare it to a number, not a quoted string:
$user["LicenseCount"] -ge 1
PowerShell can sometimes convert types automatically, but the comparison can depend on which side has which type. In IAM scripts, avoid relying on that conversion. Validate and normalize incoming data first; then make comparisons between values with compatible types.
Text comparisons and case
By default, PowerShell string comparisons are generally case-insensitive:
"Finance" -eq "finance" # True
You can require case sensitivity with a c after the hyphen:
"Finance" -ceq "finance" # False
You may also see an i prefix, such as -ieq, to state case-insensitive intent explicitly.
Case sensitivity is not automatically “more secure.” It must match the target system’s rules. More importantly, do not authorize someone solely by a display name such as "Finance" or "VPN Users" when a stable identifier is available. Names can be renamed, duplicated, or formatted inconsistently. Later, when you work with directory objects, stable object IDs and immutable identifiers will be safer inputs for authorization logic.
Wildcard comparison with -like
Use -like when the right-hand side is a wildcard pattern, rather than an exact value.
$upn = "jordan.lee@contoso.com"
$upn -like '*@contoso.com' # True
$upn -like 'jordan.?ee@*' # True
$upn -like '*@fabrikam.com' # False
The most useful wildcard characters are:
*matches any number of characters.?matches exactly one character.
A tenant-suffix test can be helpful as an early routing check:
$isContosoUpn = $upn -like '*@contoso.com'
But this is not complete UPN or email validation. It merely tests whether the text ends in the chosen suffix. Later, you will use string operations and regular expressions for stronger attribute validation.
about_Comparison_Operators - PowerShell | Microsoft Learn
Microsoft Learn’s “about_Comparison_Operators” is the reference for the precise behavior of PowerShell comparisons, particularly the important difference between comparing a single value and comparing a collection.
In the “Equality operators” section, read the “-eq and -ne” subsection and then the “-gt, -ge, -lt, and -le” subsection. Notice how the behavior changes when the left side is a collection. Also read the object comparison caution: two separately created objects with similar-looking properties are not automatically equal. Then go to “Containment operators” and read both “-contains and -notcontains” and “-in and -notin.” Pay close attention to why containment differs from equality filtering.
Collections: equality filtering is not membership testing
This PowerShell behavior is important enough to treat as a rule of thumb.
Suppose a user has this set of required groups:
$requiredGroups = @(
"Finance-Users"
"VPN-Standard-Users"
"MFA-Required"
)
If an array appears on the left side of -eq, PowerShell filters the array and returns matching item or items:
$requiredGroups -eq "VPN-Standard-Users"
Output:
VPN-Standard-Users
That output is a string from the collection, not a guaranteed Boolean result. If nothing matches, PowerShell returns no matching output. If several items match, it returns several values.
This makes -eq useful for filtering, but it is not the clearest way to ask, “Does this group list contain this exact group?” For that question, use a membership operator.
-contains: collection first
-contains puts the collection on the left and the single item on the right:
$requiredGroups -contains "VPN-Standard-Users" # True
$requiredGroups -contains "Global-Admins" # False
It always returns a Boolean.
-contains asks about an exact collection member; it does not search for a substring:
$requiredGroups -contains "VPN" # False
If you need a pattern search, use -like instead:
$requiredGroups -like "VPN-*"
The latter returns matching collection items, so it is filtering behavior again rather than a direct Boolean membership test.
-in: item first
-in expresses the same membership relationship in the order that is often easier to read aloud:
"VPN-Standard-Users" -in $requiredGroups # True
"Global-Admins" -in $requiredGroups # False
These statements mean the same thing:
$requiredGroups -contains "MFA-Required"
"MFA-Required" -in $requiredGroups
Use whichever reads more naturally in the surrounding expression. A practical convention is:
- Use
-containswhen you are describing the collection. - Use
-inwhen you are describing one candidate item.
The negative forms are available too:
$requiredGroups -notcontains "Privileged-Role"
"Privileged-Role" -notin $requiredGroups
Use negative membership checks carefully. “The desired group is absent” is not automatically permission to add it; a later script must also account for eligibility, approval, separation-of-duties constraints, and dry-run safety.
Combining identity conditions with logical operators
Most access decisions require more than one fact. A user might need to be enabled, in a particular department, and assigned to a required baseline group.
The principal logical operators are:
| Operator | Result |
|---|---|
-and | $true only if both conditions are true |
-or | $true if at least one condition is true |
-xor | $true only if exactly one condition is true |
-not | Reverses a Boolean result |

-and: every requirement must hold
$isEligibleForFinanceAccess =
($user["Enabled"] -eq $true) -and
($user["Department"] -eq "Finance") -and
("Finance-Users" -in $requiredGroups)
The final result is $true only if all three requirements hold.
The parentheses make each condition visually distinct. They also protect you from mistakes as expressions become longer. In particular, -and, -or, and -xor have equal precedence and are evaluated from left to right, so do not rely on a reader remembering an implicit order.
-or: either condition can satisfy the rule
$hasElevatedSupportPath =
("Helpdesk-Tier2" -in $requiredGroups) -or
("Identity-Operations" -in $requiredGroups)
This might represent an eligibility check where either approved support group is sufficient. It does not mean that both groups should be assigned; it only describes the current condition.
-not: make absence explicit
$missingMfaGroup = -not ("MFA-Required" -in $requiredGroups)
Parenthesize the expression following -not. It is immediately clear that the script first checks membership, then reverses the result.
-xor: exactly one state should be present
Exclusive OR is useful for detecting inconsistent migration states. For example, perhaps an account should belong to exactly one of an old or new access group:
$inLegacyGroup = "VPN-Legacy-Users" -in $requiredGroups
$inStandardGroup = "VPN-Standard-Users" -in $requiredGroups
$hasExactlyOneVpnAssignment = $inLegacyGroup -xor $inStandardGroup
This returns $true when the account is in one group but not both. It returns $false if the account is in neither group or is in both, both of which may need investigation.
about_Logical_Operators - PowerShell | Microsoft Learn
Read Microsoft Learn’s “about_Logical_Operators” to consolidate the exact Boolean meaning of AND, OR, exclusive OR, and NOT, with special attention to short-circuit evaluation.
Read the “Long description” and then the “Examples” section in full. Focus first on short-circuit evaluation, then compare the examples for -and, -or, -xor, and -not. Note the warning that -and, -or, and -xor have equal precedence, so grouping related conditions with parentheses is good script hygiene.
Short-circuit evaluation and readable conditions
PowerShell evaluates only as much of an -and or -or expression as necessary.
For -and, if the first condition is false, the complete expression must be false. PowerShell does not need to evaluate the remaining condition.
For -or, if the first condition is true, the complete expression must be true. PowerShell does not need to evaluate the remaining condition.
That behavior is useful when the first test guards the second:
$upn = $user["UserPrincipalName"]
$hasContosoUpn =
($null -ne $upn) -and
($upn -like '*@contoso.com')
Placing $null on the left of an equality comparison is a PowerShell best practice, especially when a variable might contain an array. It makes your intent unambiguous: test whether the value itself is absent before doing more work with it.
For a real IAM script, a single all-in-one expression can become difficult to audit. Prefer named Boolean facts:
$isEnabled = $user["Enabled"] -eq $true
$isFinanceUser = $user["Department"] -eq "Finance"
$hasVpnGroup = "VPN-Standard-Users" -in $requiredGroups
$hasMfaGroup = "MFA-Required" -in $requiredGroups
$isReadyForVpnReview =
$isEnabled -and
$isFinanceUser -and
$hasVpnGroup -and
$hasMfaGroup
This structure helps in three ways:
- Each business rule has a name that can be reviewed by an IAM teammate.
- You can inspect individual facts when troubleshooting.
- The final decision is separated from any future action that changes a directory.
A final diagnostic comparison can check the type of an input when a script receives uncertain data:
$user["LicenseCount"] -is [int]
This returns $true only when LicenseCount is an integer. Type checks can help reveal malformed imported data, though later lessons will focus more directly on input validation and normalization.
Key takeaways
- Use
-eq,-ne,-gt,-ge,-lt, and-leto compare individual identity values. - Use
-likefor wildcard patterns, but do not mistake a simple suffix check for complete UPN validation. - When a collection is on the left of
-eq, PowerShell returns matching items rather than a Boolean membership result. - Use
-containsor-into ask whether a single group, role, or identifier is present in a collection. - Combine Boolean conditions with
-and,-or,-xor, and-not; parenthesize component conditions for clarity. - Build named Boolean facts before a final decision. Evaluating eligibility is distinct from making a state-changing IAM operation.
Next, you will use these Boolean expressions in if, elseif, and switch statements to select an appropriate access-processing path.
Can't find a good explanation? Sign up and we'll make it for you
Sign up