Why PowerShell Isn't VBScript or KiXtart

For more than a decade (heck, close to two), Windows administrators relied upon scripting technologies to automate key tasks. Both KiXtart - part of the Windows 95 Resource Kit and earlier Windows Resource Kit editions - and Visual Basic Scripting Edition (VBScript to its fans) offered a simplified programming language that seemed purpose-built for administrative tasks.

In fact, they were anything but. KiXtart was designed primarily for logon scripts and excelled at checking group membership, mapping drives, and not much else. Subsequent improvements to it simply brought it more in line with VBScript. VBScript was designed first for Web development, including client-side scripting in Internet Explorer and server-side scripting in Active Server Pages. VBScript's use as an administrative tool came about when Microsoft released the Windows Script Host (WSH), a way of running VBScripts on their own, and started releasing Component Object Model (COM) objects that gave VBScript access to administrative functionality. But the downside of both KiXtart and VBScript was that they ultimately involved programming.

Don't get me wrong: Plenty of administrators took to programming like ducks to water, and that's a big part of why PowerShell offers programming-like structures in its intrinsic keyword set. There are certainly those complex tasks that can only be accomplished when you are willing to be a programmer, at least for an hour or so. But lots more administrators don't have a programming background, and don't want one. They're perfectly comfortable with command-line tools, and don't mind lining up a few commands in a batch file to save typing, but start throwing in "For Each" and "If Then" constructs and they just don't have the time.

And for an increasing number of complex tasks, PowerShell doesn't make them. Despite all the heavy-programming examples you see on the Web (many of which are produced by some of my well-meaning, but sadly developer-oriented fellow MVPs), PowerShell isn't a scripting language. It is, first and foremost, a command-line shell, just like Cmd.exe. It lets you run commands, and customize their behavior by using command-line parameters. Yes, sometimes those can be complex. But administrators haven't historically shied away from complex commands. Consider this MS-DOS example:

doskey myname=for /f "delims=\ tokens=2" %i in ('whoami') do @echo %i

Not exactly simplistic. Look at all that punctuation! But with a little experience, most administrators have no trouble deciphering that. Consider a PowerShell one-liner:

Get-WmiObject Win32_BIOS -computerName (Get-Content c:\names.txt) | Select-Object __SERVER,SerialNumber,@{ Label='OSBuild';Expression={ (Get-WmiObject Win32_OperatingSystem -computerName $_.__SERVER).BuildNumber }}

Go ahead and try it, you won't break anything. You just need a file called c:\names.txt that has the name of a server or two, listing one server name per line. It'll show you each server's BIOS serial number and operating system build number, along with the computer name, in a convenient table. Oh, you wanted that output to a CSV file?

Get-WmiObject Win32_BIOS -computerName (Get-Content c:\names.txt) | Select-Object __SERVER,SerialNumber,@{ Label='OSBuild';Expression={ (Get-WmiObject Win32_OperatingSystem -computerName $_.__SERVER).BuildNumber }} | Export-CSV c:\output.csv

Just pipe the output to Export-CSV. Yes, this is a complex command-line - but it's not a script. Yes, there's a lot of weird punctuation, but with a bit of experience you'll be breaking that down in no time.
That's what this blog is all about: Helping you gain the experience to use PowerShell as a command-line shell first. There will be times when I'll resort to a script - but often, I'll only do so because something can be more clearly written-out that way. I'll help you over the hurdles (like the crazy punctuation). I'll show you some killer one-liners, like this one, and introduce you to tricks that you'll end up using all the time. In return, I ask for only one thing: Ask questions. Help me figure out what you need to know. Tell me where you're getting stuck (along with examples, please!). Together, we'll hash it all out. It'll be fun!

Discuss this Blog Entry 4

on Apr 27, 2011
Oh the dreaded hidden extension, I can't count the number of times this has happened to me, you will spend hours racking your brains trying to figure out what is wrong and after all that its always something simple like these hidden extensions. At the end you don't know whether to cry because it was something so stupid or just thanks God that you got it working. Really enjoyed the post and hopefully I can make use of some of your suggestions

on Apr 16, 2010
Thanks pb, I'm on Win 7 64bit, I'll try adjusting the file to a C:\pstest\names.txt

Dang hidden extensions, you were right, it was names.txt.txt.
Ran like a champ. Looking forward to this.

I have question in mind but first I'll do a search for it, maybe some one has already asked it. May as well not re-invent the wheel.

Thanks again

packetboy (not verified)
on Apr 16, 2010
Hey Will.. Powershell is telling us it definitely can not see names.txt did you accidentally call it names.txt.txt? What OS are you running this on? If its Vista or above you normally can not save files to the root of C:\ so maybe its dropped the file in your documents folder?

Don looking forward to the blog! I am a big fan of yours and you have really made my powershell get better and better.


on Apr 16, 2010
Thanks Don, I look foward to following your blog. I'm one of those old admins that does many things with .bat files, tried to learn VB script but could not devote the time to it. I've tried the example here but it fails, not sure where to start looking for the breaking point. The file names.txt is in the c: drive. It has 3 server names each on it's own line.


PS C:\> Get-WmiObject Win32_BIOS -computerName (Get-Content c:\names.txt) | Select-Object __SERVER,SerialNumber,@{ Label
='OSBuild';Expression={ (Get-WmiObject Win32_OperatingSystem -computerName $_.__SERVER).BuildNumber }} | Export-CSV c:\output.csv
Get-Content : Cannot find path 'C:\names.txt' because it does not exist.
At line:1 char:52
+ Get-WmiObject Win32_BIOS -computerName (Get-Content <<<< c:\names.txt) | Select-Object __SERVER,SerialNumber,@{ Labe
l='OSBuild';Expression={ (Get-WmiObject Win32_OperatingSystem -computerName $_.__SERVER).BuildNumber }} | Export-CSV c:
+ CategoryInfo : ObjectNotFound: (C:\names.txt:String) [Get-Content], ItemNotFoundException
+ FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.GetContentCommand

Get-WmiObject : Cannot validate argument on parameter 'ComputerName'. The argument is null or empty. Supply an argument
that is not null or empty and then try the command again.
At line:1 char:39
+ Get-WmiObject Win32_BIOS -computerName <<<< (Get-Content c:\names.txt) | Select-Object __SERVER,SerialNumber,@{ Labe
l='OSBuild';Expression={ (Get-WmiObject Win32_OperatingSystem -computerName $_.__SERVER).BuildNumber }} | Export-CSV c:
+ CategoryInfo : InvalidData: (:) [Get-WmiObject], ParameterBindingValidationException
+ FullyQualifiedErrorId : ParameterArgumentValidationError,Microsoft.PowerShell.Commands.GetWmiObjectCommand

Please or Register to post comments.

What's PowerShell with a Purpose Blog?

Don Jones demystifies Windows PowerShell.

Blog Archive

Sponsored Introduction Continue on to (or wait seconds) ×