Feb 14 2008

Scripting With Windows PowerShell

An introduction to the commands and syntax of Microsoft's powerful platform.

Scripts are part of the foundation for efficient network administration. Network administrators are generally not programmers, but they need tools that will let them automate certain tasks and simplify the job of administering various computer resources on the network. In previous versions of the Windows operating system, Windows Script Host (WSH) has been the standard scripting language to execute such tasks. But with the introduction of Windows Vista, Microsoft introduced a new, more powerful platform, PowerShell.

PowerShell is more than a simple scripting language, but less than a full-blown programming language. PowerShell is a command-line shell that provides a powerful platform for performing an array of functions. PowerShell works with Windows XP, Windows Vista, Windows Server 2003 and the upcoming Windows Server 2008. Microsoft server applications, such as Exchange Server 2007, System Center Operations Manager 2007, System Center Data Protection Manager V2 and System Center Virtual Machine Manager are also designed to leverage the efficiency and productivity that PowerShell provides.

To understand how PowerShell works and how it compares with other programming or scripting language options, we’ll take a deeper look at some of the functions and syntax. One of the fundamental  concepts of programming is the use and manipulation of strings. Below are some examples that demonstrate how to work with strings in PowerShell, along with some comparisons to other development or scripting languages.

Objects Versus Text

One of the benefits of the PowerShell platform is that it integrates or unifies the three distinct types of programming that administrators typically do: script languages, shell programs and  development languages. PowerShell is a script language and a command-line shell that is built on a development foundation, providing a single platform that administrators can leverage to do scripting more efficiently.
The majority of scripting languages and command-line shells are text-based, so working with text is integral to using these programs. The Windows PowerShell platform is written in C#, and much of the syntax is similar to C#. PowerShell is also .NET-based, so writing scripts with PowerShell relies on understanding the .NET object model and working with the properties of .NET objects.

Comparing Strings

Even in an object-based programming environment, you can’t get away from the need to manipulate and analyze string data. PowerShell provides a variety of tools and functions that simplify the task of working with strings.

Let’s say that you want to compare two strings to see if they are the same. First, you need to decide whether letter case is relevant. If “Biztech” and “biztech” are the same to you, then you can do a case-insensitive comparison. However, if you want to differentiate the uppercase and lowercase versions as two separate strings, you would need to do a case-sensitive comparison. Assuming that you use these two strings as variables, the code for comparing them is demonstrated below:

$x = “Biztech”
$y = “biztech”

Case-Sensitive Comparison

Assuming that you want the strings to be interpreted as two different strings based on the different case, the comparison of the two strings is quite simple.

$c = $x.CompareTo($y)

This one line of code tells PowerShell to evaluate the variable $x using the CompareTo method. The parameter passed to the CompareTo method is the value $y, so CompareTo evaluates $x against $y and assigns the resulting value to $c. If the strings are the same, the result of the CompareTo is “0.” If they are not the same, the result will be something other than “0.” After entering the line of code above, type $c and hit Enter to see the result. Comparing the two strings resulted in $c being assigned the value “1,” which means they are not the same.

To further illustrate this, create a third value with the same string as $x, then re-run the code comparing $x to the new string.

$z = “Biztech”
$c = $x.CompareTo($z)

To perform a similar comparison using VBScript to write a WSH script, you would have to enter the following code in a text editor, such as Notepad, then save it as a VBS file.

str1 = "Biztech"
str2 = "biztech"

If str1 = str2 Then
     Wscript.Echo "The strings are the same"
     Wscript.Echo "The strings are different"
End If

This code uses an If-Then statement to compare the two strings and display a message box with the results of the comparison as seen here.

Case-Insensitive Comparison

If you think that “Biztech” and “biztech” are the same, then you have to perform the comparison a different way. In order to evaluate the comparison without regard to the case of the letters, you need to use the System.String class from the .NET framework. You then call the Compare method and pass the two values you intend to compare, as well as a third value, $True. PowerShell will compare the two values, along with the Boolean value $True, which tells the Compare method to ignore the case of the letters in the string.

