Bash Vs Powershell

A short comparison of OS scripting languages.


Part 1

I will start by saying, I am a fan of Powershell. Even though it doesn’t fit the need for 90% of use cases I prefer it over bash for 3 reasons:

  1. It’s object-oriented
  2. Almost all commands follow the same naming convention
  3. Arguments also follow a logical naming scheme.
    • Consider in bash what will -f do for any random command. What about -c? Always completely different. The only consistent one may be v for verbose.

I decided to compare the two. I will grade with the following attributes of each in mind:

  1. Performance
  2. Syntax
  3. Consistency

each attribute will get a score on a scale from 1-3

1
2
3
1 = poor
2 = average or no difference
3 = superior

But first a bit of background for context.

History

bash

The Bourne Again SHell – or bash was created in 1988 and ultimately released as a product by the ’90s. The current version of bash is 5.1 (2020), which is not much different syntactically from version 3.0 released in 2004 around the time Powershell was being developed.

PowerShell

Driven by a lack of a cohesive scripting language needed for modern automation on Windows, Microsoft created Powershell in 2005. Eventually, Powershell v1.0 was out of beta in 2006. Shortly after, PowerShell v2.0 was released in 2008.

Before we begin

My laptop:

  • 10th gen intel Windows 10 with bash using WSL

Powershell prompt style:

bash prompt style:

Testing commands and functions

I will test 15 different operations on each and judge each on the attributes listed above. Here are the 15 operations I have chosen to compare:

Part 1:

  1. Make the directory
  2. Download the file
  3. write file size to the console
  4. find the file and unzip it
  5. find a string in any file
  6. count file sizes of a type
  7. Get the process by name and append it to a new file

Ready? Go!

Test 1: Make a Directory

I will create test directories for each shell

Bash

Command: mkdir -p bash/test{1..15}

Powershell

Command new-item -itemType directory $(1..15 | foreach{"powershell/test$_"})

Score

StatPowershellBash
Performance22
Syntax13
Consistency22
execution time16.7 ms11 ms
———————-—-
Total66

Winner: Tie

Test 2: Download the zip form online

Bash

Command: wget https://github.com/mongodb/mongodb-kubernetes-operator/archive/refs/heads/master.zip

Powershell

Command : Invoke-WebRequest https://github.com/mongodb/mongodb-kubernetes-operator/archive/refs/heads/master.zip -outfile master.zip

Score

StatPowershellBash
Performance13
Syntax13
Consistency22
execution time1.724 s19.364 s
———————-—-
Total48

Winner: Bash

Test 3: Write file size to console

A simple example where you want to list a file’s size in the console

Bash

Command : echo "Size : $(ls -lh master.zip|awk '{print $5}')"

Powershell

Command : write-host "Size: $((Get-Item master.zip).length/1KB)K"

StatPowershellBash
Performance22
Syntax32
Consistency33
———————-—-
Total87

Winner: Powershell

Test 4: Find a file and unzip it

Bash

Command: find $(pwd) -name *.zip -exec unzip -q {} \;

Powershell

Command: gci -name *.zip|foreach{Expand-Archive $_}

Score

StatPowershellBash
Performance13
Syntax31
Consistency31
———————-—-
Total75

Winner: Powershell

Test 5: Find a string in any file

Bash

Command: grep -R testing

Powershell

Command: gci -Recurse | Select-String "testing" -List

Score

StatPowershellBash
Performance23
Syntax23
Consistency32
———————-—-
Total78

Winner: Bash

Test 6: Count file sizes of a type

Bash

Script:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
#!/bin/bash
files=$(find . -name *.go)
size=0
for i in $files
do
    val=$(ls -l $i|awk '{print $5}')
    size=$(( $size + $val ))
done

echo "Total goLang file size:"
echo "Bytes: $size"
echo "Kilobytes: $(($size / 1000))"

TotalMilliseconds: 1879

Powershell

Script:

1
2
3
4
5
6
$files=(gci -recurse *.go)
$size = ($files | Measure-Object -Sum Length).Sum

write-host "Total goLang file size:"
write-host "Bytes: $size"
write-host "Kilobytes: $($size/1KB)"

TotalMilliseconds: 80.0936

Score

StatPowershellBash
Performance31
Syntax31
Consistency32
———————-—-
Total94

Winner: Powershell

