Skip to content

Commit 74f2cd4

Browse files
Refresh chapter 6 of ps101 (#11901)
* Refresh chapter 6 of ps101 * Apply suggestions from code review Co-authored-by: Sean Wheeler <[email protected]> * Apply suggestions from code review Co-authored-by: Sean Wheeler <[email protected]> --------- Co-authored-by: Mike F. Robbins <[email protected]> Co-authored-by: Sean Wheeler <[email protected]>
1 parent 9bee248 commit 74f2cd4

File tree

1 file changed

+117
-116
lines changed

1 file changed

+117
-116
lines changed
Lines changed: 117 additions & 116 deletions
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,43 @@
11
---
22
description: PowerShell provides methods to create loops, make decisions, and logically control the flow of code in scripts.
33
ms.custom: Contributor-mikefrobbins
4-
ms.date: 12/08/2022
4+
ms.date: 3/20/2025
55
ms.reviewer: mirobb
66
title: Flow control
77
---
8+
89
# Chapter 6 - Flow control
910

1011
## Scripting
1112

12-
When you move from writing PowerShell one-liners to writing scripts, it sounds a lot more
13-
complicated than it really is. A script is nothing more than the same or similar commands that you
14-
would run interactively in the PowerShell console, except they're saved as a `.PS1` file. There are
15-
some scripting constructs that you may use such as a `foreach` loop instead of the `ForEach-Object`
16-
cmdlet. To beginners, the differences can be confusing especially when you consider that `foreach`
17-
is both a scripting construct and an alias for the `ForEach-Object` cmdlet.
13+
When you move from writing PowerShell one-liners to writing scripts, it sounds more complicated than
14+
it is. A script is nothing more than the same or similar commands you run interactively in the
15+
PowerShell console, except you save them as a `.PS1` file. There are some scripting constructs that
16+
you might use, such as a `foreach` loop instead of the `ForEach-Object` cmdlet. The differences can
17+
be confusing for beginners when considering that `foreach` is both a language keyword and an
18+
alias for the `ForEach-Object` cmdlet.
1819

1920
## Looping
2021

21-
One of the great things about PowerShell is, once you figure out how to do something for one item,
22-
it's almost as easy to do the same task for hundreds of items. Simply loop through the items using
23-
one of the many different types of loops in PowerShell.
22+
One of the best aspects of PowerShell is its scalability. Once you learn how to perform a task for a
23+
single item, applying the same action to hundreds of items is almost as straightforward. Loop
24+
through the items using one of the different types of loops in PowerShell.
2425

2526
### ForEach-Object
2627

27-
`ForEach-Object` is a cmdlet for iterating through items in a pipeline such as with PowerShell
28+
`ForEach-Object` is a cmdlet for iterating through items in a pipeline, such as with PowerShell
2829
one-liners. `ForEach-Object` streams the objects through the pipeline.
2930

30-
Although the **Module** parameter of `Get-Command` accepts multiple values that are strings, it only
31-
accepts them via pipeline input by property name or via parameter input. In the following scenario,
32-
if I want to pipe two strings by value to `Get-Command` for use with the **Module** parameter, I
33-
would need to use the `ForEach-Object` cmdlet.
31+
Although the **Module** parameter of `Get-Command` accepts multiple string values, it only accepts
32+
them via pipeline input by property name. In the following scenario, if you want to pipe two string
33+
values to `Get-Command` for use with the **Module** parameter, you need to use the `ForEach-Object`
34+
cmdlet.
3435

3536
```powershell
3637
'ActiveDirectory', 'SQLServer' |
37-
ForEach-Object {Get-Command -Module $_} |
38-
Group-Object -Property ModuleName -NoElement |
39-
Sort-Object -Property Count -Descending
38+
ForEach-Object {Get-Command -Module $_} |
39+
Group-Object -Property ModuleName -NoElement |
40+
Sort-Object -Property Count -Descending
4041
```
4142

4243
```Output
@@ -47,16 +48,16 @@ Count Name
4748
```
4849

4950
In the previous example, `$_` is the current object. Beginning with PowerShell version 3.0,
50-
`$PSItem` can be used instead of `$_`. But I find that most experienced PowerShell users still
51-
prefer using `$_` since it's backward compatible and less to type.
51+
`$PSItem` can be used instead of `$_`. Most experienced PowerShell users prefer using `$_` since
52+
it's backward compatible and less to type.
5253

53-
When using the `foreach` keyword, you must store all of the items in memory before iterating through
54-
them, which could be difficult if you don't know how many items you're working with.
54+
When using the `foreach` keyword, you must store the items in memory before iterating through them,
55+
which could be difficult if you don't know how many items you're working with.
5556

5657
```powershell
5758
$ComputerName = 'DC01', 'WEB01'
5859
foreach ($Computer in $ComputerName) {
59-
Get-ADComputer -Identity $Computer
60+
Get-ADComputer -Identity $Computer
6061
}
6162
```
6263

@@ -82,28 +83,28 @@ SID : S-1-5-21-2989741381-570885089-3319121794-1107
8283
UserPrincipalName :
8384
```
8485

85-
Many times a loop such as `foreach` or `ForEach-Object` is necessary. Otherwise you'll receive an
86-
error message.
86+
Many times a loop such as `foreach` or `ForEach-Object` is necessary. Otherwise you receive an error
87+
message.
8788

8889
```powershell
8990
Get-ADComputer -Identity 'DC01', 'WEB01'
9091
```
9192

9293
```Output
9394
Get-ADComputer : Cannot convert 'System.Object[]' to the type
94-
'Microsoft.ActiveDirectory.Management.ADComputer' required by parameter 'Identity'.
95-
Specified method is not supported.
95+
'Microsoft.ActiveDirectory.Management.ADComputer' required by parameter
96+
'Identity'. Specified method is not supported.
9697
At line:1 char:26
9798
+ Get-ADComputer -Identity 'DC01', 'WEB01'
9899
+ ~~~~~~~~~~~~~~~
99-
+ CategoryInfo : InvalidArgument: (:) [Get-ADComputer], ParameterBindingExc
100-
eption
101-
+ FullyQualifiedErrorId : CannotConvertArgument,Microsoft.ActiveDirectory.Management
102-
.Commands.GetADComputer
100+
+ CategoryInfo : InvalidArgument: (:) [Get-ADComputer], Parame
101+
terBindingException
102+
+ FullyQualifiedErrorId : CannotConvertArgument,Microsoft.ActiveDirecto
103+
ry.Management.Commands.GetADComputer
103104
```
104105

105-
Other times, you can get the same results while eliminating the loop altogether. Consult the cmdlet
106-
help to understand your options.
106+
Other times, you can get the same results while eliminating the loop. Consult the cmdlet help to
107+
understand your options.
107108

108109
```powershell
109110
'DC01', 'WEB01' | Get-ADComputer
@@ -131,19 +132,19 @@ SID : S-1-5-21-2989741381-570885089-3319121794-1107
131132
UserPrincipalName :
132133
```
133134

134-
As you can see in the previous examples, the **Identity** parameter for `Get-ADComputer` only accepts a
135-
single value when provided via parameter input, but it allows for multiple items when the input is
136-
provided via pipeline input.
135+
As you can see in the previous examples, the **Identity** parameter for `Get-ADComputer` only
136+
accepts a single value when provided via parameter input. However, by using the pipeline, you can
137+
send multiple values to the command because the values are processed one at a time.
137138

138139
### For
139140

140-
A `for` loop iterates while a specified condition is true. The `for` loop is not something that I
141-
use often, but it does have its uses.
141+
A `for` loop iterates while a specified condition is true. I don't use the `for` loop often, but it
142+
has uses.
142143

143144
```powershell
144145
for ($i = 1; $i -lt 5; $i++) {
145-
Write-Output "Sleeping for $i seconds"
146-
Start-Sleep -Seconds $i
146+
Write-Output "Sleeping for $i seconds"
147+
Start-Sleep -Seconds $i
147148
}
148149
```
149150

@@ -154,25 +155,26 @@ Sleeping for 3 seconds
154155
Sleeping for 4 seconds
155156
```
156157

157-
In the previous example, the loop will iterate four times by starting off with the number one and
158-
continue as long as the counter variable `$i` is less than 5. It will sleep for a total of 10
159-
seconds.
158+
In the previous example, the loop iterates four times by starting with the number one and continuing
159+
as long as the counter variable `$i` is less than 5. It sleeps for a total of 10 seconds.
160160

161161
### Do
162162

163-
There are two different `do` loops in PowerShell. `Do Until` runs while the specified condition is
164-
false.
163+
There are two different `do` loops in PowerShell: `do until` and `do while`. `do until` runs until
164+
the specified condition is false.
165+
166+
The following example is a numbers game that continues until the value you guess equals the same
167+
number that the `Get-Random` cmdlet generated.
165168

166169
```powershell
167170
$number = Get-Random -Minimum 1 -Maximum 10
168171
do {
169-
$guess = Read-Host -Prompt "What's your guess?"
170-
if ($guess -lt $number) {
171-
Write-Output 'Too low!'
172-
}
173-
elseif ($guess -gt $number) {
174-
Write-Output 'Too high!'
175-
}
172+
$guess = Read-Host -Prompt "What's your guess?"
173+
if ($guess -lt $number) {
174+
Write-Output 'Too low!'
175+
} elseif ($guess -gt $number) {
176+
Write-Output 'Too high!'
177+
}
176178
}
177179
until ($guess -eq $number)
178180
```
@@ -185,20 +187,17 @@ Too low!
185187
What's your guess?: 3
186188
```
187189

188-
The previous example is a numbers game that continues until the value you guess equals the same
189-
number that the `Get-Random` cmdlet generated.
190-
191-
`Do While` is just the opposite. It runs as long as the specified condition evaluates to true.
190+
`Do While` is the opposite. It runs as long as the specified condition is evaluated as true.
192191

193192
```powershell
194193
$number = Get-Random -Minimum 1 -Maximum 10
195194
do {
196-
$guess = Read-Host -Prompt "What's your guess?"
197-
if ($guess -lt $number) {
198-
Write-Output 'Too low!'
199-
} elseif ($guess -gt $number) {
200-
Write-Output 'Too high!'
201-
}
195+
$guess = Read-Host -Prompt "What's your guess?"
196+
if ($guess -lt $number) {
197+
Write-Output 'Too low!'
198+
} elseif ($guess -gt $number) {
199+
Write-Output 'Too high!'
200+
}
202201
}
203202
while ($guess -ne $number)
204203
```
@@ -219,14 +218,19 @@ The same results are achieved with a `Do While` loop by reversing the test condi
219218

220219
### While
221220

222-
Similar to the `Do While` loop, a `While` loop runs as long as the specified condition is true. The
223-
difference however, is that a `While` loop evaluates the condition at the top of the loop before any
224-
code is run. So it doesn't run if the condition evaluates to false.
221+
Like the `do while` loop, a `while` loop runs as long as the specified condition is true. The
222+
difference, however, is that a `while` loop evaluates the condition at the top of the loop before
223+
any code is run. So, it doesn't run if the condition is evaluated as false.
224+
225+
The following example calculates what day Thanksgiving Day is on in the United States. It's always
226+
on the fourth Thursday of November. The loop starts with the 22nd day of November and adds a day,
227+
while the day of the week isn't equal to Thursday. If the 22nd is a Thursday, the loop doesn't run
228+
at all.
225229

226230
```powershell
227231
$date = Get-Date -Date 'November 22'
228232
while ($date.DayOfWeek -ne 'Thursday') {
229-
$date = $date.AddDays(1)
233+
$date = $date.AddDays(1)
230234
}
231235
Write-Output $date
232236
```
@@ -235,38 +239,37 @@ Write-Output $date
235239
Thursday, November 23, 2017 12:00:00 AM
236240
```
237241

238-
The previous example calculates what day Thanksgiving Day is on in the United States. It's always on
239-
the fourth Thursday of November. So the loop starts with the 22nd day of November and adds a day
240-
while the day of the week isn't equal to Thursday. If the 22nd is a Thursday, the loop doesn't run
241-
at all.
242-
243-
## Break, Continue, and Return
242+
## break, continue, and return
244243

245-
`Break` is designed to break out of a loop. It's also commonly used with the `switch` statement.
244+
The `break` keyword is designed to exit a loop and is often used with the `switch` statement. In
245+
the following example, `break` causes the loop to end after the first iteration.
246246

247247
```powershell
248248
for ($i = 1; $i -lt 5; $i++) {
249-
Write-Output "Sleeping for $i seconds"
250-
Start-Sleep -Seconds $i
251-
break
249+
Write-Output "Sleeping for $i seconds"
250+
Start-Sleep -Seconds $i
251+
break
252252
}
253253
```
254254

255255
```Output
256256
Sleeping for 1 seconds
257257
```
258258

259-
The `break` statement shown in the previous example causes the loop to exit on the first iteration.
259+
The `continue` keyword is designed to skip to the next iteration of a loop.
260260

261-
Continue is designed to skip to the next iteration of a loop.
261+
The following example outputs the numbers 1, 2, 4, and 5. It skips number 3 and continues with the
262+
next iteration of the loop. Like `break`, `continue` breaks out of the loop except only for the
263+
current iteration. Execution continues with the next iteration instead of breaking out of the loop
264+
altogether and stopping.
262265

263266
```powershell
264267
while ($i -lt 5) {
265-
$i += 1
266-
if ($i -eq 3) {
267-
continue
268-
}
269-
Write-Output $i
268+
$i += 1
269+
if ($i -eq 3) {
270+
continue
271+
}
272+
Write-Output $i
270273
}
271274
```
272275

@@ -277,58 +280,56 @@ while ($i -lt 5) {
277280
5
278281
```
279282

280-
The previous example will output the numbers 1, 2, 4, and 5. It skips number 3 and continues with
281-
the next iteration of the loop. Similar to `break`, `continue` breaks out of the loop except only
282-
for the current iteration. Execution continues with the next iteration instead of breaking out of
283-
the loop and stopping.
283+
`Return` is designed to exit out of the existing scope.
284284

285-
Return is designed to exit out of the existing scope.
285+
Notice in the following example that `return` outputs the first result and then exits out of the
286+
loop.
286287

287288
```powershell
288289
$number = 1..10
289290
foreach ($n in $number) {
290-
if ($n -ge 4) {
291-
Return $n
292-
}
291+
if ($n -ge 4) {
292+
return $n
293+
}
293294
}
294295
```
295296

296297
```Output
297298
4
298299
```
299300

300-
Notice that in the previous example, return outputs the first result and then exits out of the
301-
loop. A more thorough explanation of the result statement can be found in one of my blog articles:
302-
["The PowerShell return keyword"]["The PowerShell return keyword"].
301+
A more thorough explanation of the result statement can be found in one of my blog articles:
302+
[The PowerShell return keyword][the-powershell-return-keyword].
303303

304304
## Summary
305305

306-
In this chapter, you've learned about the different types of loops that exist in PowerShell.
306+
In this chapter, you learned about the different types of loops that exist in PowerShell.
307307

308308
## Review
309309

310-
1. What is the difference in the `ForEach-Object` cmdlet and the foreach scripting construct?
311-
1. What is the primary advantage of using a While loop instead of a Do While or Do Until loop.
312-
1. How do the break and continue statements differ?
310+
1. What's the difference between the `ForEach-Object` cmdlet and the `foreach` scripting construct?
311+
1. What's the primary advantage of using a `While` loop instead of a `Do While` or `Do Until` loop?
312+
1. How do the `break` and `continue` statements differ?
313313

314-
## Recommended Reading
314+
## References
315315

316-
- [ForEach-Object][ForEach-Object]
317-
- [about_ForEach][about_ForEach]
318-
- [about_For][about_For]
319-
- [about_Do][about_Do]
320-
- [about_While][about_While]
321-
- [about_Break][about_Break]
322-
- [about_Continue][about_Continue]
323-
- [about_Return][about_Return]
316+
- [ForEach-Object][foreach-object]
317+
- [about_ForEach][about-foreach]
318+
- [about_For][about-for]
319+
- [about_Do][about-do]
320+
- [about_While][about-while]
321+
- [about_Break][about-break]
322+
- [about_Continue][about-continue]
323+
- [about_Return][about-return]
324324

325325
<!-- link references -->
326-
[ForEach-Object]: /powershell/module/microsoft.powershell.core/foreach-object
327-
[about_ForEach]: /powershell/module/microsoft.powershell.core/about/about_foreach
328-
[about_For]: /powershell/module/microsoft.powershell.core/about/about_for
329-
[about_Do]: /powershell/module/microsoft.powershell.core/about/about_do
330-
[about_While]: /powershell/module/microsoft.powershell.core/about/about_while
331-
[about_Break]: /powershell/module/microsoft.powershell.core/about/about_break
332-
[about_Continue]: /powershell/module/microsoft.powershell.core/about/about_continue
333-
[about_Return]: /powershell/module/microsoft.powershell.core/about/about_return
334-
["The PowerShell return keyword"]: https://mikefrobbins.com/2015/07/23/the-powershell-return-keyword/
326+
327+
[foreach-object]: /powershell/module/microsoft.powershell.core/foreach-object
328+
[about-foreach]: /powershell/module/microsoft.powershell.core/about/about_foreach
329+
[about-for]: /powershell/module/microsoft.powershell.core/about/about_for
330+
[about-do]: /powershell/module/microsoft.powershell.core/about/about_do
331+
[about-while]: /powershell/module/microsoft.powershell.core/about/about_while
332+
[about-break]: /powershell/module/microsoft.powershell.core/about/about_break
333+
[about-continue]: /powershell/module/microsoft.powershell.core/about/about_continue
334+
[about-return]: /powershell/module/microsoft.powershell.core/about/about_return
335+
[the-powershell-return-keyword]: https://mikefrobbins.com/2015/07/23/the-powershell-return-keyword/

0 commit comments

Comments
 (0)