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 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
The Most Important Commands
Two commands form the foundation for everything in PowerShell:
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.
Get-ChildItem gives the contents of a folder, getting the folder itself is handled with
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>
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.
In the next article we will look at scripts and writing logic in PowerShell. Until then, go download PowerShell Core and practice using
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.
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].