Create your own
Lesson illustration

Expressing Identity Conditions with Operators

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:

QuestionPowerShell operatorExample
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 -contains when you are describing the collection.
  • Use -in when 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:

OperatorResult
-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
-notReverses a Boolean result
Three flowcharts show PowerShell’s AND, OR, and NOT logic: AND requires both conditions to be true, OR accepts either true condition, and NOT reverses a condition’s result. The AND and OR charts also depict when the second condition need not be evaluated.

-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:

  1. Each business rule has a name that can be reviewed by an IAM teammate.
  2. You can inspect individual facts when troubleshooting.
  3. 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 -le to compare individual identity values.
  • Use -like for 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 -contains or -in to 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