using objects

PowerShell Paradigm Change

Probably the biggest mental leap you can make when moving from VBScript to PowerShell is that PowerShell is intended to deal with objects not text. That's all well and good in theory, but it can be a confusing concept to implement until you get used to it. For example, look at ServicePack.vbs, which is a VBScript that reads a list of names from C:\Computers.txt (one name per line) and uses WMI to display the service pack version for each.

ServicePack.vbs
source code
Dim strFile
strFile = "C:\computers.txt"

Dim objFSO, objTS, strComputer
Set objFSO = CreateObject("Scripting.FileSystemObject")
If objFSO.FileExists(strFile) Then
    Set objTS = objFSO.OpenTextFile(strFile)
    Do Until objTS.AtEndOfStream
        strComputer = objTS.ReadLine

        Dim objWMI
        Set objWMI = GetObject("winmgmts:\\" & strComputer & _
         "\root\cimv2")

        Dim colResults, objResult, strWMIQuery

        strWMIQuery = "SELECT * FROM Win32_OperatingSystem"
        Set colResults = objWMI.ExecQuery(strWMIQuery)
        For Each objResult In colResults
            WScript.Echo strComputer & ":" & _
             objResult.ServicePackMajorVersion
        Next

    Loop
End If

objTS.Close
WScript.Echo "Complete"
source code

As mentioned previously, you're probably familiar enough with VBScript to follow what this script is doing. However, take time to notice the methodology. Each time through the Do loop, a line is read from the text file, which is assumed to be a computer name. A WMI connection to that computer is created, and the Win32_OperatingSystem class retrieved. For each instance of the class, a loop displays the ServicePackMajorVersion property.

Now look at ServicePack.ps1, which does the same thing.

ServicePack.ps1
source code
$names = get-content "c:\computers.txt"
foreach ($name in $names) {
  $wmi = get-wmiobject win32_operatingsystem `
   -property servicepackmajorversion `
   -computer $name
  $sp = $wmi.servicepackmajorversion
  write-host "$name : $sp"
}
source code

First of all, notice how much shorter this is! It actually could be shorter, but we wrote it more for clarity than brevity. Again, the real thing to notice is the methodology. The Get-Content cmdlet is used to retrieve the entire contents of the text file into $names, all in one step. A foreach loop goes through each child item (or line) of the text file, pulling each child item into $name. The Get-Wmiobject cmdlet retrieves just the desired property, placing the class instance into $wmi. The $sp variable is used to hold the actual property in which we're interested. The Write-Host is used to output the information to the screen.

Keep in mind that, where VBScript typically requires something to be done in a particular way, PowerShell is a lot more flexible. ServicePack2.ps1 demonstrates the same script, from a different approach.

ServicePack2.ps1
source code
filter getversion {
  $wmi = get-wmiobject win32_operatingsystem `
   -property servicepackmajorversion `
   -computer $_
  $sp = $wmi.servicepackmajorversion
  write-host "$_ : $sp"
}

get-content "c:\computers.txt" | getversion
source code

Here, the content of the text file is piped to "getversion," which is a custom filter. This filter is called once for each object or line of text in the text file. The special $_ variable refers to the current object, which would be a single computer name. ServicePack3.ps1 simplifies this even further.

ServicePack3.ps1
source code
filter getversion {
  $wmi = get-wmiobject win32_operatingsystem `
   -property servicepackmajorversion `
   -computer $_
  write-host "$_ : " $wmi.servicepackmajorversion
}

get-content "c:\computers.txt" | getversion
source code

All that's been done here is to remove the $sp variable. This was done because $wmi.servicepackmajorversion is now output directly, which removes a line of code. This could be simplified even further. However, the VBScript example we started with has been simplified about as much as possible.

Getting used to PowerShell's way of working with objects take some time. However, if you make the effort, these examples have demonstrated how much more quickly you can produce usable administrative scripts.