Comparing Windows PowerShell and Bash

Slashdot it! Delicious Share on Facebook Tweet! Digg!
ariwasabi, 123RF

ariwasabi, 123RF

Disparate Development

Bash and PowerShell are related, but as in all large families, the branches of the tree often take on different forms.]

Several years have passed since my previous article looking at the command-line languages under Windows and Linux [1] – time to reinvestigate how these two opponents have developed over the past half decade. A comparison of Windows PowerShell and Bash might indicate who has the current edge in modern scripting.

Windows PowerShell was a completely fresh start of Microsoft's command language under Vista (see the "New Beginning" box). Meanwhile, Bash under Linux was always at the core of the system (see the "Tried and Tested" box) with the project participants continuously updating the interface. So, has Bash matured and got better with age, or has inherited too much cruft that weighs it down?

Tried and Tested

Bash development is rather straightforward in comparison. As many as 111 enhancements have been spliced into Bash [2] since my last evaluation in 2007 – the largest number in the jump from version 3.2 to 4.0 in 2009. The comparatively minor changes in the current version 4.2 prove how well Bash has matured.

Just under half (18 of 39) of the built-in Bash functions are from the Bourne Shell. The cd and test are certainly among the most commonly used, but they also count among the relics. The other half of the functions, among them echo and read, came along with the Bourne Again Shell. They handle everyday tasks, with Bash leaving the special ones to other programs.

Splitting the workload has always been a well-known Linux concept. The login shell serves more as a central command function for the many specialized programs. Thus, nearly 100 programs are available in the GNU Coreutils, which comes with just about every Linux distribution [3].

New Beginning

Microsoft has wanted that the graphical interface to be all you need to operate a computer. There was simply no room for an unadorned shell. Hence, Windows command line sat for decades in a hidden niche.

Despite this decision, the system still relied on scripts for management and, in consequence, many interpreter languages soon sprouted up – Windows Scripting Host (WSH), the Windows Management Interface (WMI), HTML Applications (HTA), the Active Directory Services Interface (ADSI), and Visual Basic Script (VBS).

Microsoft then set the system on a totally new course with Windows Vista. Desktop and server editions began sharing the same code base. Developers also reworked the system architecture and based everything on reusable objects. The .NET framework was supposed to be the unifying structure for all modern applications and provide the building blocks for all new ones. An interpreter should be able to access the system library.

The new shell should, therefore, have all the qualities that modern interpreters such as Python and Ruby already had, except now on Windows as well. Hence PowerShell is object-oriented. It can pass the output from one command in a pipe to another command, and .NET components can be integrated. In terms of modern scripting languages, this was hardly a breakthrough, but it proved to be a big step for Microsoft toward professional system administration.

Four generations of PowerShell have emerged from the company since 2006. Windows 7 includes PowerShell 2.0, and Windows 8 has PowerShell 3.0 with many enhancements. The current version 4.0 was written for Windows 8.1 and, with .NET Framework 4.5.1, also comes as an update for Windows 7 and Windows 8.

Comparing Concepts

One of the most important characteristics of a scripting language is the ability to link two commands, assuming that one command receives, understands, and processes the output of the other. As a rule, Bash uses plain text as input and output. Thus, the following command shows the size and name of the three largest files in the /var/log directory:

$ ls -l /var/log | sed 's/ \+/,/g' | cut -d',' -f 5,9 | sort -g | tail -3
267453,core.log
443742,core.log.1
584584,lastlog

In Windows PowerShell, the input and output are objects; thus, entire data structures migrate from command to command, which assumes that objects follow certain guidelines. To get the same result in Windows as in the previous example, you need to know the properties of the corresponding objects:

PS> Get-ChildItem -Directory | Sort-Object -Property Length | Select-Object Length,Name -Last 3
   Length Name
   ------ ----
 597379 Manual.pdf
 5715026 Applications.in.Ruby.pdf
 27318109 AnnualCatalogue_de-EU.pdf

The fact that Bash presents output as text naturally makes it easier to pass information on to the next program. Most things can be worked out by trial and error – which is nearly impossible in PowerShell.

In the example, you need the properties Length and Name. Intuitively, you might have used Size instead of Length. So, to know the properties of an object, sometimes the documentation is the only resort.

As it is, the example from PowerShell 3.0 is already easier than in previous versions. In earlier versions, the Get-ChildItem cmdlet (which corresponds roughly to ls) didn't yet recognize the -Directory option. Instead, it depended on a subsequent cmdlet (Where-Object {-not $_.PSIsContainer} ) to be built into the pipe to filter by directory, because only directories have the property PSIsContainer.

The difference in handling input and output is just one of many differences between Bash and PowerShell, but it's strikingly obvious. The difference in concept is basically that Bash aims at division of labor while PowerShell focuses on tasks, which was reinforced further in versions 3.0 and 4.0.

Steep Learning Curve

Bash uses only about 40 internal functions and 100 helper programs. PowerShell 4.0 has 299 built-in cmdlets. Version 2.0 (Windows 7) already had 251. Every cmdlet has options, which increase in number with each new PowerShell version.

Thus, the Get-Content cmdlet in Version 3.0 (Windows 8) has the option -Tail <count> , which the developers apparently borrowed from the Unix tail command. Microsoft provides a quick reference guide to the new PowerShell features [4].

The cmdlets are more like mini-programs compared to the Bash built-ins, which becomes obvious when the cmdlet does not do what you expect it to do. When this happens, which is often, you'll need to look at the reference document to find the correct parameters and options. On the plus side, cmdlets can execute more complex tasks in one call. For example, to call up all the links on the ubuntu-user.com website, all you need in PowerShell 3.0 are the commands in Listing 1.

Listing 1

Call Up Links with PowerShell

PS> (Invoke-WebRequest http://www.ubuntu-user.com/).links
innerHTML : <IMG border=0 alt=logoOL.gif src="http://www.ubuntu-user.com/pix/logoOL.gif" width=140 height=62>
innerText :
outerHTML : <A href="/"><IMG border=0 alt=logoOL.gif src="http://www.ubuntu-user.com/pix/logoOL.gif" width=140 height=62></A>
outerText :
tagName   : A
href      : /

Sometimes this task orientation seems a bit much, and it makes certain tasks a bit cumbersome. To generate a password in Bash, all you need is to read the file descriptor for the random number generator and prepare it somewhat (see Listing 2).

Listing 2

Generate a Password with Bash

$  echo $(< /dev/urandom tr -dc _A-Z-a-z-0-9 | head -c10)
Kc-TUGC8cd

To accomplish the same in PowerShell 3.0, you can load a system library from .NET Framework and use a module from it. In the Assembly System.Web, you'll find the Security.Membership module and its GeneratePassword function (Listing 3). An assembly is similar to the Shared Object principle in Linux. You can load assemblies into scripts and use their functions from there.

Listing 3

Generate a Password with PowerShell

PS> $Assembly = Add-Type -AssemblyName System.Web
PS> [System.Web.Security.Membership]::GeneratePassword(10,3)
lGv%.ua]Wl

PowerShell may leave you wondering things like how to determine which objects use which methods, and in which of the many thousand system libraries can you find the function GeneratePassword. PowerShell definitely requires some heavy lifting. You need to study the extensive reference to the .NET Framework [5] to get anywhere.

Buy this article as PDF

Express-Checkout as PDF

Pages: 4

Price $0.99
(incl. VAT)

Buy Ubuntu User

SINGLE ISSUES
 
SUBSCRIPTIONS
 
TABLET & SMARTPHONE APPS
Get it on Google Play

US / Canada

Get it on Google Play

UK / Australia

Related content