Summary: Microsoft Scripting Guy Ed Wilson talks about when to not write a Windows PowerShell script.
Weekend Scripter
Microsoft Scripting Guy, Ed Wilson, is here. Network administrators do not script! ITPros do not like to script! I have heard statements like this for years. Yet, when I first wrote my VBScript workshop for Microsoft Premier Workshops, it quickly became the most popular of all workshop offerings. So what gives? Is there a disconnect? Do ITPros really like to write scripts? Is there a secret developer hiding inside net admins that is struggling to make itself known? I do not think so. Rather, I believe that the desire to “learn” scripting is the desire to ease network administration duties. I believe the impetus to acquire scripting skills is the wish to automate repetitive tasks. In the past, these twin needs and goals did require learning rudimentary (and at times more advanced) programming skills, but this is no longer the case.
Microsoft Windows PowerShell MVP, Don Jones, caused a minor tempest in the Windows PowerShell community when he declared that Windows PowerShell was not a “scripting language.” To an extent he was kidding, but he also had a point because Windows PowerShell is an automation tool.
I believe, within reason, that the days of writing scripts are rapidly drawing to a close. To the extent that customization is required, it can be handled in the pipeline. To the extent that new functionality is required, it is best handled as an advanced function.
I think a couple of examples are in order to illustrate what I am talking about. Consider the simple case of checking the version of the BIOS on the computer. In the old-fashioned VBScript days, a script such as the following was the order of the day.
GetBiosInformation.vbs
On Error Resume Next
strComputer = “.”
Set objWMIService = GetObject(“winmgmts:\\” & strComputer & “\root\cimv2”)
Set colItems = objWMIService.ExecQuery(“Select * from Win32_BIOS”,,48)
For Each objItem in colItems
Wscript.Echo “BiosCharacteristics: ” & objItem.BiosCharacteristics
Wscript.Echo “BIOSVersion: ” & objItem.BIOSVersion
Wscript.Echo “BuildNumber: ” & objItem.BuildNumber
Wscript.Echo “Caption: ” & objItem.Caption
Wscript.Echo “CodeSet: ” & objItem.CodeSet
Wscript.Echo “CurrentLanguage: ” & objItem.CurrentLanguage
Wscript.Echo “Description: ” & objItem.Description
Wscript.Echo “IdentificationCode: ” & objItem.IdentificationCode
Wscript.Echo “InstallableLanguages: ” & objItem.InstallableLanguages
Wscript.Echo “InstallDate: ” & objItem.InstallDate
Wscript.Echo “LanguageEdition: ” & objItem.LanguageEdition
Wscript.Echo “ListOfLanguages: ” & objItem.ListOfLanguages
Wscript.Echo “Manufacturer: ” & objItem.Manufacturer
Wscript.Echo “Name: ” & objItem.Name
Wscript.Echo “OtherTargetOS: ” & objItem.OtherTargetOS
Wscript.Echo “PrimaryBIOS: ” & objItem.PrimaryBIOS
Wscript.Echo “ReleaseDate: ” & objItem.ReleaseDate
Wscript.Echo “SerialNumber: ” & objItem.SerialNumber
Wscript.Echo “SMBIOSBIOSVersion: ” & objItem.SMBIOSBIOSVersion
Wscript.Echo “SMBIOSMajorVersion: ” & objItem.SMBIOSMajorVersion
Wscript.Echo “SMBIOSMinorVersion: ” & objItem.SMBIOSMinorVersion
Wscript.Echo “SMBIOSPresent: ” & objItem.SMBIOSPresent
Wscript.Echo “SoftwareElementID: ” & objItem.SoftwareElementID
Wscript.Echo “SoftwareElementState: ” & objItem.SoftwareElementState
Wscript.Echo “Status: ” & objItem.Status
Wscript.Echo “TargetOperatingSystem: ” & objItem.TargetOperatingSystem
Wscript.Echo “Version: ” & objItem.Version
Next
With Windows PowerShell, it is possible to replace that exact script with the following command.
Get-WmiObject Win32_bios | Format-List *
The output from the VBScript script and the PowerShell command are nearly identical.
Now, suppose I decide that I need to run the command to get BIOS information from a large number of computers. The choice of where the computer names reside is a different discussion, but for now suppose the computer names are stored in a text file, one computer name per line. To solve this scenario, I can use the command that is shown here.
Get-WmiObject win32_bios -cn (Get-Content C:\fso\Servers.txt)
If I need to use different credentials (an account other than the one that I am currently using) to run the command, I use the Credential parameter as shown here.
Get-WmiObject win32_bios -cn (Get-Content C:\fso\Servers.txt) –credential nwtraders\administrator
When the command runs, a dialog box appears that prompts me to enter my password. This password is encrypted as it is transmitted because it is retrieved and handled as a secure string. The dialog box for the password is shown in the following image.
Well, this is all fine and dandy, but to be honest, it is a bit silly to read a text file that contains dozens (or even hundreds) of computer names, and then display the results to the console. It makes more sense to output the information somewhere. I like writing the data to a database and using the SQLPSX modules. It is really trivial to write information to a database. The easiest way to store the returned information is to use redirection arrows and write the returned data to a text file. This technique is shown here.
Get-WmiObject win32_bios -cn (Get-Content C:\fso\Servers.txt) >> c:\fso\biosInfo.txt
Because I am working interactively in the Windows PowerShell console, I might want to shorten the syntax a bit by using commonly available aliases for the commands. To do this, the previous command becomes:
gwmi win32_bios -cn (cat C:\fso\Servers.txt) >> c:\fso\biosInfo.txt
This command works because gwmi is an alias for the Get-WmiObject cmdlet. I need to let the Get-WmiObject cmdlet know what I intend to do with the results of my Get-Content cmdlet. I can use cn as an alias for the longer ComputerName parameter (in fact, I have cheated all along on this detail today). There are three default aliases for the Get-Content cmdlet. I found them by using the Get-Aliases cmdlet as shown here.
PS C:\> Get-Alias -Definition get-content
CommandType Name Definition
———– —- ———-
Alias cat Get-Content
Alias gc Get-Content
Alias type Get-Content
If you do not like any of the default aliases, you can create your own alias. For example, if you like dogs better than cats, you can create a new alias as shown here. One thing to keep in mind, is that nothing is returned when you create a new alias in this manner.
PS C:\> New-Alias -Name dog -Value get-content
PS C:\>
You can always check to ensure that the new alias “took” by using the Get-Alias cmdlet as shown here.
PS C:\> Get-Alias dog
CommandType Name Definition
———– —- ———-
Alias dog get-content
Or better yet, you can simply try the new command and see what happens. This is what I do here.
gwmi win32_bios -cn (dog C:\fso\Servers.txt)
None of this required any scripting. Now suppose in my testing, I detect that there is a bad BIOS version. I mean, it is the sort of thing that causes my servers to emit a BSOD (blue screen of death). In the past, I would need to write a script to check for that. But by using Windows PowerShell, I simply “tack” an additional cmdlet to the end of my pipeline. The revised command is shown here.
Get-WmiObject win32_bios -cn (Get-Content C:\fso\Servers.txt) |
Where-Object { $_.version -match ‘2170’}
Note: The previous command is a single logical command. I broke it at the pipeline character (|) so it would fit better in the blog format.
I can shorten this command by using aliases. In the short version, gwmi is an alias for the Get-WmiObject cmdlet. I use gc for Get-Content, and the question mark (?) as an alias for the Where-Object cmdlet. The short version of this command is shown here.
gwmi win32_bios -cn (gc C:\fso\Servers.txt) | ? { $_.version -match ‘2170’}
If I only need a list of the servers that will need the BIOS update, I add an additional cmdlet to the end of the command. This time, I use the Select-Object cmdlet to retrieve the __Server property (that is a double underscore character at the beginning of the __Server property). In WMI, there is always a system property named __Server that stores the name of the computer. This property exists in nearly every WMI class. The revised command is shown here.
Get-WmiObject win32_bios -cn (Get-Content C:\fso\Servers.txt) |
Where-Object { $_.version -match ‘2170’} | Select-Object __Server
Once again, this is a single logical command. I broke the command at the pipeline character (|) to better format the command for the blog.
I can shorten this command by using aliases. There is a default alias of Select for the Select-Object cmdlet. A short version of the command is shown here.
gwmi win32_bios -cn (gc C:\fso\Servers.txt) | ? { $_.version -match ‘2170’} | select __Server
Even by using aliases, the command is becoming a bit long. But the cool thing is that the command is built incrementally, and I can use the command buffer to retrieve and to edit my commands.
I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.
Ed Wilson, Microsoft Scripting Guy
0 comments