As you begin to write scripts or commands that interact with unknown data, the concepts of looping and flow control become increasingly important.
PowerShell's looping statements and commands let you perform an operation (or set of operations) without having to repeat the commands themselves. This includes, for example, doing something a specified number of times, processing each item in a collection, or working until a certain condition comes to pass.
PowerShell's flow control and comparison statements let you adapt your script or command to unknown data. They let you execute commands based on the value of that data, skip commands based on the value of that data, and more.
"let you to adapt your script" needs to change grammatically. "allow you to adapt" "let you adapt"
Together, looping and flow control statements add significant versatility to your PowerShell toolbox.
You want to compare some data with other data and make a decision based on that comparison.
Use PowerShell's logical operators to compare pieces of data and make decisions based on them.
-eq,
-ne, -ge, -gt, -lt, -le, -like, -notlike, -match, -notmatch, -contains, -notcontains, -is, -isnot
-and,
-or, -xor, -not
For a detailed description (and examples) of these operators, see the section called “Comparison Operators”.
These are case insensitive - worth mentioning the explicit case sensitive versions?
PowerShell's logical and comparison operators
let you compare pieces of data, or test data for some condition. An
operator either compares two pieces of data (a
binary operator) or tests one piece of data (a
unary operator). All comparison operators are
binary operators (they compare two pieces of data), as are most of the
logical operators. The only unary logical operator is the -not operator, which returns the true/false opposite of the data that it
tests.
Comparison operators compare two pieces of data and return a result that depends on the specific comparison operator. For example, you might want to check whether a collection has at least a certain number of elements:
PS > (dir).Count -ge 4 True
or, check whether a string matches a given regular expression:
PS > "Hello World" -match "H.*World" True
Most comparison operators also adapt to the
type of their input. For example, when you apply them to simple data
such as a string, the -like and
-match comparison operators determine
whether the string matches the specified pattern. When you apply them to
a collection of simple data, those same comparison operators return all
elements in that collection that match the pattern you provide.
The -match operator takes a regular expression
as its argument. One of the more common regular expression symbols is
the $ character, which represents the end of line. The $ character
also represents the start of a PowerShell variable, though! To prevent
PowerShell from interpreting characters as language terms or escape
sequences, place the string in single quotes rather than double
quotes:
PS > "Hello World" -match "Hello" True PS > "Hello World" -match 'Hello$' False
By default, PowerShell's comparison operators
are case-insensitive. To use the case-sensitive versions, prefix them
with the character c:
-ceq,-cne,-cge,-cgt,-clt,-cle,-clike,-cnotlike,-cmatch,-cnotmatch,-ccontains,-cnotcontains
For a detailed description of the comparison operators, their case-sensitive counterparts, and how they adapt to their input, see the section called “Comparison Operators”.
Logical operators combine true
or false statements and return a
result that depends on the specific logical operator. For example, you
might want to check whether a string matches the wildcard pattern you
supply, and that it is longer than a certain number
of characters:
PS > $data = "Hello World" PS > ($data -like "*llo W*") -and ($data.Length -gt 10) True PS > ($data -like "*llo W*") -and ($data.Length -gt 20) False
Some of the comparison operators actually
incorporate aspects of the logical operators. Since using the opposite
of a comparison (such as -like) is so
common, PowerShell provides comparison operators (such as -notlike) that save you from having to use the
-not operator explicitly.
For a detailed description of the individual logical operators, see the section called “Comparison Operators”.
Comparison operators and logical operators (when combined with flow control statements) form the core of how we write a script or command that adapts to its data and input.
See also the section called “Conditional Statements” for detailed information about these statements.
For more information about PowerShell's
operators, type Get-Help
About_Operators.
You want to control the conditions under which PowerShell executes commands or portions of your script.
Use PowerShell's if, elseif,
and else conditional statements to
control the flow of execution in your script.
For example:
$temperature = 90
if($temperature -le 0)
{
"Balmy Canadian Summer"
}
elseif($temperature -le 32)
{
"Freezing"
}
elseif($temperature -le 50)
{
"Cold"
}
elseif($temperature -le 70)
{
"Warm"
}
else
{
"Hot"
}Conditional statements include the following:
if
statementExecutes the script block that follows it if its condition evaluates to true
elseif
statementExecutes the script block that follows
it if its condition evaluates to true, and
none of the conditions in the if or elseif statements before it evaluate to
true
else
statementExecutes the script block that follows
it if none of the conditions in the if or elseif statements before it evaluate to
true
In addition to being useful for script control flow, conditional statements are often a useful way to assign data to a variable. PowerShell version two makes this significantly easier by now letting you assign the results of a conditional statement directly to a variable:
$result = if(Get-Process -Name notepad) { "Running" } else { "Not running" }For more information about these flow control
statements, type Get-Help
About_Flow_Control.
I appreciate the references to the get-help information for the topics
You want to find an easier or more compact way
to represent a large if … elseif … else conditional statement.
Use PowerShell's switch statement to more easily represent a
large if … elseif … else conditional statement.
For example:
$temperature = 20
switch($temperature)
{
{ $_ -lt 32 } { "Below Freezing"; break }
32 { "Exactly Freezing"; break }
{ $_ -le 50 } { "Cold"; break }
{ $_ -le 70 } { "Warm"; break }
default { "Hot" }
}PowerShell's switch statement lets you easily test its
input against a large number of comparisons. The switch statement
supports several options that let you configure how PowerShell compares
the input against the conditions—such as with a wildcard, regular
expression, or even arbitrary script block. Since scanning through the
text in a file is such a common task, PowerShell's switch statement supports that directly. These
additions make PowerShell switch
statements a great deal more powerful than those in C and C++.
Can some more real life examples of how the switch statement is used be included? Scanning for text in a file was mentioned, but it would be nice to see an example that relates to a system administrator's job
As another example of the switch statement in action, consider how
to determine the SKU of the current operating system. For example, is
the script running on Windows 7 Ultimate? Windows Server Cluster
Edition? The Get-WmiObject cmdlet lets you determine
the operating system SKU, but unfortunately returns its result as a
simple number. A switch statement lets you map these to their english
equivalent:
$sku = Get-WmiObject Win32_OperatingSystem
switch ($sku.OperatingSystemSKU)
{
0 {"Undefined"; break}
1 {"Ultimate Edition"; break}
2 {"Home Basic Edition"; break}
3 {"Home Basic Premium Edition"; break}
4 {"Enterprise Edition"; break}
5 {"Home Basic N Edition"; break}
6 {"Business Edition"; break}
7 {"Standard Server Edition"; break}
8 {"Datacenter Server Edition"; break}
9 {"Small Business Server Edition"; break}
10 {"Enterprise Server Edition"; break}
11 {"Starter Edition"; break}
12 {"Datacenter Server Core Edition"; break}
13 {"Standard Server Core Edition"; break}
14 {"Enterprise Server Core Edition"; break}
15 {"Enterprise Server Edition for Itanium-Based Systems"; break}
16 {"Business N Edition"; break}
17 {"Web Server Edition"; break}
18 {"Cluster Server Edition"; break}
19 {"Home Server Edition"; break}
20 {"Storage Express Server Edition"; break}
21 {"Storage Standard Server Edition"; break}
22 {"Storage Workgroup Server Edition"; break}
23 {"Storage Enterprise Server Edition"; break}
24 {"Server For Small Business Edition"; break}
25 {"Small Business Server Premium Edition"; break}
default {"UNKNOWN: " + $SKU.OperatingSystemSKU}
}Although used as a way to express large conditional
statements more cleanly, a switch statement operates much like a large
sequence of if statements, as opposed
to a large sequence of if … elseif … elseif … else statements. Given the input that you
provide, PowerShell evaluates that input against
each of the comparisons in the switch statement. If the comparison evaluates
to true, PowerShell then executes the
script block that follows it. Unless that script block contains a
break statement, PowerShell continues
to evaluate the following comparisons.
For more information about PowerShell's
switch statement, see the section called “Conditional Statements” or type Get-Help About_Switch.
Use one of PowerShell's looping statements
(for, foreach, while, and do), or PowerShell's Foreach-Object cmdlet to run a command or
script block more than once. For a detailed description of these looping
statements, see the section called “Looping Statements”. For
example:
do..until loop should also be mentioned here
Tibor: Isn't a do ... until loop also a do loop, which is already mentioned?
Nevermind, didn't look far enough.
for loopfor($counter = 1; $counter -le 10; $counter++)
{
"Loop number $counter"
}foreach loopforeach($file in dir)
{
"File length: " + $file.Length
}Foreach-Object
cmdletGet-ChildItem | Foreach-Object { "File length: " + $_.Length }while loop$response = ""
while($response -ne "QUIT")
{
$response = Read-Host "Type something"
}do..while loop$response = ""
do
{
$response = Read-Host "Type something"
} while($response -ne "QUIT")do..until loop$response = ""
do
{
$response = Read-Host "Type something"
} until($response -eq "QUIT")Although any of the looping statements can be written to be functionally equivalent to any of the others, each lends itself to certain problems.
You usually use a for loop when you need to perform an operation
an exact number of times. Because using it this way is so common, it is
often called a counted for loop.
You usually use a foreach loop when you have a collection of
objects and want to visit each item in that collection. If you do not
yet have that entire collection in memory (as in the dir collection from the foreach example above), the Foreach-Object cmdlet is usually a more
efficient alternative.
Unlike the foreach loop, the Foreach-Object cmdlet lets you process each
element in the collection as PowerShell generates
it. This is an important distinction; asking PowerShell to
collect the entire output of a large command (such as Get-Content
hugefile.txt) in a foreach loop can easily drag down your
system.
A handy shortcut to repeat an operation on the command line is:
PS > 1..10 | foreach { "Working" }
Working
Working
Working
Working
Working
Working
Working
Working
Working
WorkingLike pipeline-oriented functions, the
Foreach-Object cmdlet lets you define commands to
execute before the looping begins, during the looping, and after the
looping completes:
PS > "a","b","c" | Foreach-Object `
>> -Begin { "Starting"; $counter = 0 } `
>> -Process { "Processing $_"; $counter++ } `
>> -End { "Finishing: $counter" }
>>
Starting
Processing a
Processing b
Processing c
Finishing: 3The while and
do..while loops are similar, in that
they continue to execute the loop as long as its condition evaluates to
true. A while loop checks for this before ever running
your script block, while a do..while
loop checks the condition after running your script block. A
do..until loop is exactly like a
do..while loop, except that it exits when its
condition returns $true, rather than when its
condition returns $false.
For a detailed description of these looping
statements, see the section called “Looping Statements” or type Get-Help About_For, Get-Help About_Foreach, Get-Help
about_While, or Get-Help
about_Do.
can also add
Get-Help About_Do Get-Help About_While
but the do help doesn't exist in PowerShell 1
To pause until the user presses ENTER, use the Read-Host cmdlet:
PS > Read-Host "Press ENTER" Press ENTER:
To pause until the user presses a key, use the
ReadKey() method on the $host object:
PS > $host.UI.RawUI.ReadKey()
To pause a script for a given amount of time,
use the Start-Sleep cmdlet:
PS > Start-Sleep 5 PS > Start-Sleep -Milliseconds 300
When you want to pause your script until the
user presses a key or for a set amount of time, the Read-Host and Start-Sleep cmdlets are the two you are most
likely to use. For more information about using the Read-Host cmdlet to read input from the user,
see the section called “Read a Line of User Input”.
In other situations, you may sometimes want to write a loop in your script that runs at a constant speed—such as once per minute, or 30 times per second. That is typically a difficult task, as the commands in the loop might take up a significant amount of time, or even an inconsistent amount of time.
In the past, many computer games suffered from solving this problem incorrectly. To control their game speed, game developers added commands to slow down their game. For example, after much tweaking and fiddling, the developers might realize that the game plays correctly on a typical machine if they make the computer count to one million every time it updates the screen. Unfortunately, the speed of these commands (such as counting) depend heavily on the speed of the computer. Since a fast computer can count to 1 million much more quickly than a slow computer, the game ends up running much quicker (often to the point of incomprehensibility) on faster computers!
To make your loop run at a regular speed, you can measure how long the commands in a loop take to complete, and then delay for whatever time is left, as shown in Example 4.1, “Running a loop at a constant speed”.
Example 4.1. Running a loop at a constant speed
$loopDelayMilliseconds = 650
while($true)
{
$startTime = Get-Date
"Executing"
$endTime = Get-Date
$loopLength = ($endTime - $startTime).TotalMilliseconds
$timeRemaining = $loopDelayMilliseconds - $loopLength
if($timeRemaining -gt 0)
{
Start-Sleep -Milliseconds $timeRemaining
}
}For more information about the Start-Sleep cmdlet, type Get-Help Start-Sleep.
2 comments
I will review this chapter
Reviewing
Add a comment