Hey, Scripting Guy! Question

Hey, Scripting Guy! I have been using VBScript for a long time. One of my favorite language statements in VBScript is the While…Wend loop. It is easy to use and easy to understand. Is there an equivalent command in Windows PowerShell?

- HS

SpacerHey, Scripting Guy! Answer

Hi HS,

WE never did use the While…Wend loop very much. WE generally used the Do…While…Loop construction instead. We have a good Sesame Script article that talks about five ways of performing looping in VBScript. In fact, most of the scripts we have written over the years at the Script Center did not use the While…Wend loop. That does not mean that it is wrong, nor is one any better than the other as long as it does the job that you want to perform. It is all about choices. Sometimes, these choices can be confusing. When you walk into a chocolate store, you may think it is a bit unnecessary that they have 50 different kinds laid out in all the display cases. We know that we’ll have the giant peanut butter cup; we are in and out in less than a minute. However, we have friends who could spend a complete day shopping in a chocolate store. So we can each experience the same activity in a different way. As long as one is happy, it is all that is important. If you want to use the While…Wend loop in VBScript, go ahead. If you want to use the same kind of construction in Windows PowerShell, guess what? We can accommodate you!

This week we are looking at scripting Windows PowerShell. Windows PowerShell is installed by default on Windows Server 2008 R2 and Windows 7. It is an optional installation on Windows Server 2008, and a download for Windows Vista, Windows XP, and Windows Server 2003. The Windows PowerShell Scripting Hub is a good place to start using Windows PowerShell. An excellent book for learning Windows PowerShell is the Microsoft Press book, Microsoft Windows PowerShell Step by Step. This book has many hands-on labs and uses real-world examples to show the use of Windows PowerShell.

For those who may not be familiar with the While…Wend loop in VBScript, we took the time to write a quick VBScript to explain what we are talking about. The first thing the WhileReadLineWend.vbs script does is create an instance of the FileSystemObject, and store it in the objFSO variable. We then use the OpenTextFile method to open a test file, and store that object in the objFile variable. We then use the While Not …Wend construction to read one line at a time from the text stream and display it on the screen. We continue to do this until we are at the end of the text stream object. A While…Wend loop merely continues to operate as long as a condition is evaluated as true. In this example, as long as we are not at the end of the stream, we will continue to read the line from the text file. The WhileReadLineWend.vbs script is shown here.

WhileReadLineWend.vbs

Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objFile = objFSO.OpenTextFile("C:\fso\testfile.txt")

While Not objFile.AtEndOfStream
 WScript.Echo objFile.ReadLine
Wend

As you probably have already guessed, we have the same kind of construction available to us in Windows PowerShell. Incidentally, the While statement in Windows PowerShell works in a very similar manner to the one that you use in VBScript. In the DemoWhileLessThan.ps1 script, we first initialize the variable $i to be equal to 0. We then use the While keyword to begin the While loop. In Windows PowerShell, we must include the condition that will be evaluated inside a set of parentheses. For this example, we determine the value of the $i variable with each pass through the loop. If the value of $i is less than the number 5, we will perform the action that is specified inside the braces (curly brackets) that set off the script block.

In VBScript the condition that is evaluated is positioned on the same line with the While statement, but no parentheses are required. Although this is convenient from a typing perspective, it actually makes the code a bit confusing to read. In Windows PowerShell, the statement is outside the parentheses and the condition is clearly delimited by the parentheses. In VBScript the action that is performed is added between two words: while and wend. In Windows PowerShell, there is no wend statement, and the action to be performed is positioned inside a pair of braces. Although shocking at first to users coming from a VBScript background, the braces are always used to contain code. This is what is called a script block, and they are used everywhere. As soon as you are used to seeing them here, you will find them with other language statements too. The good thing is you do not have to look for items such as the keyword Wend or the keyword Loop (from Do…Loop fame).

In Windows PowerShell, there are two kinds of strings: literal strings and expanding strings. In the DemoWhileLessThan.ps1 script, we use the expanding string (signified by using the double quotation mark, [the literal string uses the single quotation mark, ]). We want to display the name of the variable, and we want to display the value that is contained in the variable. This is a perfect place to showcase the expanding string. In an expanding string, the value that is contained in a variable is displayed on the screen when a line is evaluated. As an example, consider the following code. We assign the value 12 to the variable $i. We then put $i inside a pair of double quotation marks to make an expanding string. When the line “$i is equal to $i” is evaluated, we get “12 is equal to 12” which while true is barely illuminating. This is shown here:

