The Evolution of the Shell: PowerShell
As a software developer by trade and by passion, I find the PowerShell to be an incredibly flexible shell. Personally, I feel that it is what shells were always meant to be. Object-piping feels so natural, it enables us to access specific parts of output from a command without parsing. How awesome is that?
To fully appreciate that we should perhaps take a quick look at how it used to be done in the various other shells.
Text output is the past
Traditionally all output of commands used to be text. Therefore, if we wanted to get a specific piece of information to be passed to the next command, then we had to parse. The following question was asked on stackoverflow and demonstrates the problems with that quite nicely: How do I get the IP address into a batch-file variable?
Let’s take a look at what the output of the ipconfig command typically looks like:
Windows IP Configuration Ethernet adapter vEthernet (N1): Connection-specific DNS Suffix . : local.vm IPv4 Address. . . . . . . . . . . : 192.168.199.102 Subnet Mask . . . . . . . . . . . : 255.255.255.0 Default Gateway . . . . . . . . . : 192.168.199.1
The IP address can be easily spotted by its label. Extracting it however is a bit of a hassle, as the accepted answer demonstrates:
@echo off set ip_address_string="IP Address" rem Uncomment the following line when using Windows 7 (with removing "rem")! rem set ip_address_string="IPv4 Address" for /f "usebackq tokens=2 delims=:" %%f in (`ipconfig ^| findstr /c:%ip_address_string%`) do echo Your IP Address is: %%f
Relying on a label or structure within a text output is highly fragile. It may simply change between versions. Also, when we choose our criteria for identifying some piece of data, it might work at first, but may fail later on, when the data has changed, because it has become ambiguous.
In this particular case the ipconfig command uses the label “Ipv4 Address”. However, in earlier versions of windows the label was “IP Address”.
While different text-based shells may have different sets of commands, the same principles do apply.
Back to the present and onwards into the future
So, how would this be done in the PowerShell? One line – it is that simple. So in detail, what does the above line mean exactly?
Get-NetIPAddress | % { $_.IPAddress }
The cmdlet Get-NetIPAddress will write objects to the pipeline. Zero or more. The pipe operator passes these to the next command which is a loop over the items. Within the loop we can specify what should be done with each of the items. This can be a single command, or several.
We could however also decide to filter the data. When having a lot of network interfaces we might want to filter them by address family or adapter name. We might also want to display only certain properties of the results in a tabular fashion.
Get-NetIPAddress | where { $_.AddressFamily -eq "IPv4" } | Format-Table -AutoSize -Property InterfaceAlias,IPAddress
The output should look like this:
InterfaceAlias IPAddress -------------- --------- vEthernet (Nat001) 192.168.64.1 Ethernet 192.168.96.100 Loopback Pseudo-Interface 1 127.0.0.1
In my next post, I’ll go more into the details about how to make good use of the PowerShell pipeline, such as concatenating cmdlets and filtering their output. Stay tuned.