$c = [string]::Compare($x, $y, $True)

Using the same values for $x and $y as we did in the case-sensitive example above, the result of this comparison will be that $c is assigned a value of “0,” indicating that the two strings are equal, regardless of the difference in case.

Now, let’s take a look at the WSH equivalent again. By default, the VBScript compares the two values as binary. In a binary comparison, the letter “B” and the letter “b” have two different values. However, you can use the StrComp (for string comparison) to force the values to be evaluated as strings. Using the following code, the WSH script will compare the two strings without regard to the case of the letters. The comparison is assigned to a variable, and then the value of the variable is checked to determine if the comparison was equal or not:

str1 = "Biztech"
str2 = "biztech"
intResult = StrComp (str1, str2, vbTextCompare)

If intResult = 0 Then
     Wscript.Echo "The strings are the same"
     Wscript.Echo "The strings are different"
End If

Replacing Strings

One of the more common tasks that network administrators are faced with is correcting or modifying file names to normalize data. Perhaps the company is changing the standard naming convention of files, or maybe thousands of files were imported with a typo and fixing them manually one at a time would be a gargantuan task. Thankfully, you can use PowerShell to quickly and easily replace all or part of a string.

For example, if you accidentally mistype “Biztech” as “Bitzech” while assigning a value to a variable, you can use the following code in PowerShell to replace the misspelled word.

$x = “Bitzech”
$x = $x.Replace(“Bitzech”, “Biztech”)

Of course, it was really only the “t” and the “z” that needed flip-flopping. So, instead of replacing the whole word, you could just do this:

$x = $x.Replace(“tz”, “zt”)

In this example, it would be easier to just reassign $a by typing $a=“Biztech” and move on to the rest of your script. But, using this example code — where $a is actually a file name pulled from a directory and with the code running in a loop — you can automate the renaming of hundreds or thousands of files.

You can also use the Replace functionality of PowerShell to remove part of a string. For instance, if you have a bunch of files that all started with the naming convention “Biztech Magazine,” and you want to shorten the name by dropping the word “magazine,” you could use the following PowerShell code:

$x = “Biztech Magazine”
$x = $x.Replace(“ Magazine”, “”)

This replaces the space following “Biztech” and the word “Magazine” with an empty string, or nothing, leaving the value of $x as simply “Biztech”.

Unleashing PowerShell

Working with strings is certainly a necessary function when developing scripts and executing administrative tasks, but let’s take a look at some more useful ways to put PowerShell to work. Let’s use an example of a midsize business with a little more than 1,000 users. A text file has been created with the names of every computer system in the inventory. For starters, let’s assume you just want to validate that the number of devices in the text file matches the number of devices you know are in your inventory. Assuming that the file is called “computers.txt” and is located on your C: drive, you could use the following code:

Get-Content C:\computers.txt | Measure-Object

The Get-Content cmdlet reads the contents of the text file and automatically generates an array from each line of the file; the Measure-Object cmdlet counts the rows in the array, returning the value of the total number of devices named in the text file.

Now let’s take a look at leveraging the power of the Get-Content cmdlet even further. Assume that the text file is all the company has in terms of inventory tracking. They want to get a better handle on which systems are which. Using the following PowerShell code, you can use Get-Content along with the ForEach-Object cmdlet to pull the data from the text file, then loop through the data one line at a time. The Get-Wmiobject cmdlet is called by ForEach-Object to gather the BIOS information from each system, including the serial number, manufacturer and BIOS version.

Get-Content C:\computers.txt | ForEach-Object {Get-Wmiobject –computername $_win32_bios}

Tony Bradley, a Microsoft MVP (Most Valuable Professional) in Windows Security, is a computer security consultant with BT INS in Houston and author of Essential Computer Security.