A fundamental concept in any programming language is the use of looping techniques. Because everything in Windows PowerShell is an object, looping techniques not only become much more important but also are inherent in the way you use the scripts. Most of the time, you will not have to stop and think, “Do I need to use a looping technique here?” Rather, it will be intuitive, and you will probably find yourself performing the looping without thinking.
If you were tempted to call this the for … each … next statement (as it was called in VBScript), then I have good news for you. In Windows PowerShell, there is no “next” required for the ForEach-Object cmdlet. Therefore, you will never forget to close out a for … each … next statement by leaving out the last next statement again. This is because Windows PowerShell automatically closes the statement, and the trailing next is no longer required. Of course, because everything in Windows PowerShell is an object, foreach is actually an alias for the ForEach-Object cmdlet.
In the ColorCodeProcessOutput.ps1 script, we use a ForEach-Object to produce a color-coded listing of processes running on a local machine that are using more CPU clock cycles than other processes. We use an if statement to decide on the color of the text to display. If the amount of CPU time is less than 100, then the color of text is blue. If it is more than 100, then we change the color of the text to red.
The Write-Host cmdlet is used to write the output from the script to the Windows PowerShell console. There are several properties available from the Get-Process cmdlet. If you wanted to add properties to display, you would simply list them in the first position separated by commas, as we did with $_.name and $_.cpu. To see all the properties available from Get-Process, pipeline Get-Process into the Get-Member cmdlet, as shown here:
Get-Process | Get-Member
After you have identified the properties you wish to retrieve, the next argument to supply to the Write-Host cmdlet is the foregroundcolor argument.
The color constants listed in Table 4-5 can be used for both the foregroundcolor argument and the backgroundcolor argument of Write-Host.
Black | DarkBlue | DarkGreen | DarkCyan |
DarkRed | DarkMagenta | DarkYellow | Gray |
DarkGray | Blue | Green | Cyan |
Red | Magenta | Yellow | White |
Note | Before you run ColorCodeProcessOutput.ps1 script on your machine, you may want to use Get-Process with no arguments to see what processes are using the most CPU time, and then adjust the -gt and the -lt arguments in the script accordingly. |
ColorCodeProcessOutput.ps1
Get-Process | ForEach-Object ` {if ($_.cpu -lt 100) {Write-Host $_.name, $_.cpu -foregroundcolor blue} elseif ($_.cpu -gt 100) {Write-Host $_.name, $_.cpu -foregroundcolor red}}
Troubleshooting | If you are unable to run Windows PowerShell scripts, one thing to check is the script execution policy. To do this, use the Get-ExecutionPolicy cmdlet. If the script execution policy is set to Restricted, you will need to change the policy to either Remote Signed or Unrestricted. To do this, you can use the Set-ExecutionPolicy cmdlet. |
Open Windows PowerShell.
Use the Get-Service cmdlet to produce a listing of the name and status of each service defined on your machine. The code to do this is shown here:
Get-Service
Pipeline the results from the Get-Service cmdlet to a ForEach-Object. This code is shown here:
ForEach-Object
Use the line continuation special escape sequence to continue the ForEach-Object command to the next line. The line continuation character is the grave accent (`) and on English language keyboards is found on the same key as the tilde (~). This line is shown here (you will not need to repeat ForEach-Object because this is the same line).
ForEach-Object `
Open an if statement. The condition to be evaluated is "if the status of the service is equal to stopped." The status property will be associated with the current pipeline object and is referenced by the special variable $_. The code to do this is shown here:
if ($_.Status -eq "stopped")
Open a script block by using the left curly bracket ({). Use the Write-Host cmdlet to write data to the Windows PowerShell console. Write the name and the status of each service. If the service is stopped, we want to specify the foregroundcolor to be red. Use the separator argument and use the comma, a new line, and a Tab. To specify the new line, use the special escape sequence `n. To specify a Tab, use the special escape sequence `t. The code to do this is shown here:
{Write-Host $_.name, $_.Status -foregroundcolor red -separator ",`n`t"}
For the elseif clause, evaluate whether the status of the service in the current pipeline object is equal to running. This is shown here:
elseif ($_.Status -eq "running")
If the service is running, we want to write the name and the status of the service in green by using the foregroundcolor argument of the Write-Host cmdlet. Use the separator argument and use the comma, a new line, and a Tab. To specify the new line, use the special escape sequence `n. To specify a Tab, use the special escape sequence`t. The code to do this is shown here:
{Write-Host $_.name, $_.Status -foregroundcolor green -separator ",`n`t"}}
Save your script as yourname ColorCodedServiceStatus.ps1. If your script does not work as expected, compare your script with the ColorCodedServiceStatus.ps1 script in the scripts folder for this chapter.
Similar to the ForEach-Object cmdlet, the for statement is used to control execution of a script block as long as a condition is true. Most of the time, you will use the for statement to perform an action a certain number of times. The line of code shown here is the basic for construction. The parentheses are used to separate the expression being evaluated from the code block contained in curly brackets. The evaluated expression is composed of three sections. In the first part, we create a variable $a and assign the value of 1 to it. In the second section, we have the condition to be evaluated. In the code shown here, as long as the variable $a is less than or equal to 3, the command in the code block section will continue to run. The last portion of the evaluation expression adds 1 to the variable $a. The code block is a simple printout of the word hello.
for ($a = 1; $a -le 3 ; $a++) {"hello"}
The PingArang.ps1 script shown here is very useful because it can be used to ping a range of IP addresses and will tell you whether the computer is responding to Internet control messaging packets (ICMPs). This is helpful for network discovery, or for ensuring that a computer is talking to the network. The $intPing variable is set to 10 and defined as an integer. Next, the $intNetwork variable is assigned the string "127.0.0." and is defined as a string.
The for statement is used to execute the remaining code the number of times specified in the $intPing variable. The counter-variable is created on the for statement line. This counter-variable, called $i, is assigned the value of 1. As long as $i is less than or equal to the value set in the $intPing variable, the script will continue to execute. The last thing that is done inside the evaluator section of the for statement is to add one to the value of $i.
The code block begins with the curly bracket. The first thing that is done inside the code block is to create a variable called $strQuery. The $strQuery is the string that holds the WMI query. The reason for putting this in a separate variable is that it makes it easier to use the $intNetwork variable and the $i counter-variable to create a valid IP address for use in the WMI query that results in a ping.
The $wmi variable is used to hold the collection of objects that is returned by the Get-WmiObject cmdlet. By using the optional query argument of the Get-WmiObject cmdlet, we are able to supply a WMI query. The statuscode property contains the result of the ping operation. A zero (0) indicates success; any other number means the ping failed. To present this information in a clear fashion, we use an if … else statement to evaluate the statuscode property.
PingArange.ps1
[int]$intPing = 10 [string]$intNetwork = "127.0.0." for ($i=1;$i -le $intPing; $i++) { $strQuery = "select * from win32_pingstatus where address = '" + $intNetwork + $i + "'" $wmi = get-wmiobject -query $strQuery "Pinging $intNetwork$i ... " if ($wmi.statuscode -eq 0) {"success"} else {"error: " + $wmi.statuscode + " occurred"} }
The do … while statement is one method for looping through code. The do … while statement evaluates the test condition before running the script block. If the condition is false, then it will not run. If however, it is true, the script will run the loop, evaluate the condition to see whether it is still true, and then run again.
In the CountDownTimer.ps1 script, a do … while loop is used to alternatively pause the script and display the current time as the script counts down to a specified time just like an alarm clock. The script begins by using the variable $dtmTime to hold the object that is returned by the Get-Date cmdlet. When you supply the values for hour, minute, and second, the Get-Date cmdlet will return a dateTime object representing the specified time. The do … while loop evaluates the current time (retrieved by the Get-Date cmdlet and stored in the $dtmCurrent variable) with the time specified in the $dtmTime variable.
If the $dtmCurrent time value is less than the time specified in $dtmTime, then the script will print out the current time value that is contained in the $dtmCurrent variable. To do this, we use the -lt comparison operator. Other comparison operators are seen in Table 4-6. The Start-Sleep cmdlet is used to pause script execution for 2 seconds (as indicated by the -s 2 argument). After the while condition has been satisfied, the script will print out the message “time reached”, and it uses the`a special escape sequence to play the alert beep. The CountDownTimer.ps1 script is shown here:
CountDownTimer.ps1
$dtmTime = get-date -h 04 -mi 23 -s 00 do {$dtmCurrent = Get-Date -DisplayHint time "The current time is " + $dtmCurrent "counting to " + $dtmtime start-sleep -s 2 } while ($dtmCurrent -lt $dtmTime) "time reached à"
Operator | Description |
---|---|
-eq | equals |
-ne | not equal |
-gt | greater than |
-ge | greater than or equal to |
-lt | less than |
-le | less than or equal to |
-like | wild card comparison |
-notlike | wild card comparison |
-match | regular expression comparison |
-notmatch | regular expression comparison |
Q. If you want to perform an operation as long as a value is equal to a certain number, what operator do you use?
A. If you want to perform an operation as long as a value is equal to a certain number, use the -eq operator.
Q. If you want to sound a beep in a script, what special escape character can you use?
A. If you want to sound a beep in a script, use the `a special escape character.
The do … until statement provides a means of looping through your code until a condition becomes true. The difference between do … while and do … until is that the do … until statement evaluates at the end of the loop. This means the code will always run at least once. A basic do … until command is shown here. The value of $i is set to 10. The semicolon is then used to separate the value assignment from do … loop. The curly brackets separate the script block from the rest of the code. Inside the script block, 1 is subtracted from the value of $i each time we loop through the code. The double hyphen (--) operator is used to do the subtraction. A string is used to print out a status message that lets us know the current value of $i. The until block tells the command to continue to run until the value of $i is equal to 0.
$i = 10; do {$i --; "i is $i"} until ($i -eq 0)
In the ReadTxtFile.ps1 script, the variable $i is given a value of 0. The value of $i is then incremented after the script displays one line of text from the text file. The until clause evaluates whether the value of $i is equal to the length of the text file. When the length of the text file is the same as the value of $i, then we have reached the end of the file.
ReadTxtFile.Ps1
$strTxtFile = "c:\mytest\loopbackprocesses.txt" $i = 0 $mytext = Get-Content $strTxtFile do { $mytext[$i] $i ++ } until ($i -eq $mytext.length)
The exploring the do ... until procedure will highlight this behavior.
Open Windows PowerShell.
Type the variable $i and assign the value of 0 to it. Use a semicolon to separate this variable assignment from the following command. This code is shown here:
$i=0;
Open a do loop and add one to the $i variable. Use the special double plus symbol (++) operator. Include the semicolon command separator. This code is shown here:
do {$i++;
Print out the string "I is equal to" and include the value of $i. Close out the script block. This code is shown here:
"i is equal to $i"}
Add the until clause and evaluate the value of $i when it is equal to 0. This code is shown here:
until ($i -eq 0)
Before you run this command, realize it will go into a continuous loop. This is because do … until evaluates at the end of the script. The value of $i will have already been incremented to 1 before the evaluation being performed. You can use ^c to break into the loop.
Run the command. After a few lines have scrolled past, use ^c to break into the loop.
Press the up arrow to retrieve the previous command. This line of code is shown here:
$i=0;do {$i++; "i is equal to $i"} until ($i -eq 0)
Convert the do … until loop into a do … while loop. To do this, simply replace the word until with while. The altered code is shown here:
$i=0;do {$i++; "i is equal to $i"} while ($i -eq 0)
This code runs one time and produces the output shown here:
i is equal to 1
This concludes this procedure. Commands used are stored in the ExploringDoLoop.txt file.