PowerShell
Step 8. Conditionals and Loops — Making the Computer Judge and Toil
Level 0 — Understanding How to Operate a Computer and How It’s Structured | Difficulty ★★☆☆☆ | Estimated time: 3 hours
Prerequisites: Step 7 complete. Use Windows PowerShell 5.1 or PowerShell 7 on Windows. No internet connection needed.
- What you need: a Windows PC, PowerShell.
- Safety: use small fictional arrays and a log in a new dedicated folder. Do not apply repeated operations to existing files or real accounts.
- Caution: the comparison symbols are unusual. PowerShell uses
-gtinstead of>, and-eqinstead of=. It feels awkward, but the rules are simple — get it wrong once and it becomes familiar fast.
Step 4 searched logs and Step 7 stored results. Now turn “warn at a threshold” and “inspect each line” into code. Runtime depends on the amount of data and the work performed. Use small fictional inputs today so you can calculate the expected answer and compare it with the output.
1. Learning Objectives
By the end of this unit, you can:
- Turn “if ~ then” judgments into code with
if/else - Sweep an entire list automatically with
foreach, and repeat a fixed number of times withfor - Combine condition + loop to build “pick out only what matches (filtering)”
- Complete the even-number-sum script for 1–100 with the accumulation pattern (totals and counts)
2. Background Knowledge — Today’s Tools and Concepts
This section’s Tools at a Glance
| Category | Details |
|---|---|
| Language/environment | Windows PowerShell 5.1 / PowerShell 7 — conditions and loops |
| This section’s syntax | if (condition) { } else { }, foreach ($x in $list) { }, for ($i=1; $i -le N; $i++) { } |
| Comparison operators | -eq -ne -gt -lt -ge -le (plus the remainder %) |
| Concepts you need | control flow, conditional expressions (true/false), loops, the accumulation pattern |
If variables are the alphabet, conditionals and loops are grammar. You’re already using both concepts in daily life — “if it rains, take an umbrella” (condition), “wait until the elevator arrives” (repetition). Today is merely the practice of moving these into code.
2-1. Control Flow — Dams and Channels on a Stream
A program flows top to bottom by default. This flow is called control flow. This section’s two tools are devices attached to that flow:
- Conditional (if) — a sluice gate that splits the flow: “if this condition is true, go to A; otherwise, to B”
- Loops (foreach, for) — a circulating channel that runs the same stretch over many rounds
Python, C, and JavaScript also use conditions and repetition. These concepts transfer, but truth conversion, scope, and syntax differ between languages; do not assume identical behavior.
2-2. Conditional Expressions — Questions Answered True/False
If interprets its condition as true or false. The scalar numeric comparisons below return Boolean values, but a collection on the left can return matching elements. Not every comparison expression outputs True or False.
$a -gt 5 — “is a greater than 5?” If a is 7, true; if 3, false. Here’s PowerShell’s comparison operator table:
| Operator | Meaning | Example | Result |
|---|---|---|---|
-eq |
equals | $a -eq 5 |
true if a is 5 |
-ne |
not equal | $a -ne 5 |
true if a is not 5 |
-gt |
greater than | $a -gt 5 |
true if a is greater than 5 (for example, 5.5) |
-lt |
less than | $a -lt 5 |
true if a is less than 5 (for example, 4.5) |
-ge |
greater than or equal | $a -ge 5 |
true if a is 5 or more |
-le |
less than or equal | $a -le 5 |
true if a is 5 or less |
Caution: = assigns; -eq compares for equality. > redirects output, so use -gt for greater-than comparison. Compare the boundary, a fractional value, and a collection:
5 -gt 5 5 -ge 5 5.5 -gt 5 @(3, 7, 2, 8) -ge 5
False True True 7 8
5.5 is also greater than 5. The final outputs, 7 and 8, are selected collection elements. String -eq comparisons are case-insensitive by default; use -ceq when case matters.
2-3. The Two Faces of Repetition
Two kinds of repetition are used depending on the situation:
- foreach — “for each item in the list, one at a time” (calling roll down a member roster)
- for — “a set number of times” (run 10 laps)
Foreach is natural for walking a collection; for is useful when you control initialization, continuation, and updates. For does not guarantee a fixed number of iterations: a false initial condition gives zero, while a condition that never becomes false can keep running. This section’s examples have finite bounds.
3. Follow Along
Before you begin. Predict a small loop by hand before expanding its range. Check zero, one, and several input items.
3-1. First Conditional — if
$a = 7
if ($a -gt 5) { "Greater than 5" } else { "5 or less" }
Greater than 5
How to read the output: since $a is 7, “is it greater than 5?” is true → the { "Greater than 5" } side ran.
Structural breakdown: if (conditional expression) { what to do when true } else { what to do when false }. The curly braces { } are “bundles of things to do.”
Why do this: now change $a to 3 and run it again:
$a = 3
if ($a -gt 5) { "Greater than 5" } else { "5 or less" }
This time 5 or less comes out. Exactly 5 also takes this else branch. Same code, different behavior depending on the value — that’s the power of conditionals. Your code has started reacting to situations on its own.
3-2. if Without else, and a Real-World Condition
When there’s nothing to do on false, omit the else:
$failCount = 7
if ($failCount -ge 5) { "Warning: too many login failures!" }
Warning: too many login failures!
Why do this: the example warns at 5 or more. With $failCount set to 2, this if emits nothing. Five is a chosen threshold for fictional data, not a real intrusion verdict. Operational rules also need an observation window, user/device scope, and treatment of missing data.
Predict first: if you use
-gtinstead of-ge, as inif ($failCount -gt 5) { ... }, will the warning appear when failures are exactly 5? (Answer: no.-gtmeans “greater than,” so 5 isn’t included. How behavior changes at the boundary value — exactly at the threshold number — is a classic seat of programming mistakes. Put in 5 yourself and check.)
3-3. foreach — Automatically Sweeping a List
Let’s bring back the array from Step 7:
$members = @("Kim", "Lee", "Park")
foreach ($m in $members) { "Hello, $m!" }
Hello, Kim! Hello, Lee! Hello, Park!
How to read the output: it ran once per list item, three times total.
Structural breakdown: foreach ($m in $members) — “pull out one at a time from the members list, calling it m” — and run the inside of { }. $m changes each round: first round Kim, second round Lee, third round Park.
Why do this: in real work this pattern transforms like this — “pull files one by one from a file list and inspect,” “pull users one by one from a user list and check permissions.” Whether it’s 100 items or a million, the code stays the same one line.
3-4. for — Repeating a Fixed Number of Times
for ($i = 1; $i -le 5; $i++) { "Number $i" }
Number 1 Number 2 Number 3 Number 4 Number 5
Structural breakdown — the parentheses hold three pieces:
$i = 1— starting value (start with i at 1)$i -le 5— condition to keep going (repeat only while i is 5 or less)$i++— what to do at the end of each round (add 1 to i —++is the symbol for “increment by 1”)
Why do this: use it for bounded work such as summing 1–100 or producing numbered test data. This lesson works with console output and newly created local practice files.
3-5. Condition + Loop Combined — Filtering
Now let’s combine the two. “From a list, pick out only what matches the condition”:
$scores = @(85, 42, 91, 55, 78)
foreach ($s in $scores) {
if ($s -ge 60) { "$s points: Pass" }
}
85 points: Pass 91 points: Pass 78 points: Pass
How to read the output: 42 and 55 didn’t meet the condition (60 or more), so they were filtered out. The loop ran over everything, and the conditional selected what to print.
Why do this: “sweep everything, process only what matches” — that’s exactly how log analysis works. Tens of thousands of lines driven through a foreach, hooked by a condition like “contains ERROR.” This section’s 5 lines are that principle in miniature.
3-6. The Grand Synthesis — Summing the Even Numbers
Let’s do this section’s completion-criteria assignment together: sum only the even numbers from 1 to 100.
First, how to tell an even number: a number whose remainder when divided by 2 is 0 is even. The remainder operator is %. If $n % 2 is 0, it’s even.
$sum = 0
for ($i = 1; $i -le 100; $i++) {
if ($i % 2 -eq 0) { $sum = $sum + $i }
}
$sum
2550
Line-by-line explanation:
$sum = 0— prepare the box that will hold the total at 0 (an empty pocket)- Repeat from 1 to 100, and
$i % 2 -eq 0— if it divides evenly (if it’s even)$sum = $sum + $i— add that number into the pocket. The right side is calculated first, and the result goes back into $sum- Final output: 2550 (2+4+6+…+100, illustrative result)
Why do this: “accumulation” (stacking up a value while repeating) is a basic pattern of data processing. Total error count, total bytes transferred, average calculation — they all take this shape.
3-7. Real-World Connection — Merging with Step 4’s Log
Let’s connect, as a taste, how this section’s techniques are used on an actual log file. First, make a test log (same trick as Step 4’s generator):
$looplab = Join-Path $HOME ('infosec-step08-' + [guid]::NewGuid().ToString('N'))
New-Item -ItemType Directory -Path $looplab -ErrorAction Stop
Set-Location -LiteralPath $looplab
pwd
1..20 | ForEach-Object {
if ($_ % 3 -eq 0) { "ERROR number $_" }
else { "OK number $_" }
} | Set-Content scanlog.txt -Encoding UTF8
Check the new folder path. Rerunning the generator rebuilds the same scanlog.txt with twenty lines. Continue in that session and folder, explicitly read UTF8, and count matching lines:
$lines = @(Get-Content scanlog.txt -Encoding UTF8)
$errCount = 0
foreach ($line in $lines) {
if ($line.Contains("ERROR")) { $errCount = $errCount + 1 }
}
"Out of $($lines.Count) lines total, $errCount errors"
Out of 20 lines total, 6 errors
Line-by-line explanation:
Get-Content— returns lines that@(...)collects into an array. Twenty lines give twenty elements; wrapping also handles zero-line and one-line files consistently$errCount = 0— prepare the accumulation pocket (subsection 3-6’s pattern)foreach— walk the 20 lines one by one$line.Contains("ERROR")— a conditional expression asking “does this line contain the text ERROR?” True if it does- Final report — remember the
$($lines.Count)notation inside double quotes?
Why do this: this small example reads a file, iterates over lines, counts matches, and reports a summary. Contains(“ERROR”) is a case-sensitive substring test: lowercase error differs, while NO_ERROR also contains ERROR. The count is matching lines, not automatically distinct errors or security incidents. Larger systems also need structured parsing, deduplication, and memory/streaming considerations.
4. Missions & Exercises
Mission — Login Watch Script (Miniature)
The following is a fictional array of one user’s failure counts by time slot. No login requests are sent to a real account or server. Practice applying conditions and summing the given counts.
$failLog = @(0, 1, 0, 3, 9, 12, 2, 0)
Tasks:
- Walk this list with foreach, and for time slots with 5 or more failures, print
"Danger: N failures" - After the loop ends, print the total of all failures as
"Total failures: M"(use the accumulation pattern)
Exercises
Exercise 1. Explain the difference between $a = 5 and $a -eq 5.
Exercise 2. What’s the criterion for choosing between foreach and for?
Exercise 3. Write code that prints only values 5 or greater from @(3, 7, 2, 8).
Exercise 4. I ran an accumulation-pattern script twice in a row and the total doubled. Cause and fix?
Answers & completion criteria · expand/collapse
5. Model Answers & Completion Criteria
Mission Model Answer
When text immediately follows a variable, use $($variable) or ${variable} to make its boundary explicit.
$failLog = @(0, 1, 0, 3, 9, 12, 2, 0)
$sum = 0
foreach ($f in $failLog) {
if ($f -ge 5) { "Danger: $f failures" }
$sum = $sum + $f
}
"Total failures: $sum"
Expected output (illustrative result):
Danger: 9 failures Danger: 12 failures Total failures: 27
How to verify: perfect if “Danger” appears on exactly two lines and the total is 27. If Danger appears on three or more lines, recheck the condition. If the total differs, you very likely left out the $sum initialization (= 0).
Deeper dive: if you change the condition to -gt 5, which lines disappear? Predict with your reasoning, then check. (Answer: none. Both 9 and 12 are greater than 5, so the result is the same. Instead, compare -ge 9 vs -gt 9 with the threshold raised to 9 — then the boundary-value difference becomes unmistakable.)
Exercise Answers
Answer 1. $a = 5 is assignment — the act of putting 5 into a box. $a -eq 5 is comparison — the question “is a equal to 5?”, answered true/false. Writing = in a condition slot is the beginner’s greatest bug.
Answer 2. If the list you need to handle already exists, foreach (“for each item in the list, one at a time”); if a count or numeric range is fixed, for (“from 1 to 100”).
Answer 3.
$nums = @(3, 7, 2, 8)
foreach ($n in $nums) {
if ($n -ge 5) { $n }
}
The output is 7 and 8. “Sweep everything, process only what matches” — the filtering pattern.
Answer 4. You may have rerun the accumulating part without initialization or duplicated the input file. Check prior values in the same session and rerun the complete block including $sum = 0, as well as the complete synthetic-log generator. Resetting the sum inside every iteration prevents accumulation.
Completion Checklist
- [ ] I can distinguish and use comparison operators like
-eq,-gt,-lt - [ ] I can explain the difference between
=and-eq - [ ] I can write branching by condition with if/else
- [ ] I can walk every item of an array with foreach
- [ ] I can write count-based repetition with for
- [ ] I can compute totals with the accumulation pattern
- [ ] Mission: I completed the login watch script (miniature)
6. Common Pitfalls & Fixes
Wall 1. I keep confusing = and -eq
Use -eq for equality and appropriate alternatives such as -gt or -ge for other comparisons. if ($a = 5) assigns a value and then tests that value; it is not comparison. Five converts to true, zero to false. The nonempty string “False” converts to true and differs from Boolean $false.
Wall 2. The loop never runs, or never ends
Symptom: typed a for loop and got no output, or it won’t stop.
Cause: the condition is often written backwards. for ($i=1; $i -ge 100; $i++) is false the moment it starts, so it never runs. The reverse — a condition that’s true forever — loops infinitely.
Fix: if it won’t stop, interrupt with Ctrl + C. Then check just two things: “does the starting value satisfy the condition?” and “does the condition move toward false each round?”
Wall 3. The curly braces { } don’t pair up
A >> prompt means input is incomplete. Quotes, parentheses, braces, or a trailing pipe may be responsible. Finish the intended structure or cancel current input with Ctrl+C. Interrupting a running loop does not undo file operations already performed.
Wall 4. The total is weirdly large, or 0
Initialize the total once before the loop. Resetting it inside each iteration can leave only the last value; rerunning only the accumulation portion can double an earlier total. Also check whether the input file was generated twice. Running the corrected complete blocks should again yield 2550 and a 20-line log with 6 ERROR lines.
Wall 5. I get confused at the boundary of -gt and -ge
Symptom: I wanted “5 or more,” but it doesn’t trigger at 5.
Cause: you used -gt (greater than), so 5 was excluded. “Or more” is -ge; “greater than” is -gt.
Fix: test by putting in the threshold number itself (boundary-value testing). Decide “what should happen at exactly 5?” first, then pick the code — mistakes shrink.
7. Summary
This section’s Two Pillars
| Tool | Purpose | Form |
|---|---|---|
| if / else | fork by condition | if (condition) { A } else { B } |
| foreach | sweep an entire list | foreach ($x in $list) { ... } |
| for | repeat a fixed count | for ($i=1; $i -le N; $i++) { ... } |
Comparison Operator Cheat Sheet
-eq (equals) -ne (not equal) -gt (greater than) -lt (less than) -ge (or more) -le (or less) — and = is assignment, % is remainder.
This section’s Pattern Card
| Pattern | Code skeleton | Real-world use |
|---|---|---|
| Threshold alert | if ($n -ge threshold) { warn } |
failed-login alerts |
| Filtering | if inside foreach | extracting only anomalies from logs |
| Accumulation | $sum = 0, then add while looping |
totals and grand totals |
Instincts That Matter More Than Commands
Intrusion detection rules, log analysis, alerting systems — all of them stand on this section’s “condition + loop.” Being able to write “warn at 5 or more failures” as code means you’re no longer a person who reads logs with your eyes but a person who builds programs that inspect logs.
Remember too that the same tools serve both offense and defense. An attacker uses for to try password candidates one by one (brute force — you’ll practice this yourself in a lab environment in Level 2); a defender uses foreach to sweep connection logs for anomalies. Firewall rules and access controls are, in the end, giant collections of if statements.
Once every box is checked, Step 8 is complete.
Practice verification record
Historical record. The dated record below describes the earlier lesson version. The current instructions include subsequent editorial corrections; that record does not certify every revised example.
On 2026-09-10, both language editions were executed separately using Windows PowerShell 5.1.26100.9444 and PowerShell 7.6.5. Checks covered the boundary 5, fractional comparisons, even sum 2550, a repeatable twenty-line log with six ERROR lines, and a failure total of 27 with two warning lines. The original Korean variable-suffix bug was reproduced before correction. All file operations used new practice folders.
Microsoft: Comparison operators · If · For · String.Contains · Quoting rules
ONE STEP FURTHER
Finished this lesson?
Check the completion criteria, then mark your progress.