PS C:\> $i = 12
PS C:\> "$i is equal to $i"
12 is equal to 12
PS C:\>

What we wanted to do is display both the name of the variable and the value that is contained inside it. In VBScript we would have to use concatenation. For this example to work, we have to use the literal string as seenhere:

PS C:\> $i = 12
PS C:\> '$i is equal to ' + $i
$i is equal to 12
PS C:\>

If we want to use the advantage of the expanding string, we have to suppress the expanding nature of the expanding string for the first variable. To do this, we use the escape character which is the backtick character. This is seen here:

PS C:\> $i = 12
PS C:\> "`$i is equal to $i"
$i is equal to 12
PS C:\>

In the DemoWhileLessThan.ps1 script, we use the expanding string to display our status message of the value of the $i variable during each trip through the While loop. We suppress the expanding nature of the expanding string for the first $i variable so that we can see which variable we are talking about. As soon as we have done this, we increment the value of the $i variable by one. To do this, we use the $i++ syntax. This is identical to saying the following:

$i = $i + 1

The advantage is that the $i++ syntax is less typing. The DemoWhileLessThan.ps1 script is seen here:

DemoWhileLessThan.ps1

$i = 0
While ($i -lt 5)
 {
  "`$i equals $i. This is less than  5"
  $i++ 
 } #end while $i lt 5

When you run the DemoWhileLessThan.ps1 script, you receive the following output:

$i equals 0. This is less than  5
$i equals 1. This is less than  5
$i equals 2. This is less than  5
$i equals 3. This is less than  5
$i equals 4. This is less than  5
PS C:\>

Now that you know how to use the While loop, let’s examine the WhileReadLine.ps1 script. The first thing we do is initialize the $i variable and set it equal to 0. We then use the b cmdlet to read the contents of the Testfile.txt and to store the contents into the $fileContents variable. The Testfile.txt file is shown here:

Image of using the Get-Content cmdlet to read the Testfile.txt file

 

Now we use the While statement to loop through the contents of the text file. We do this as long as the value of the $i variable is less than or equal to the number of lines in the text file. The number of lines in the text file is represented by the length property. Inside the script block, we treat the contents of the $fileContents variable as if it is an array (which it is), and we use the $i variable to index into the array to print the value of each line in the $fileContents variable. We then increment the value of the $i variable by one. The WhileReadLine.ps1 script is shown here:

WhileReadLine.ps1

$i = 0
$fileContents = Get-Content -path C:\fso\testfile.txt
While ( $i -le $fileContents.length )
 {
  $fileContents[$i]
  $i++
 }

If you are thinking the WriteReadLine.ps1 script is a bit difficult, in reality it is about the same difficulty level as the VBScript version. The difference is we resorted to using arrays to work with the content we received from the Get-Content cmdlet. The VBScript version uses a FileSystemObject and a TextStreamObject to work with the data. In reality, we would not have to use a script exactly like the WhileReadLine.ps1 script to read the contents of the text file. This is because the Get-Content cmdlet does this for us automatically. All we really have to do to display the contents of the TestFile.txt is use Get-Content. This is shown here:

Get-Content –path c:\fso\TestFile.txt

The results of the command are shown here:

Image of the Get-Content cmdlet reading and displaying content from a text file

 

By not storing the results of the command in a variable, the contents are automatically displayed. The Get-Content command can be further shortened by using the gc alias (short name for the Get-Content cmdlet) and by omitting the name of the –path parameter (which is the default parameter). When we do this, we create a command that resembles the following:

GC c:\fso\TestFile.txt

To find the available aliases for the Get-Content cmdlet, I used the Get-Alias cmdlet to produce a listing of all the aliases that are defined in the current session. I then pipelined the results of the command to the Where-Object and looked for definitions that match Get-Content. Here is the command and the output Ireceived:

PS C:\> Get-Alias | where-object { $_.definition -eq 'get-content'}

CommandType     Name                            Definition
-----------     ----                            ----------
Alias           cat                             Get-Content
Alias           gc                              Get-Content
Alias           type                            Get-Content

We have shown you that you can use the While statement in Windows PowerShell. We have also shown that occasionally you do not have to use the looping behavior because some cmdlets will automatically display information. Finally, we showed you how you can find aliases for cmdlets you frequently use. Join us tomorrow as we continue with Introduction to Windows PowerShell Scripting Week. Until then, take care.

 

Ed Wilson and Craig Liebendorfer, Scripting Guys