From Linux to PowerShell

Jody Whitlock

Introduction

For many folks coming from a Linux background into Windows, there is a learning curve in the change of toolsets. For instance, by default one doesn’t have Perl, Sed, Awk, or Grep. This can present a challenge, even for those that are moving from a VMware ESX environment where you SSH into a host to a ESXi environment where PowerCLI and PowerShell rule the day. This article is aimed to assist in that transition and reduce the learning curve.

For many who are used to Perl, one can install Perl in Windows using ActiveState, but that may not always be the best option. Microsoft’s PowerShell is built using some of the best concepts of Perl, Bash, and various other Linux scripting architectures. The major difference with PowerShell is that this is truely an interactive shell similar to Bash, where everything you do persists throughout the shell. In addition, like Perl, one does not have to implicitly type-cast variables, but unlike Perl, PowerShell (which is built on top of .Net Framework) treats everything like Objects and is very good at internally type-casting objects depending on the data put into them.

One thing very similar to Bash and Linux is the pipe operator, which in PowerShell takes the output objects from the left of the pipe and passes them as input to the command on the right of the pipe. This can be extremely powerful and confusing all at the same time.

In that, PowerShell is about 90% the same as Bash and Perl, with many constructs being the same, such as For loops and If..Then. The major difference in PowerShell is everything is Verb-Noun based as far as commands, so for example to read a file is Get-Content and not cat.

In this, one nice feature of PowerShell is the ability to create alias’ in a profile that can map commands to a name, so one can create an alias for Get-Content and call it cat. Below there will be some examples of alias’ that can assist in the transition, and some tips ‘n tricks that can help speed up the transition from Bash/Perl to PowerShell.

One very important thing to note, PowerShell loves RegEx (Regular Expressions) and by default uses RegEx for matching and parsing. The PowerShell RegEx engine is based on the .Net RegEx class, which, not surprisingly, was built directly from the Perl RegEx engine. So RegEx from Perl is directly translatable to PowerShell, and vice-verse.

So in starting out, one may want to parse through some of the built-in alias’ and commands by running the following commands in PowerShell:

  • Get-Alias | more – Yes, I used the familiar more command in PowerShell. Can you start to see where things are the same?

Examples

Man

I wanted to start off with this because I think this is a very distinct advantage that sets PowerShell apart from everything else. In Linux, for Bash items you can use Manpages (if available) to get some help, such as man cat. Perl doesn’t have a direct translation for this, but PowerShell does, and it’s called aptly Get-Help, which has a built in alias called coincidentally man. The advantage is that as one writes a script or commendlet in PowerShell, the help documentation is integrated into the script directly, removing the need for separate documentation files.

Grep

In Linux, one can search for a string of text in a file using grep, an example being grep mytext -f * -r to search for mytext in all files in all subdirectories. There’s actually two ways to do this, one uses the DOS command findstr and the other uses the PowerShell command Get-String

For FindStr, this website FindStr Help Page, and the equivalent command from above would be findstr -l -c:"mytext" –s
The above is very slow as FindStr is actually an old 32-bit binary that has not been optimised or updated. I much prefer PowerShell for this using the built-in PowerShell alias cat, which is an alias for Get-Content.

So, the equivalent grep command in PowerShell uses a pipe like so:
cat somefile.txt | where { $_ -match "expression"}
The -match operator in PowerShell uses the RegEx engine to perform pattern matching.

Sed

What about sed or awk? Well, it’s actually only just a slight variation of the above command as follows:
cat somefile.txt | %{$_ -replace "expression","replace"}

Wooh, what the heck is this percent crap! Well, if you go back to the Get-Alias | more you will see that % is an alias for ForEach-Object.

So what is happening above is we read the contents of somefile.txt and pipe the output to ForEach-Object (Remember in PowerShell everything is an Object, cat returns an array of objects representing each line of the file) to perform a line-by line replacement if the desired text (expression) with the new text (replace).

Awk

So what about good ole Awk? Well, let’s look at what a good use would be. Using Awk, it’s very simple to take a string, split it, then return only a particular index from the split. Well, PowerShell can do exactly the same, with some ease. Here we go.

Say you have a string from a log such as 2013-02-05 16:05:02 This is my log entry. In this example, we want to do a match on the third index, using space as the delimiter, then return the time stamp (index 0 and 1) of the entry. Now mind you, this is a crap example that would be a little funky in awk, and I will admin in PowerShell it is funky too, but here it goes:
cat access_log | ?{ $_ -match "entry" | %{ $_.Split(" ")[0,1] -join " " }

Wow! So first off, I used another alias, this time the ?, which is the same as Where-Object. Next, we can split (forgive the pun) this into three parts, separated by the pipe operator.
The first part is simple, get the lines of text from the log file. Next, this is not bad because we aren’t worrying about splitting the string yet, so we just search each object (line) for the existence of our text. Then, we pass all the objects to the third part, where we now split along our delimiter and return the first two indexes (date and time). Now in PowerShell, each item in an object array, which is the result of a split operation, is written on it’s own line. Because of this, I threw in the last join operator to make PowerShell print the timestamp of each found entry together on one line.

So, what if we have more lines? Well, the PowerShell code above will return each entry’s timestamp, one line for each entry, but just like Awk, what line was this found on? Well, in PowerShell, we can actually use the second method to replace grep, awk, etc, which is to use Select-String as such:

Select-string -Path access_log -Pattern 'entry' | Select FileName,LineNumber,@{N="TimeStamp";E={$_.Line.Split(" ")[0,1]}}, which gives us an object array that represents each matching item.
Now that seems a little crazy, so for things like this I would create a wrapper function in my profile or in a module so that I could do something like awk -Pattern "entry" -Files "access_log" or even something like awk -Pattern "entry" -Files (ls), which feeds an array of objects representing all files in the directory.

Noticed I used ls? Well, another built-in PowerShell alias is ls, which is actually Get-ChildItem, so as you can start to see, PowerShell is really designed to be easy to use for beginners, and also very familiar for those with experience in other platforms such as Linux.

Conclusion

So in conclusion, just because PowerShell is made by Microsoft and runs on Windows… Hang on there a second! Don’t get to far ahead of yourselves because there’s a project out there called PASH which uses the Mono Framework to host PowerShell on non-Windows platforms such as Linux, Mac OS, and even Solaris! Also, with Windows Server 2012, you can now run full PowerShell (not an implementation) using Windows 2012 PowerShell Web Access, which uses a web browser to execute remote PowerShell commands.

Now you may ask yourself why? Well, in the realm of Virtualization, specifically VMware, the non-GUI management has shifted from Perk SDK to PowerCLI, which is an implementation of VMware’s SDK/API’s on top of PowerShell.

So in conclusion (round two), don’t shy away from PowerShell because you have always used Perl or you think Microsoft is the evil empire. If you are in an enterprise environment, chances are you will use Windows, and if you are a VMware admin, you will not get new Perl SDK items going forward as it’s not in VMware’s best interest to maintain both Perl and the regular API’s that the Web Client, C# GUI, AND PowerCLI all use. They will maintain one effort going forward, as evidenced by William Lamb no longer developing the Perl SDK and working on PowerCLI.

PowerShell is a great replacement for Perl, or augmentation to Perl, and the learning curve from Perl/Bash to PowerShell is very small, so don’t shy away and dive on in, you may find the water isn’t as cold as you thought.