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
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"
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
$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"
}
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
filter getversion {
$wmi = get-wmiobject win32_operatingsystem `
-property servicepackmajorversion `
-computer $_
$sp = $wmi.servicepackmajorversion
write-host "$_ : $sp"
}
get-content "c:\computers.txt" | getversion
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
filter getversion {
$wmi = get-wmiobject win32_operatingsystem `
-property servicepackmajorversion `
-computer $_
write-host "$_ : " $wmi.servicepackmajorversion
}
get-content "c:\computers.txt" | getversion
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.