Test 7: Get the process by name and append it to a new file

Bash

Command: pgrep -f bash > out-file.txt && wc out-file.txt

Powershell

Command : (get-process -name system).id|out-file out-file.txt; gci out-file.txt|Measure-Object –Line

Score

StatPowershellBash
Performance32
Syntax22
Consistency22
———————-—-
Total76

Winner: Powershell

Summary

Aggregate total for first 7 tests:

StatPowershellBash
Performance1515
Syntax1615
Consistency1814
———————-—-
Total4944

Powershell Feature spotlight:

Advanced help pages.

Powershell has an intuitive way to find commands that you may want to use. Unlike man pages on bash, which require you to know and read the exact binary that you are needing help with. Powershell allows for searching all help pages, for example:

Get-Help -Name remoting

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
Name                              Category  Module                    Synopsis
Add-AppvClientConnectionGroup     Cmdlet    AppvClient                Add-AppvClientConnectionGroup...
Get-AppvClientConnectionGroup     Cmdlet    AppvClient                Get-AppvClientConnectionGroup...
Enable-AppvClientConnectionGroup  Cmdlet    AppvClient                Enable-AppvClientConnectionGroup...
Remove-AppvClientConnectionGroup  Cmdlet    AppvClient                Remove-AppvClientConnectionGroup...
Disable-AppvClientConnectionGroup Cmdlet    AppvClient                Disable-AppvClientConnectionGroup...
Repair-AppvClientConnectionGroup  Cmdlet    AppvClient                Repair-AppvClientConnectionGroup...
Stop-AppvClientConnectionGroup    Cmdlet    AppvClient                Stop-AppvClientConnectionGroup...
Connect-VMNetworkAdapter          Cmdlet    Hyper-V                   Connect-VMNetworkAdapter...
Grant-VMConnectAccess             Cmdlet    Hyper-V                   Grant-VMConnectAccess...
Disconnect-VMNetworkAdapter       Cmdlet    Hyper-V                   Disconnect-VMNetworkAdapter...
Get-VMConnectAccess               Cmdlet    Hyper-V                   Get-VMConnectAccess...
Disconnect-VMSan                  Cmdlet    Hyper-V                   Disconnect-VMSan...
Revoke-VMConnectAccess            Cmdlet    Hyper-V                   Revoke-VMConnectAccess...
Test-VMReplicationConnection      Cmdlet    Hyper-V                   Test-VMReplicationConnection...
Connect-VMSan                     Cmdlet    Hyper-V                   Connect-VMSan...
Get-IscsiConnection               Function  iSCSI                     ...
Disconnect-IscsiTarget            Function  iSCSI                     ...
Connect-IscsiTarget               Function  iSCSI                     ...
Disconnect-WSMan                  Cmdlet    Microsoft.WSMan.Manage... Disconnect-WSMan...
Connect-WSMan                     Cmdlet    Microsoft.WSMan.Manage... Connect-WSMan...
Get-NetConnectionProfile          Function  NetConnection             ...
Set-NetConnectionProfile          Function  NetConnection             ...
Get-NetTCPConnection              Function  NetTCPIP                  ...
Test-NetConnection                Function  NetTCPIP                  ...

Consistency

  • All of Microsoft’s cmdlets have a Verb-Noun structure.

  • All of Microsoft’s cmdlets can easily be researched on Google because no other program calls their commands “cmdlets”. So, you will always get something on PowerShell if you use that word.

  • All functions are object-oriented, making scripting and automation work the same way on every command. No more guessing which column a specific value you are looking for is on like in bash. No more trimming whitespace and tab characters.

  • All loops automatically use the $_ notation for the object being looped over. So for example, every loop can reference $_.name to get the name property if it exists.

Bottom Line

Powershell is fundamentally a more intuitive and powerful scripting language than bash. However, the most symmetrical comparison for Powershell would be something we didn’t compare: python.

There is little reason to use Powershell on Linux because it’s not often packaged with Linux. However, python is more powerful than bash and is your most likely target language on Linux for automation. The only caveat is that you would want to use bash for system calls and configuration, and then have Python specifically for automation. Whereas, on windows, PowerShell can do it all.

If you are using Windows and looking to script and automate, PowerShell is your friend.

Graham Steffaniak
Built with Hugo
Theme Stack designed by Jimmy