Foundational PowerShell For Developers – Part 1

Foundational PowerShell

PowerShell Introduction

When Microsoft introduced PowerShell in the mid-2000’s, it was a pretty big deal. The venerable cmd.exe (based on DOS’s command.com) was not very effective in comparison to open source shells popping up on Windows that drug half of a GNU/Linux installation along with them. About 13 years ago I wrote about Microsoft’s new wunder-shell. Everything in there still applies today, so I suggest a quick read at some point.

Today I am focusing on using Foundational PowerShell as part of your development process. BASH users have been doing these things for decades and it’s time that all Windows developers start using PowerShell to it’s fullest extent. But first, baby steps. Over a series of articles I will explain the foundation concepts and commands in PowerShell and how and why to use them for things like build automation, deployments and CI/CD. PowerShell brings a unique identity position to these things that other shells don’t match. Whether you are using Windows or Linux, PowerShell can and should become your primary CLI environment. Lets get into Foundational PowerShell.

PowerShell Basics

PowerShell is written in DotNet and everything runs in managed sandboxes. There are multiple levels of trust that can be applied to code whether it resides in a module, a script or a single command.

PowerShell comes in two flavors: Windows PowerShell, and PowerShell Core. Windows PowerShell is based on .NET Framework and obviously runs natively on Windows while PowerShell Core is cross-platform and runs on Windows and Linux. Updating Windows PowerShell is done via updating your Windows Management Framework. PowerShell Core is distributed as a standalone installer for Windows and through various packages for Linux, all of which are available from the Releases page on GitHub.
Under the hood, PowerShell operates as a Context object representing a session. The Context contains all the state of the session and marshals calls to the underlying OS based on configured security settings. PowerShell exposes a set of services that can be used to connect to a session on another machine and operate as if you were physically on that machine, much like ssh on *nix systems. This is handled with WinRM, and is something that you should get very familiar with if you deploy to other systems or manage multiple machines in a farm.

PowerShell is how DevOps is Done Right — The Sharp Ninja

PowerShell code exits in three flavors: scripts (PS1 files), modules (PSM1 files) and assemblies (DLL files). Because PowerShell is DotNet code running in the CLR, it can utilize the full DotNet ecosystem. Any conceivable project can be implemented in PowerShell and distributed as modules (a combination of a manifest, scripts and assemblies in a nuget package) that can be distributed from any Nuget server, including Microsoft’s PowerShell Gallery. Using OneGet, which is part of both Windows PowerShell and PowerShell Core, it is easy to find and install PowerShell Modules using the Get-Module and Install-Module commands.

The Most Important Commands

Two commands form the foundation for everything in PowerShell: Get-Item and Get-ChildItem. The former is used to get a single item to work with, the latter is for working with collections of child items.

Commands can be chained using the Pipe | operator which takes the object output of a command and passes it as the first parameter of the chained command. Let’s look at an example:

PS C:\Users\payton.byrd> Get-ChildItem .nuget


    Directory: C:\Users\payton.byrd\.nuget


Mode                LastWriteTime         Length Name
----                -------------         ------ ----
d-----        5/19/2020   4:21 PM                packages
d-----         2/9/2020  12:44 PM                plugins


PS C:\Users\payton.byrd> Get-ChildItem .nuget | Write-Host
packages
plugins
PS C:\Users\payton.byrd>

Here we are in my profile folder and perform Get-Item on .nuget which is my Nuget home folder. Calling the command with processing or piping the output send the results to the default formatter for a folder (the type of Item representing .nuget).
By piping the result to the Write-Host command, the list of items in the folder is written through the default array formatter specified by Write-Host, which simply outputs the Name property of the Item (if it has one), otherwise the .NET ToString() method is called on the items of the collection.

You can also capture the output to a variable.

PS C:\Users\payton.byrd> $a = Get-ChildItem .nuget
PS C:\Users\payton.byrd> $a


    Directory: C:\Users\payton.byrd\.nuget


Mode                LastWriteTime         Length Name
----                -------------         ------ ----
d-----        5/19/2020   4:21 PM                packages
d-----         2/9/2020  12:44 PM                plugins


PS C:\Users\payton.byrd> $a | Write-Host
packages
plugins
PS C:\Users\payton.byrd>

As you can see, outputting the contents of $a gives the same results as outputting directly from the command.
Whereas Get-ChildItem gives the contents of a folder, getting the folder itself is handled with Get-Item.

PS C:\Users\payton.byrd> $b = Get-Item .nuget
PS C:\Users\payton.byrd> $b


    Directory: C:\Users\payton.byrd


Mode                LastWriteTime         Length Name
----                -------------         ------ ----
d-----         2/9/2020  12:44 PM                .nuget


PS C:\Users\payton.byrd> $b | Write-Host
C:\Users\payton.byrd\.nuget
PS C:\Users\payton.byrd>

We can use that reference to the .nuget folder in many ways.

PS C:\Users\payton.byrd> $b | Get-ChildItem


    Directory: C:\Users\payton.byrd\.nuget


Mode                LastWriteTime         Length Name
----                -------------         ------ ----
d-----        5/19/2020   4:21 PM                packages
d-----         2/9/2020  12:44 PM                plugins


PS C:\Users\payton.byrd> $b.FullName
C:\Users\payton.byrd\.nuget
PS C:\Users\payton.byrd> $b.Name
.nuget
PS C:\Users\payton.byrd>

The output of commands are objects. PowerShell has many built in objects for files, collections and such, but any .NET object can be obtained and used as well.

PS C:\Users\payton.byrd> [string]$c = $b.FullName
PS C:\Users\payton.byrd> $c
C:\Users\payton.byrd\.nuget
PS C:\Users\payton.byrd> [string]::IsNullOrEmpty($c)
False
PS C:\Users\payton.byrd>

Here we declare $c as a string and place the FullName of our nuget folder in it. Then we call a .NET Framework method, string.IsNullOrEmpty() on it.

In this way we have the entire .NET ecosystem available to us. If you want to use the Dotnet Core runtime and libraries, you use PowerShell Core. If you want .NET Framework CLR and libraries, use Windows PowerShell.

Next Steps

In the next article we will look at scripts and writing logic in PowerShell. Until then, go download PowerShell Core and practice using Get-Item and Get-ChildItem. Also, learn about the -Recurse flag and how it allows you to process trees of data.

For more great content, check out the Resource Centre

About the Author:

Life-long programmer and big-picture-thinker. I love to solve problems big and small and am insatiably curious.

Reference:

Ninja, S. (2020). Foundational PowerShell For Developers – Part 1. Available at: https://dev.to/sharpninja/functional-powershell-for-developers-part-1-23b4 [Accessed: 22nd May 2021].

Share this on...

Rate this Post:

Share: