PowerShell Core for Linux Administrators Cookbook

4.5 (2 reviews total)
By Prashanth Jayaram , Ram Iyer
  • Instant online access to over 8,000+ books and videos
  • Constantly updated with 100+ new titles each month
  • Breadth and depth in over 1,000+ technologies
  1. Introducing PowerShell Core

About this book

PowerShell Core, the open source, cross-platform that is based on the open source, cross-platform .NET Core, is not a shell that came out by accident; it was intentionally created to be versatile and easy to learn at the same time. PowerShell Core enables automation on systems ranging from the Raspberry Pi to the cloud.

PowerShell Core for Linux Administrators Cookbook uses simple, real-world examples that teach you how to use PowerShell to effectively administer your environment. As you make your way through the book, you will cover interesting recipes on how PowerShell Core can be used to quickly automate complex, repetitive, and time-consuming tasks. In the concluding chapters, you will learn how to develop scripts to automate tasks that involve systems and enterprise management.

By the end of this book, you will have learned about the automation capabilities of PowerShell Core, including remote management using OpenSSH, cross-platform enterprise management, working with Docker containers, and managing SQL databases.

Publication date:
November 2018
Publisher
Packt
Pages
566
ISBN
9781789137231

 

Chapter 1. Introducing PowerShell Core

In this chapter, we will cover the following recipes:

  • Installing PowerShell
  • Updating and using Help
  • Exploring the about_topics
  • Discovering cmdlets
  • Finding and installing PowerShell modules
  • Listing the various providers in PowerShell
  • Understanding objects
  • Parsing input from text to object
  • Comparing the outputs of Bash and PowerShell
  • Comparing Windows PowerShell and PowerShell Core
  • Working with aliases
  • Dissecting a .NET Core Object
  • Listing the execution policies and setting a suitable one
 

Introduction


Carl Sagan once said the following:

If you are skeptical, then no new ideas will make it through to you. You will never learn anything new. You become a crotchety old person convinced that nonsense is ruling the world. (There is, of course, much data to support you.) But every now and then, maybe once in a hundred cases, a new idea turns out to be on the mark, valid, and wonderful. If you are too much in the habit of being skeptical about everything, you are going to miss or resent it, and … you will be standing in the way of understanding and progress.

 

Us system administrators start building our arsenal of administration tools from the very first day. Usually, we do not think of adding tools to do something that our favorite already does—this would be like adding a redundant weapon. However, these alternate tools turn out to be great. PowerShell, to me, was one such tool.

There is a good chance that you are reading this page at a bookstore—digital or physical—and there is a good chance that the question in your mind is, Is this book for me?

The answer is probably yes, if you are any of the following:

  • A Linux administrator, open to other scripting frameworks
  • A system administrator who manages Linux as well as Windows workloads, looking to unify management
  • A Linux administrator who wants a framework that handles—and aces in—structured data (as a side note, PowerShell is probably the only framework in Linux that works well with structured data)
  • A Windows Administrator, new to PowerShell, wanting to learn PowerShell scripting
  • A generally curious system administrator

A brief note on .NET Core

Microsoft's announcement of open sourcing .NET in 2014 almost stirred a storm. Many rushed to the stands (so to speak) to read about the unbelievable—how could Microsoft possibly open source the core of their operating system? Some were cynical, while others rejoiced. Then came the announcement—a little louder and clearer—that .NET Core was open source, not the .NET Framework. Many said that .NET Core was a subset of .NET Framework.

.NET was first announced in 2000, as a new platform based on internet standards. Along with it, by the end of the year, Microsoft published the Common Language Infrastructure as a standard, so that anyone who wanted could write their own .NET framework based on those standards. .NET Framework has been the basis of Windows since the noughties.

Windows PowerShell was released to the general market in 2006, as an implementation of .NET Framework, and focused on system administrators (or sysadmins), enabling them to better manage their workloads or daily activities and automate them. PowerShell 1.0 was leaps and bounds ahead of the hitherto rulers of automation Windows: Batch and VBScript.

 

In June, 2016, Microsoft released a collaboratively refactored, more modern and efficient .NET. The .NET Core was officially born. While .NET Framework continues to rule the Windows arena, .NET Core, which is open source and cross-platform, has picked up great momentum and grows every day. .NET Core seems to be the way forward.

PowerShell Core is based on .NET Core, and therefore is open source, with the same vision as .NET Core: to be cross-platform.

The assumptions

This book assumes no experience in PowerShell, and so sticks to the basic and intermediate levels. That is to say, we will not create complex PowerShell modules in this book. We will start by installing PowerShell, understanding the object model, working through scripting by understanding PowerShell constructs, creating functions, creating simple script modules, and so on, as system administrators (and not as programmers). We will also learn how to manage Docker and cloud workloads using PowerShell.

How to read this book

You may skip recipes or even chapters. Whenever there is a need for something we created in a recipe that you have skipped, we will mention the recipe in the prerequisites. For example, we will state something similar to the following: follow the How to do it… section of the skipped recipe to fulfill this prerequisite.

An important note

There are two editions of PowerShell available today:

  1. Windows PowerShell (up to v5.1, proprietary; powershell)
  2. PowerShell Core (6.0+, open source; pwsh)

Windows PowerShell is based on .NET Framework, which is Microsoft's proprietary framework that Windows is built on. PowerShell began at 1.0, and was considered feature-complete at 5.1. Microsoft has stopped developing Windows PowerShell; going forward, it will only receive bug fixes.

The open source PowerShell Core 6.0 is based on the open source .NET Core. This book is about open source PowerShell. Windows PowerShell and PowerShell Core are two different entities, with two different code bases.

 

 

While PowerShell to a Windows administrator has so far meant Windows PowerShell, officially, PowerShell now means the open source PowerShell Core. In this book, we follow this convention: going forward, every mention of PowerShell points to the open source PowerShell Core 6. Windows PowerShell is referred to as Windows PowerShell.

Writing the cmdlets (Linux admins note)

If you are a Linux administrator, chances are, you do not like long commands—verbosity, to be specific. We will try to make the commands as short as possible, but in the interest of readability (which is an important convention in PowerShell), we will also mention the full commands.

Note

Tab completion comes in handy for reducing keystrokes. PowerShell tab-completes cmdlets, parameters, and in many cases, even parameter values. We will learn about this in the Running cmdlets with minimal keystrokes section of Chapter 2, Preparing for Administration Using PowerShell.

In general, we split scripting from running cmdlets on the console in the following ways:

  • By using aliases (carefully) and short parameter names at the Terminal to save keystrokes and time
  • By being verbose in scripts, so that everyone using them can read and understand them

Off we go

This is where it all starts: with the installation of PowerShell on your system. The installation of PowerShell is simple and straightforward. Since PowerShell is open source, its source code is available on GitHub. At the moment, Windows, Debian (and Ubuntu), Red Hat Linux (and CentOS), Fedora, OpenSUSE, and macOS are officially supported by the PowerShell project. Arch Linux and Kali Linux are supported by the community, as indicated in the README project. Community support is also available for the Snapcraft edition of PowerShell, which can be used on many of the modern-day Linux distributions.

PowerShell 6, at the time of writing this book, is experimentally available for Raspbian Stretch as well as the ARM edition of Windows (https://github.com/PowerShell/PowerShell/blob/master/README.md).

 

Installing PowerShell


In this book, we will focus on installing PowerShell on Ubuntu (16.04 and 18.04) and CentOS 7, since Ubuntu and CentOS were among the first to be supported by the PowerShell project.

PowerShell is available in two releases: stable and preview. The stable releases are suitable for a production environment since they are more reliable. The preview releases are for test environments where the administrators are allowed to feel a little adventurous. The expectation from the administrators is to report bugs they come across, along with providing feedback on the capabilities of it.

Note

As of the Preview 4 release of PowerShell 6.1, pwsh (stable) and pwsh-preview (preview) can be installed side by side, without the worry of interference.

Getting ready

Linux administrators will already know how to do this. If you are new to Linux, getting ready to install PowerShell on your computer is simple. You simply need a working Linux computer that you have administrator privileges on. Depending on what mode you pick to install PowerShell, you may or may not need a package manager. Chances are, your Linux distribution already has a package manager available.

Also, many of the future recipes will require a desktop environment so that you can work with tools such as Visual Studio Code.

Ubuntu does not ship with curl. Install curl by running the following command:

$ sudo apt install curl

How to do it…

As we have already discussed, we will look at the procedure of installing PowerShell on Ubuntu (and its derivatives) as well as CentOS (and its derivatives).

Installation on Ubuntu

There really are many ways to install PowerShell on your computer. Since we are installing PowerShell on Ubuntu, we will look at two ways of doing so. The first is by adding Microsoft's key, registering the repository, and then using the Advanced Package Tool (APT) to install PowerShell. The second method is by doing so directly, using the .deb package from GitHub.

Installing from the repository

Ubuntu 16.04 and Ubuntu 18.04 have the stable release of PowerShell available. Follow these steps if you wish to install PowerShell on Ubuntu:

  1. Download the GPG keys for the Microsoft repository:
$ # On Ubuntu 16.04
$ wget -q https://packages.microsoft.com/config/ubuntu/16.04/packages-microsoft-prod.deb

$ # On Ubuntu 18.04
$ wget -q https://packages.microsoft.com/config/ubuntu/18.04/packages-microsoft-prod.deb
  1. Register the GPG keys:
$ sudo dpkg -i packages-microsoft-prod.deb
  1. Update the package list using the following command:
$ sudo apt update
  1. Install PowerShell using apt-get:
$ # To install PowerShell (stable)
$ sudo apt install -y powershell

$ # To install PowerShell (preview)
$ sudo apt install -y powershell-preview

 

  1. Run PowerShell using the following command:
$ # If you installed PowerShell (stable)
$ pwsh

$ # If you installed PowerShell (preview)
$ pwsh-preview
Installing via direct download

Follow these steps to install PowerShell on Ubuntu:

  1. Go to https://github.com/powershell/powershell.
  2. Scroll down to the table that contains the list of Linux distributions officially supported by the PowerShell team.
  3. Click on the relevant link, that is, .deb under Downloads (stable) or Downloads (preview).
  4. Read the installation instructions if you need additional information.
  5. Use dpkg to install the package:
$ sudo dpkg -i powershell-version-os-osversion_architecture.deb
$ sudo apt install -f

Installation on CentOS

The installation of PowerShell on CentOS 7 (or Red Hat 7) also has two methods: the repository and a direct download. The process is similar to that of installation on Ubuntu Linux. While it is recommended that PowerShell is installed from the repository, use the second method—the direct download method—should you choose otherwise.

Installing from the repository

To begin the installation, follow these steps:

  1. First, register the Microsoft repository:
$ curl https://packages.microsoft.com/config/rhel/7/prod.repo | sudo tee /etc/yum.repos.d/microsoft.repo
  1. Next, install PowerShell using yum:
$ sudo yum install -y powershell

 

Installing via direct download

Follow these steps to install PowerShell on CentOS:

  1. Go to https://github.com/powershell/powershell.
  2. Scroll down to the table that contains the list of Linux distributions officially supported by the PowerShell team.
  3. Click on the relevant link, that is, .rpm under Downloads (stable)—we will stick to the stable release.
  4. Read the installation instructions if you need additional information.
  5. Install the RPM package using the following command (assuming your download is at ~/Downloads and your pwd is ~/Downloads):
$ sudo yum install <the-downloaded-file.rpm>

Using the Snapcraft package

If your distribution supports the installation of Snapcraft (snap) packages, you can install PowerShell using the snap command:

  1. Install snapd if you do not already have it. Here is how you do this on Ubuntu:
$ sudo apt install snapd
  1. Next, install the PowerShell Snapcraft package:
$ snap install powershell --classic
  1. You may be prompted for your credentials. Enter your credentials at the prompt.
  2. Launch PowerShell:
$ pwsh

 

Using the binary archives

If your package manager does not have PowerShell, use the binary archives:

  1. Install the dependencies based on your operating system. Here are the dependencies required in the case of Ubuntu 16.04, Ubuntu 18.04, and CentOS:

Operating System

Dependencies

Ubuntu 16.04

libc6, libgcc1, libgssapi-krb5-2, liblttng-ust0, libstdc++6, libcurl3, libunwind8, libuuid1, zlib1g, libssl1.0.0, libicu52

Ubuntu 18.04

libc6, libgcc1, libgssapi-krb5-2, liblttng-ust0, libstdc++6, libcurl3, libunwind8, libuuid1, zlib1g, libssl1.0.0, libicu60

CentOS7

libunwind, libcurl, openssl-libs, libicu

  1. Use curl to get the archived file:
$ curl -L -o /tmp/powershell.tar.gz https://github.com/PowerShell/PowerShell/releases/download/v6.1.0/powershell-6.1.0-linux-x64.tar.gz
  1. Create the directory where PowerShell will be installed:
$ sudo mkdir -p /opt/microsoft/powershell/6.1.0
  1. Unpack the binaries into the directory you just created:
$ sudo tar zxf /tmp/powershell.tar.gz -C /opt/microsoft/powershell/6.1.0
  1. Add execute permissions to the file:
$ sudo chmod +x /opt/microsoft/powershell/6.1.0/pwsh
  1. Create a symbolic link to point to pwsh:
$ sudo ln -s /opt/microsoft/powershell/6.1.0/pwsh /usr/bin/pwsh

Bonus– using the Install-PowerShell script (including on macOS)

The official PowerShell repository has a script that detects your operating system and installs PowerShell based on the operating system and the distribution.

 

 

Your computer must have the following:

  • The Bash shell
  • sed
  • A native package manager

We need the Visual Studio Code IDE so that we can follow the exercises in this book. Run the following command to commence the installation:

$ bash <(wget -O - https://raw.githubusercontent.com/PowerShell/PowerShell/master/tools/install-powershell.sh) -includeide

Note

If you do not have a desktop environment on your computer, you will not be able to install Visual Studio Code. Either install a desktop environment or omit the -includeide switch.

For more information, go through the README file at https://github.com/PowerShell/PowerShell/blob/master/tools/install-powershell-readme.md.

How it works…

The package manager installs the package with all of its dependencies and makes the relevant commands available for use.

Starting with Snap 2.20, you can install Snapcraft packages with relaxed security boundaries using the --classic switch. Snaps usually run in a sandboxed environment, meaning that they are separated from the host, so to speak. However, PowerShell, being a shell, needs access to all of the host resources so that it can function as desired, hence the --classic install. Also note that this is not supported on systems such as Ubuntu Core.

See also

  • The Comparing Windows PowerShell and PowerShell Core recipe
 

Updating and using Help


Help documentation is very important in PowerShell, regardless of whether a certain cmdlet is packaged by providers such as Microsoft, VMware, or Citrix, or community-created. Help is not a switch in PowerShell. PowerShell uses the Get-Help cmdlet (pronounced command-let) to fetch the Help information enclosed within cmdlets.

By default, PowerShell is installed with minimal Help information, which contains only the description and the parameters. In this recipe, we will update Help and learn to get Help by using cmdlets, specific parameters, or certain keywords.

Getting ready

To go through this recipe, you must have PowerShell 6 installed on your computer, and you must have administrator privileges available. To install PowerShell, refer the Installing PowerShell recipe in this chapter.

How to do it…

To update the Help files for the locally installed PowerShell modules, follow these steps:

  1. Type exit to exit PowerShell. This is so that you can relaunch PowerShell with elevated privileges. This is required for some of the modules, based on the permissions used to install them.
  2. Enter sudo pwsh (or sudo pwsh-preview) to launch PowerShell as a superuser.
  3. At the PS> prompt, run Update-Help.
  1. Wait for the update progress bar to appear. The bar will fill as the Help files download onto your computer:
  1. Use exit to exit PowerShell as a superuser, and launch PowerShell as a regular user.

We can now proceed and fetch Help information for other cmdlets.

  1. At the command prompt, enter the following command:
PS> Get-Help Write-Host

 

You will get an output similar to the following:

  1. Next, gather different levels of Help information by using the following commands:
PS> Get-Help Write-Host -Full
PS> Get-Help Write-Host -Examples
PS> Get-Help Write-Host -Online
  1. Pass a different cmdlet as a parameter to Get-Help. Note the two groups of parameters:
PS> Get-Help Get-Command
  1. Compare the outputs of the different commands you ran.
  2. Now, look for Help information for the specific parameter of Write-Host (the second command in the following code is for reference; this states what the first command means to PowerShell):
PS> get-help write-host -par foregroundcolor
PS> # Verbose version: Get-Help -Name Write-Host -Parameter ForegroundColor

 

Now let's look for a certain keyword within the Help information:

  1. Convert the output of Get-Help Get-Command into text, one string at a time, rather than putting in the entirety of the Help information as a single string:
PS> get-help get-command | out-string -s
PS> # Verbose version: Get-Help Get-Command | Out-String -Stream
  1. Pipe this to the Select-String cmdlet to perform a grep-like operation:
PS> get-help get-command | out-string -s | select-string 'wildcard'
PS> # Verbose version: Get-Help -Name Get-Command | Out-String -Stream | Select-String -Pattern 'wildcard'
  1. This gives you an output of a line that contains wildcard:

How it works…

It is inconvenient to leave your Terminal to read Help online. We would prefer to have all of the Help available locally. PowerShell can potentially work on low-memory devices such as Raspberry, but saving all of the Help in the limited space we have is not advisable. This is one of the reasons PowerShell comes with minimal Help by default. The reason updating Help requires elevated privileges is that the Help information is stored within the shell. Therefore, non-administrators may not be able to update Help without administrator intervention.

As a general practice, cmdlets come pre-packaged with Help information, and Get-Help works like the man command in Linux. The output of Get-Help has the name of the cmdlet, the syntax to use with the cmdlet, the alias(es) available for the cmdlet and more online Help if required. -Full and -Examples are (mutually exclusive) switches that tell PowerShell about the level of Help you need.

 

The groups of parameters, as seen in the case of Get-Command, under SYNTAX, are called parameter sets. They tell us which parameters can be used together. Parameters not appearing in the same parameter set cannot be used together. For example, you cannot use -Noun and -Name with Get-Command at the same time; it wouldn't be logical to do so.

If the Help information seems elaborate, and you would like to learn about a specific parameter of a cmdlet, you can specify that parameter, and the Help will be filtered accordingly. Since the output of most PowerShell cmdlets is objects, it is easy to select the necessary object and discard the rest from the output. Also note that this is the recommended approach to fetch Help that's specific to a certain parameter.

Note

PowerShell, in general, is case-insensitive. Therefore, Noun and noun, or Parameter and parameter, mean the same thing to it. The use of CamelCase is the general convention in PowerShell. With the almost ubiquitous tab completion, this is a cakewalk.

Next, let's talk about searching Help for specific keywords. PowerShell outputs objects. However, at the end, when the content comes to the host, the content can be processed by Linux commands such as grep. Therefore, to search Help for specific keywords, you could always pipe the output to grep. If you would like to go the PowerShell way (especially if you go by the write once, run everywhere philosophy), this requires minor modifications. First, we fetch the Help; the output is an object (so that it can be processed further if needed). We convert this into a string using Out-String, since search is nothing but string matching.

PowerShell cmdlets output single or multiple instances of objects (we will discuss objects in more detail in the Understanding objects recipe). Out-String waits for all of the Get-Help commands to be processed and converts the output into a single concatenated string. To break the string into chunks, we use the -Stream switch, which instructs Out-String to not concatenate the output. This way, each paragraph is processed separately. Next, we use the Select-String cmdlet, along with the search keyword to perform keyword matching. The output of this is the chunk (paragraph, in this case) with the keyword.

See also

  • The Working with aliases recipe
  • The Updating and using Help recipe
  • The Running cmdlets with minimal keystrokes recipe in Chapter 2, Preparing for Administration using PowerShell

 

 

 

 

Exploring about_ topics


Documentation is one of the key strengths of PowerShell. While not all modules have complete documentation, all of the modules written by Microsoft, along with the well-done third-party ones, do. By default, PowerShell itself has exhaustive documentation built within it. In this recipe, we will look at about_ topics, pick one of the topics from the output, and read more about the subject we picked.

Getting ready

A prerequisite to be able to fetch any output in this recipe is to update the local copy of PowerShell Help documentation. Follow the Updating and using Help recipe to update the local PowerShell Help documentation.

How to do it…

Let's begin by listing all of the about_* Help files:

  1. List all the about_ topics:
PS> get-help about_*
  1. Display the documentation about PowerShell modules:
PS> get-help about_modules

How it works…

Get-Help gives you information about cmdlets if the cmdlet is passed as an argument. In cases where you know only a part of the name of the cmdlet, you can use a combination of characters and wildcards to list out cmdlets that match the search string (about_*, in our case).

Now, we can pick the topic we would like to read about and enter that specific about_ topic. Get-Help shows the complete documentation about the topic.

 

 

Discovering cmdlets


So far, we have seen how we can get Help on cmdlets. We used the Get-Command cmdlet as an example argument. Now, we are going to use Get-Command to discover cmdlets in PowerShell. Get-Help and Get-Command become the two most important cmdlets when you need any Help information in PowerShell.

PowerShell is like plain English—PowerShell follows the Verb-Noun format in cmdlet naming, which makes the cmdlets sound like plain English commands. It is a convention in PowerShell to use approved verbs, which ensures that verbs are limited in order to facilitate discovery. The nouns, on the other hand, can be arbitrary.

Note

Thinking in the scripting/programming language of your choice, along with muscle memory, is key to speed and efficiency. PowerShell's English-like structure helps in this regard; it is easy to think in PowerShell. For instance, if you would like to know the current date, all you have to say is Get-Date, and PowerShell will print the date and time on the screen for you.

How to do it…

Get-Command can help determine the best cmdlet for a task. To find cmdlets, follow these steps:

  1. Enter Get-Command to get a list of all of the available cmdlets in PowerShell. The number of cmdlets returned will change based on when you last updated PowerShell and the modules you have loaded:
PS> Get-Command

This may not be particularly useful—what would you do with a list of commands if you were looking for something to do with processes?

  1. The lazy way of doing this is by using the following command:
PS> Get-Command *proc*
  1. To be specific and look for a command that deals with processes, use the following code:
PS> get-command -no process
PS> # Verbose version: Get-Command -Noun 'Process'

Note

In PowerShell, the convention is to always have the noun in the singular form. Therefore, it is always Process, Service, Computer, and so on, and never Processes, Services, Computers, and so on.

  1. To look for cmdlets that help you export objects, use the following code:
PS> get-command -v export
PS> # Verbose version: Get-Command -Verb 'Export'

Note

PowerShell has a standard set of verbs. This is to ensure the discoverability of cmdlets. If you use a nonstandard verb when creating your cmdlets, PowerShell will warn you that your cmdlet may not be discoverable. To get a list of approved verbs, run the Get-Verb cmdlet.

  1. The -Noun and -Verb parameters also accept wildcards:
PS> get-command -no proc*
  1. Imagine that you just installed a PowerShell module (more on that later) and would like to look for cmdlets packaged in the module. For this example, we will use the SqlServer module:
PS> get-command -v get -m sqlserver 
PS> # Verbose version: Get-Command -Verb 'Get' -Module 'SqlServer'

How it works…

PowerShell cmdlets are in the Verb-Noun form. The word appearing before the hyphen is the verb, and the one after is the noun. When cmdlets are loaded from modules, PowerShell identifies the verbs and the nouns in them. The search promptly returns the cmdlets based on the search specifications. Filters based on the name of the verb, noun, or even the module restrict the search accordingly.

 

Finding and installing PowerShell modules


Loosely coupling the components is one of the keys to the success of a framework. PowerShell follows this principle as well. All cmdlets are packaged within PowerShell modules. The modules can be first-party provided, created by you, or created by other software vendors.

 

Initially, extending PowerShell capabilities was done using snap-ins. With PowerShell 2.0, PowerShell modules were introduced. One other place that Microsoft has gotten it right is advocating the use of modules over snap-ins. The installation of PowerShell modules, which could have been a hassle in the past, has been streamlined today. PowerShell now comes pre-packaged with a package manager called PowerShellGet, which connects to the official Microsoft PowerShell Gallery (https://www.powershellgallery.com). The PowerShell Gallery is an online repository that contains modules, scripts, and other utilities that have been created by providers—as well as the community—that administrators can download and install to extend PowerShell's capabilities.

While it is possible to download PowerShell modules from third-party sites, our focus in this book will be on the PowerShell Repository.

How to do it…

We will start by finding cmdlets that work with modules, and proceed to work with these modules:

  1. Launch PowerShell by running pwsh on the Terminal.
  2. Look for commands that work with modules:
PS> get-command -no module PS> # Verbose version: Get-Command -Noun 'Module'

The output should look something like this:

 

Pick Find-Module for this task. If you would like to, use the Get-Help cmdlet to learn about what Find-Module does.

  1. Search for a module to help you work with Docker containers:
  1. Now, install the module. You will need to use superuser privileges to install the Docker module. Use the following command to install Docker without having to exit the current PowerShell session:
PS> sudo pwsh -c install-module docker

If you would rather use a new session and call the Install-Module cmdlet from within it, terminate the current PowerShell session and launch a new one with sudo:

  1. To update a module, use the Update-Module cmdlet:
PS> Update-Module docker
  1. To uninstall a module from the machine, use the Uninstall-Module cmdlet:
PS> Uninstall-Module docker

 

 

  1. To load a certain module into the current session, use the Import-Module cmdlet. You do not need elevated privileges to load or unload a module to or from the session:
PS> Import-Module docker
  1. To remove a module from the session, use the Remove-Module cmdlet:
PS> Remove-Module docker

How it works…

Hundreds of modules, scripts, and Desired State Configuration resources have been registered with the PSGallery repository. Microsoft now recommends using this repository for module management. Using the Find-Module cmdlet, PowerShell makes a connection to the repository and gets a list of all available modules. Then, it runs a search on the returned results based on the criteria you mention.

Note

In PowerShell, Find usually means working with the internet, and Get is usually used to get objects from the local machine.

You can also find scripts that can perform repetitive tasks. To find scripts, use the Find-Script cmdlet. It works similar to the Find-Module cmdlet, except that it finds individual scripts rather than modules.

Installation of modules is a simple process of pulling the modules down from the repository, similar to npm or chocolatey. These tasks are taken care of by the PowerShellGet module, which ships with PowerShell. Installing, updating, and uninstalling PowerShell modules may require elevated privileges.

To load the capabilities of a module into the PowerShell session, use Import-Module. PowerShell modules have members such as cmdlets, functions, aliases, and so on for sessions. Import-Module loads these members into the session. By default, the sessions are unloaded when exiting the session. However, if you would like to manually unload them, use the Remove-Module cmdlet. Remove-Module does not remove the entire module; it just unloads it.

 

The modules are installed in one of the $env:PsModulePath directories. You don't need to specify the path to modules that are installed this way. If the module files are saved elsewhere, you will need to specify the path to the module's psd1 or psm1 file when calling Import-Module. Also, some modules enable automated loading. Just call a cmdlet from the module, and the module will auto-import.

Import-Module has parameters such as -Prefix and -NoClobber. The -Prefix parameter adds the specified prefix to the nouns of all of the cmdlets in the module. For instance, Import-Module docker -pre dm will import the Docker cmdlets as Invoke-dmDockerCommand instead of Invoke-DockerCommand. The -NoClobber switch helps in cases where there may be cmdlet name conflicts; it prevents the already loaded cmdlets from being replaced by the ones from the module being imported.

There's more…

Try installing the module in portable mode, by first saving the module using Save-Module and then calling Import-Module with the path to the module file as the parameter.

You can also get the list of directories from which PowerShell discovers modules. At the prompt, type the following and press the Enter key:

PS> $env:PSModulePath

See also

  • The Writing a script module recipe in Chapter 12, Advanced Concepts of Functions
  • The Calling a PowerShell script recipe in Chapter 2, Preparing for Administration using PowerShell
 

Listing the various providers in PowerShell


Before we start preparing for administration using PowerShell, it would be helpful to understand the concept of providers.

 

How to do it…

To list the providers in PowerShell, follow these steps:

  1. Run pwsh to load PowerShell on the Terminal.
  2. Run the following command:
PS> Get-PsProvider

You will get something that looks like this:

Note the providers that are available in PowerShell, and the drives and capabilities found within these providers.

  1. Navigate to the Alias: drive:
PS> Set-Location Alias:
PS> Get-ChildItem

Note how the prompt is now Alias:

Note

Note the preceding colon after the drive name (Alias: and not Alias). This is necessary for you to indicate to PowerShell that you are switching drives. Without the colon, PowerShell would simply try to look for a directory called Alias in your present working directory.

How it works…

On Linux, PowerShell support is limited (at the time of writing this book). Discussion on the issues pertaining to providers on Linux indicates that further development is highly likely, especially regarding cross-provider support.

A provider is a program that logically represents non-filesystem drives as though they are drives. For instance, on Windows, the Registry is a database of configuration information. In PowerShell 6 on Windows and on Windows PowerShell, the Registry is a provider; this way, administrators can use PowerShell to navigate and manipulate Registry keys in the same way that we work with files. This capability is available on Linux as well, however, there aren't as many providers as there are on Windows.

Note

If you are interested in programming, providers in PowerShell are a great example of the concept of overloading in object-oriented programming.

The Name column gives the names of the providers. Each provider may have one or more drives. For instance, the FileSystem provider in Windows shows all of the partitions (C:, D:, E:, and so on) present on the computer. A Set-Location operation is performed on these drives within the providers, and not the providers themselves. To indicate to PowerShell that you are connecting to a drive and not a subdirectory, the name of the drive must be followed by a colon.

See also

  • The Adding safety switches to functions recipe from Chapter 12, Advanced Concepts of Functions

 

 

Understanding objects


PowerShell is object-oriented, text being an object too. An object in PowerShell contains entities within it, which are called members. These members can be referred to using what is called the member access operator, which is nothing but a dot (.). In this recipe, we will look at picking members from within objects.

Since we are going to be dealing with members of objects, we will now look at one of the most important cmdlets in PowerShell: Get-Member.

How to do it…

  1. We will start by gathering the properties of our home directory. The path to this is stored in the automatic variable known as $HOME:
PS> Get-Item $HOME | Get-Member

Note the TypeName of the object—the very first line—as well as the MemberType column in the table.

  1. Next, check when the home directory was last written to:
PS> (Get-Item $HOME).LastWriteTime
  1. Can we find out when the parent of your $HOME was created?
PS> (Get-Item $HOME).Parent | Get-Member
PS> (Get-Item $HOME).Parent.CreationTime

 

Note

To reiterate, PowerShell is not case-sensitive. However, to improve readability, we have stuck to the PowerShell convention of using camel case.

  1. What are the members of this object?
PS> (Get-Item $HOME).Parent.CreationTime | Get-Member
  1. Pick out the year:
PS> (Get-Item $HOME).Parent.CreationTime.Year

 

  1. Next, let's use a method from within the returned object and convert it into plain text. We saw that CreationTime is a DateTime object. Let's convert that into a plain string:
PS> (Get-Item $HOME).Parent.CreationTime.ToString()
  1. Find the type of object returned by the previous command. Press the up arrow key to bring back the previous command and pipe its output to Get-Member. Compare the output of Get-Member without .ToString():
PS> (Get-Item $HOME).Parent.CreationTime.ToString() | Get-Member
PS> (Get-Item $HOME).Parent.CreationTime | Get-Member

How it works…

This recipe is only here to show you that PowerShell outputs objects, and what an object looks like. We will look at leveraging the TypeName much later, when we modify the returned objects.

For now, we will stick to properties as the first step for understanding the object model of PowerShell. To demonstrate that methods are also available for use, we will use one that's among the simplest of them, the ToString() method; it's simple because it does not need any arguments—only empty parentheses.

The Get-Member cmdlet is very important in PowerShell because it lets you peek into the object that a certain cmdlet returned. It shows the type of the object returned (TypeName), and shows the properties and methods available. The properties and methods are of different data types themselves, which can be seen in the Definition column. As you get comfortable with objects, you will start to leverage these data types to simplify your tasks.

There's more…

Just because you can (and not because this is the way to do so), create a subdirectory within your home directory using the CreateSubdirectory() method from the object returned by Get-Item:

PS> (Get-Item $HOME).CreateSubdirectory('test-directory')

This should show you the new directory that you just created:

PS> Get-ChildItem $HOME # To list the contents of your home directory

See also

  • The Selecting columns from the output  recipe from Chapter 4, Passing Data Through the Pipeline
 

Parsing input from text to object


Moving to the object model from text could seem a little daunting at first. However, with PowerShell, it is not very hard to switch to the new model, especially given that PowerShell can convert text into objects given the right tools. In this recipe, we will look at two of the ways that PowerShell converts textual data into objects.

Getting ready

Before we dive into the recipe, let's give ourselves a little introduction to how text-to-object parsing is handled. One way is to use .NET's built-in functionality, and the second way involves using a cmdlet to perform the conversion based on a delimiter.

The basic requirement for this recipe is simple: you simply need PowerShell installed on your computer. We will edit the file within PowerShell. If you would be more comfortable using a text editor instead, that works as well. Most Linux distributions pack a text editor. If not, use your package manager to install Vim, Nano, Gedit, Visual Studio Code, Atom, or any other text/code editor.

 

How to do it…

First, we will look at converting text into an object from a plain text input at the Terminal. This involves using what is known as a PowerShell Type Accelerator. A PowerShell Type Accelerator is an alias for .NET classes. Using these, we can call .NET classes and use many of their functionalities within PowerShell:

  1. Let's take plain text as input and convert the text into a date object. To check what sort of object your input is, use the Get-Member cmdlet:
PS> '21 June 2018' | Get-Member

Note

Enclosing any text within single quotes defines the text as a non-expanding literal string. No explicit definition is required in this case.

  1. The TypeName says System.String. This confirms that what we entered was plain text. Now, let's use a Type Accelerator (or, more specifically, a cast operator) and convert this text into a DateTime object. The accelerator for this purpose is [DateTime]; place this accelerator before the literal string:
PS> [DateTime]'21 June 2018'

Thursday, 21 June 2018 00:00:00
  1. Next, find the TypeName of the object that was returned:
PS> [DateTime]'21 June 2018' | Get-Member

   TypeName: System.DateTime

Voila, the string has been successfully parsed into date and time!

  1. It is also possible to achieve the same result with the Get-Date cmdlet when it is called with the text argument:
PS> Get-Date '21 June 2018'

Thursday, 21 June 2018 00:00:00
  1. Similarly, the TypeName would be as follows:
PS> Get-Date '21 June 2018' | Get-Member

   TypeName: System.DateTime

 

  1. Just like we did in the previous recipe, we can now manipulate the object to show information in a more meaningful way. For instance, if you care only about the year, you would write the following:
PS> (Get-Date '21 June 2018').Year
2018

The other way of converting text into an object is to use cmdlets that perform such tasks. PowerShell packs a few converter cmdlets, one of which is Import-Csv. You may have noticed that PowerShell usually generates output in a tabular format. This is a simple representation of objects. The Import-Csv cmdlet converts data in a delimited row-and-column structure into objects, where each row is an instance of the object itself, and each column is a property of the object:

  1. To demonstrate this, let's create a CSV file with the following content in it. At the PowerShell prompt, type/paste in the following:
PS> @'
WS,CPU,Id,SI,ProcessName
161226752,23.42,1914,1566,io.elementary.a
199598080,77.84,1050,1040,gnome-shell
216113152,0.67,19250,1566,atom
474685440,619.05,1568,1566,Xorg
1387864064,1890.29,15720,1566,firefox
'@ | Out-File sample.csv

Note

You could perform the same operation using the touch command and the text editor of your choice. The goal is to get the content into the sample file.

  1. Next, read the contents of the file using PowerShell:
PS> Get-Content ./sample.csv
  1. That looks like simple text. Let's look at the type name of the object to confirm that this is indeed plain text. Type in the following:
PS> Get-Content ./sample.csv | Get-Member

   TypeName: System.String
  1. That is a plain and simple string. Now, let's convert the content into a simple object. This is done using Import-Csv:
PS> Import-Csv ./sample.csv

 

That should give you a list-like output, like so:

  1. To confirm that the output is objects, list out its members:

 

 

 

In general, the content is a custom object, which is denoted by PSCustomObject. The columns we had in the CSV are of type NoteProperty, as shown by MemberType.

A NoteProperty is a generic property whose characteristics are similar to those of a string. While most properties are inherited from .NET, NoteProperty is custom-created within PowerShell as a name-value pair.

  1. If you would rather look at the content as a table, format the content as a table. You can do this by using the following command:
PS> Import-Csv ./sample.csv | Format-Table

We have successfully converted text into an object. However, note that this is just a simple conversion, and that the output of Import-Csv is still string-like. Although all of the content is now string-based objects, these are easier to handle in PowerShell.

Also note that Format-Table and other Format-* cmdlets output strings. These are among the handful of PowerShell cmdlets that do not generate a .NET object. Therefore, do not use any of these format cmdlets if you would like to process an object further. The format cmdlets should only be used at the end of the pipeline.

 

How it works…

Type accelerators are another form of encapsulation of .NET code in PowerShell. Recall the first recipe in this chapter, wherein we created a .NET object within PowerShell. We used the PowerShell command New-Object -TypeName System.IO.DirectoryInfo -ArgumentList '/home/ram' to get information on a home directory: we created a new instance of System.IO.DirectoryInfo and passed an argument to it. That was a lot of code to write. To accelerate this process, we could use [IO.DirectoryInfo]'/home/ram' (System is the default namespace; PowerShell will understand it without us explicitly mentioning it when calling accelerators), which outputs the same object as the former command.

With Import-Csv, on the other hand, the process is a simple conversion of data from text into name-value pairs. This is similar to using ConvertFrom-Text with a Delimiter parameter. This way, we instruct PowerShell to convert each row of text into instances of the object: the first row in the row-column structure is taken as the property name, and the rest of the rows are data. The cells are separated using a delimiter, which was a comma in the case of the CSV file.

There's more…

Look for more conversion cmdlets that are built into PowerShell. This can be done using the Get-Command -Verb ConvertFrom command.

See also

 

 

Comparing the outputs of Bash and PowerShell


PowerShell and Bash are both shells, and are capable of interacting with the kernel. Just like Bash can run on Windows, PowerShell can now run on Linux. While almost all of the aspects of which shell is better than the other is debatable, and the choice of shell is simply a matter of personal preference today, it is true that PowerShell is as powerful as .NET Core can get.

The primary difference between the two shells is that PowerShell outputs objects, while Bash returns text. Manipulation of the output in Bash involves manipulating text first, and then running further commands on the manipulated text to fetch the desired output. PowerShell, on the other hand, handles content as objects and, by design, requires comparatively less manipulation.

Structured data, as noted by Jeffrey Snover (the inventor of Windows PowerShell), is getting more popular as days pass, and structured data is where PowerShell shines the most.

Getting ready

In this recipe, we are going to pick one example to show you how simple and efficient it is to handle file metadata using PowerShell, primarily since the output is an object. We will list the files and folders within our home directory, along with the date and time of modification using both ls in Bash and Get-ChildItem in PowerShell.

We will use PowerShell to run the Linux commands as well.

How to do it…

  1. At the Bash prompt, enter ls -l to list all of the files, along with the metadata that the command shows by default:
  1. Go to the Terminal that has PowerShell running and type in Get-ChildItem at the prompt:

 

  1. Now, let's pick only the name of the folders and the last modified date and time. This is done in Bash by passing the output of ls -l to awk:
ls -l | awk '{print $6, $7, $8, $9}'
  1. Next, let's pick the same information on PowerShell as well:
Get-ChildItem | select LastWriteTime, Name

As you may have noticed, the output is very similar in both cases. However, with PowerShell, you can see the names of the columns as well, which means that you do not have to look for further documentation. Also, the selection of columns is simpler in PowerShell; no text manipulation is required. On the other hand, in Bash, we can use the awk command to manipulate the text output.

  1. Let's go one step further and create a subdirectory with a space in the name:
$ mkdir 'test subdirectory'
$ ls -l | awk '{print $6, $7, $8, $9}'

Note that what should have been test subdirectory appears as test. Compare this with the output from PowerShell:

How it works…

PowerShell reads content from the filesystem as objects, not as text. Therefore, you perform a selection of the desired columns (or, as we shall later see, properties) directly. Bash, on the other hand, outputs text, columns from which are manipulated using a delimiter.

To demonstrate that this is the case, we created a new subdirectory with a space in its name, and we performed the column selection just like we did before, only in this case we did not get the complete name of the new subdirectory. This is because the name contained a whitespace, which is a delimiter in awk.

Note

Comparing Bash and PowerShell is like comparing apples and oranges—in more ways than one. However, understanding the differences helps us leverage each of the tools to our benefit.

See also

  • The Selecting columns from the output recipe from Chapter 4, Passing Data Through the Pipeline
 

Comparing Windows PowerShell and PowerShell Core


Windows PowerShell and PowerShell Core are two different implementations. The former is based on a larger framework, the .NET Framework. The latter, on the other hand, is a more modern framework, the .NET Core. PowerShell Core is cross-platform since its parent is. Windows PowerShell, on the other hand, is Windows-only, but has more capabilities than PowerShell at the time of writing this book.

Note

The PowerShell that this book talks about is the cross-platform PowerShell Core. This is referred to as PowerShell. The PowerShell that is Windows-specific is referred to as Windows PowerShell.

Windows PowerShell leverages the internal components and the architectural model of Windows, with its capabilities enhanced by WinRM as well as Windows Management Instrumentation. In fact, most of the differences exist because of the inherent differences between Windows and Unix-like operating systems.

Support for snap-ins

PowerShell will not support the legacy version of modules, also known as snap-ins. Many of the snap-ins of old have been repackaged to be binary modules. Therefore, the unavailability of snap-ins should not be of much concern. Future development of these binary modules should, in theory, work on either PowerShell, provided that the host supports the API calls that are part of the binaries. For example, let's imagine that the Windows Active Directory module was repackaged into a binary PowerShell module. This module would run on Windows PowerShell as well as PowerShell on Windows. However, since Windows Active Directory does not run on Linux, the module would not work with PowerShell on Linux.

Convenience aliases

One important point to note is that commands such as ls and mkdir are aliases in Windows PowerShell, which means that running ls on Windows PowerShell would run Get-ChildItem in the background (this is also true for PowerShell on Windows). In Linux, however, running ls from within PowerShell would run the actual ls command; ls is not an alias in PowerShell on Linux—it is the command itself, whose output would be plain text. You can validate this by running ls | Get-Member on PowerShell on Linux, and comparing it with PowerShell on Windows as well as Windows PowerShell (it is, therefore, good to stick to the best practice of not using aliases in scripts):

Note

PowerShell knows whether it is running on Linux, Windows, or macOS by means of the values of the automatic variables IsLinux, IsWindows, and IsMacOS. On any system, only one of these variables has the value True. When PowerShell sees that IsLinux is True, it would run Linux commands instead of the convenience aliases that were initially created to facilitate Linux administrators. For more information on these automatic variables, read the Configuring built-in variables recipe.

PowerShell Workflows

Windows administrators who are used to PowerShell Workflows in Windows PowerShell need to note that they are absent in PowerShell. PowerShell Workflows were a little advanced (to put it nicely) and were used in specific scenarios where multiple cmdlets were to be run in parallel, or activities had to, say, survive a reboot. Workflows work on the Windows Workflow Foundation, which is not cross-platform. Therefore, PowerShell Workflows will not run on PowerShell. However, the unavailability of PowerShell Workflows is no deal-breaker. Workflows were not used much either.

 

PowerShell Desired State Configuration

Desired State Configuration (DSC) is a work in progress at the time of writing this book. As of now, there are two code bases of DSC resources: LCM for Linux, which is managed by Microsoft's Unix team, and DSC Resources for Windows PowerShell, which was written by the PowerShell team. It could be some time before the DSC code base becomes cross-platform.

 

Working with aliases


An alias, as the meaning goes, is an alternative name for cmdlet. They serve two purposes:

  • To reduce the number of keystrokes
  • To make the transition to PowerShell smoother

Traditionally, aliases were created in PowerShell so that Windows and Linux administrators did not find the new framework intimidating to work with. Regardless, aliases are best used only on the command line, and not in scripts, because some aliases are not aliases in Linux, and, in general, aliases affect readability. (For instance, it would take conscious effort to realize that gbp stands for Get-PSBreakPoint.)

How to do it…

As we have already mentioned, it is simple to think in PowerShell. When we know that the verb to fetch any information locally is Get, and the noun in this case would be Alias, the cmdlet should be Get-Alias :

  1. Run Get-Help to understand how to use the cmdlet:
PS> Get-Help Get-Alias

Note

If you're unsure about any command, or you would like to reduce keystrokes without involving aliases, use tab-completion. Write a part of the cmdlet or parameter and press the Tab key. PowerShell will complete the command for you, or show you suggestions, based on which platform you're doing this on.

 

  1. According to the help documentation, all of the parameters for Get-Alias are optional (they are all enclosed in []). Therefore, simply running Get-Alias will give us a list of all of the aliases that are available in the current instance of PowerShell:
  1. Now, let's try to resolve the gbp alias to the PowerShell cmdlet that it actually runs in:
PS> Get-Alias gbp
  1. Now, do the opposite: get the alias for a certain cmdlet. The Definition in the second parameter set of the help documentation should be used. The output shows the actual PowerShell cmdlet that runs when an alias is called:
PS /home/ram> Get-Alias -Definition Get-ChildItem

 

 

  1. We can see two aliases as output, both of which run Get-ChildItem under the hood. Now, let's run dir as well as Get-ChildItem and compare their outputs:
PS> dir
PS> Get-ChildItem
  1. The two outputs are identical. Now, let's look at what type of object the commands return:
PS> /home/ram> dir | Get-Member
PS> /home/ram> Get-ChildItem | Get-Member

They returned the same object as well.

Now, let's create an alias:

  1. First, identify a word that you'd like to use as the alias. For example, let's consider listdir.
  2. Run listdir on PowerShell to ensure that such a cmdlet (or a Linux command) does not already exist.
  3. List out the cmdlets that deal with aliases by running the following command:
PS> Get-Command *alias
  1. New-Alias is the cmdlet we are looking for, since it creates a new alias.

Note

In PowerShell, the Set verb is used to modify something. Therefore, Set-Alias is used to modify an alias that already exists.

  1. Read the help documentation for New-Alias by running the following command:
PS> Get-Help New-Alias

The help document indicates that only the Name and the Value parameters are mandatory. We will only use these two to create this simple alias.

  1. Run the following command to create the custom alias:
PS> New-Alias listdir Get-ChildItem

 

  1. Check whether the alias was created as desired or not:
PS> Get-Alias listdir
  1. Next, run the alias to see what output it gives:
PS /home/ram> listdir

That is the output that we are familiar with—the output of Get-ChildItem.

Note

Aliases are ephemeral by default. They exist only as long as your PowerShell session exists. To use custom aliases without having to recreate them each time, export these aliases (the instructions for which are in the next recipe) and import them using your PowerShell profile. We will look at profiles in Chapter 2, Preparing for Administration using PowerShell.

Since aliases are ephemeral, let's export the alias we created. The output of Get-Command a few steps ago showed Export-Alias. Get-Help for the cmdlet shows that there are two ways to export the aliases: as a comma-separated values file, and as a script.

Export the aliases as a CSV file:

PS> Export-Alias aliases.csv

Export the aliases as a script as well:

PS> Export-Alias aliases.ps1 -As Script

View the contents of both files either using cat or Get-Content.

Optionally, edit the file to remove all of the aliases except the ones you created. The custom aliases can be found at the bottom of the list.

Next, import the aliases into your PowerShell session:

  1. Restart PowerShell.
  2. Check if the listdir alias that you created exists:
PS> Get-Alias listdir
  1. Now, import either of the alias exports:
PS> Import-Alias ./aliases.csv
PS> # Or, simply call the script, ./aliases.ps1

Note

If you did not remove the pre-existing aliases, you may receive several errors, each saying that the new alias could not be created. There are two ways to handle this: the first way is to remove the default aliases from the export file (which is recommended), and the second way is to use the -Force parameter (this may still result in errors, but there would be significantly fewer).

If you would like to add these aliases to your session, follow the Enabling automated execution of commands for each load recipe in  Chapter 2, Preparing for Administration Using PowerShell.

How it works…

Aliases are nothing but mappings that are done within PowerShell. The short words are mapped to PowerShell cmdlets; the cmdlets are recorded as Definition in each of the aliases. Aliases also support the same parameters as the cmdlet as well, since aliases are merely pointers to the right cmdlet. When you run anything on PowerShell, PowerShell checks its list of cmdlets and aliases (among other definitions) to understand what you are asking for. When PowerShell encounters an alias, it looks for which cmdlet it points to, and runs the cmdlet.

Using New-Alias, you can create a pointer with a custom name that points to the desired PowerShell cmdlet. When the custom cmdlets are exported as a script, the contents show New-Alias for each of the aliases available in the session.

Exporting aliases as CSV makes it easier to extend within a text editor if needed. The Import-Alias cmdlet understands that the first column in the CSV is the name of the alias, and that the second is its definition.

There's more…

Add more content to your aliases, such as descriptions. Refer to the help documentation for Get-Alias to see what more you can do with aliases. If you have a Windows computer, try running Get-Alias against Linux commands such as ls.

 

See also

  1. The Understanding cmdlets and parameters recipe from Chapter 2, Preparing for Administration Using PowerShell
  2. The Enabling automated execution of commands for each load recipe from Chapter 2, Preparing for Administration Using PowerShell
 

Dissecting a .NET Core object


This is a tangential recipe, in case you are interested in seeing how PowerShell has been implemented.

.NET Core works on a cross-platform standard Common Language Infrastructure. Therefore, it has been possible to encapsulate the internal workings of Linux using .NET Core. As we will see in future chapters, PowerShell is object-oriented, just like .NET Core. For this demonstration, we will pick a simple system class called System.IO.DirectoryInfo to show information about a certain directory. We will also compare the output of the .NET Core object to the output of a PowerShell cmdlet, which also shows information about a certain directory.

Note

You do not have to remember the names of the .NET Core classes or methods, or their syntax to work with PowerShell; that is the whole point of the existence of PowerShell. However, if you need information on the .NET libraries and the classes, extensive help documentation is available online ().

Getting ready

Every object has members—properties and methods. In case you're new to the concepts of object-oriented programming, properties are qualities of an object (what the object has), and methods are the capabilities of an object (what the object can do). Therefore, to quote (arguably) the most overused example of properties and methods: if a car is an object, its height, its color, and so on would be its properties, while accelerating, braking, and so on would be the methods that the object supports.

 

How to do it…

  1. With PowerShell, .NET Core is also installed as a dependency. Let's create an object in PowerShell that will call a .NET class and its default constructor. This constructor requires an argument:
PS> New-Object -TypeName System.IO.DirectoryInfo -ArgumentList $HOME

Here, /home/ram is my home directory. Replace this path with yours.

  1. Use the Get-Item cmdlet with the same argument as before, and see what you get:
PS> Get-Item $HOME
  1. Close! Now, let's look at the members of the output object we just received by using Get-Member:
PS> Get-Item $HOME | Get-Member

This will list a series of members (properties, methods) that are part of the output. We're primarily concerned about the very first line for now.

How it works…

Note the very first line of the output, TypeName: System.IO.DirectoryInfo. That is the exact type name we used when we created the .NET object:

This proves that the same task of showing information on the current working directory can be achieved by either calling a .NET constructor or by running a PowerShell cmdlet, the implication being that PowerShell cmdlets are simply encapsulated .NET code. In essence, Get-Item calls the System.IO.DirectoryInfo class under the hood, with the arguments passed along with the cmdlet.

Like they say: "If the C# guys can do it, so can you."

 

Listing out the execution policies and setting a suitable one


This is a Windows-only recipe. Skip this if you never plan to work on Windows.

There was a time when running scripts on Windows computers was a cakewalk. Windows computers were highly prone to remote script executions. With PowerShell, Microsoft added a safety belt that allowed the user some control over how PowerShell scripts were loaded. Some specific models of script executions got restricted, which plugged some holes in the system.

Note

It is important to remember that execution policies are not a security feature. There are ways to circumvent this fence. Execution policies are in place only to ensure that users don't accidentally run scripts without awareness.

PowerShell Core on Windows and Windows PowerShell contain this feature. Running PowerShell scripts on Windows is still restricted by default. On PowerShell Core on Linux, execution policies do not work at the moment, and, based on the interactions in the community, it is uncertain whether this feature will ever make it to PowerShell on Linux. Regardless, if you are reading this book, you are more than capable of understanding the perils of scripts from unknown sources.

An execution policy determines what type of scripts can be executed. Here are the six execution policies (excluding Default):

  1. AllSigned
  2. RemoteSigned
  3. Restricted
  4. Unrestricted
  5. Bypass
  6. Undefined

There are three scopes as well:

  1. Process
  2. CurrentUser
  3. LocalMachine

 

A combination of an execution policy and a scope are what determine the condition that scripts can be loaded under. Microsoft has documented in detail what each of the policies is. In general, AllSigned requires that all of the scripts that run on the computer are signed using a code-signing certificate by a trusted certification authority. If this policy is set, PowerShell will not run unsigned scripts, even if you were the one to create them.

Restricted is the default policy: commands can be run, but not scripts. RemoteSigned allows scripts that have been created on your own computer to run. Scripts that have been downloaded from the internet cannot be run.

Bypass is similar to Unrestricted, however, it is used in specific scenarios, such as when PowerShell forms the basis of a certain application, and the application has its own security implementation.

Unrestricted means that all scripts and commands can run after a simple confirmation. Undefined means that no policy has been defined for a particular scope. Follow the recipe to find the execution policy that is effective on the session, and change it to suit your needs.

Getting ready

This recipe can only be run on Windows. If you're running a pure Linux environment, you cannot work with this recipe. You may run the commands, but you will see the Unrestricted policy set at all levels.

If you have a Windows computer to work with, you can proceed with this recipe, regardless of whether it has PowerShell or Windows PowerShell.

How to do it…

Open a PowerShell window by running pwsh or powershell. The pwsh command calls PowerShell, and powershell calls Windows PowerShell.

Windows PowerShell comes preinstalled on all modern Windows operating systems; PowerShell, on the other hand, has to be installed. Note that all of the current PowerShell cmdlets will run on Windows PowerShell as well:

  1. First, run the Get-Command cmdlet to find out how to work with execution policies:
PS> Get-Command -Noun Execution*
  1. Now, let's get help on running the cmdlet:
PS> Get-Help Get-ExecutionPolicy
  1. We want to know the execution policy set on the machine. Therefore, we will run the following code:
PS> Get-ExecutionPolicy

This shows that the execution policy is currently effective on the current PowerShell session.

  1. To list out the policies set at various scopes, run the following command:
PS> Get-ExecutionPolicy -List

We can see that the policy is only set at the LocalMachine level, and that it is set as RemoteSigned, which is the same as what is reflected in the previous step. The policy at the LocalUser and the Process scopes is Undefined, which made the session pick the execution policy from LocalMachine.

Now, let's set the execution policy for the local machine to be Undefined and see what our session picks up.

  1. For this to work, close the current PowerShell session and open a new session as the administrator.
  2. Next, run the following command:
PS> Get-Help Set-ExecutionPolicy

 

  1. The help document shows that the value of the ExecutionPolicy parameter is mandatory, and that Undefined is one of the valid values it will accept. We want to set the policy at the LocalMachine scope, and so we will use the following code:

Note

You will need to launch PowerShell (either Core or Windows) with elevated privileges to set the policy at the LocalMachine level.

PS> Set-ExecutionPolicy -ExecutionPolicy Undefined -Scope LocalMachine
  1. Now, list the execution policies at the various scopes:
PS> Get-ExecutionPolicy -List
  1. Now, let's check the currently effective execution policy:
PS> Get-ExecutionPolicy

 

 

  1. Finally, let's set the execution policy back to how it was before we began the recipe. You may want to change the policy to suit your needs, based on what authority you have on the computer:
PS> Set-ExecutionPolicy RemoteSigned -Scope LocalMachine

How it works…

Execution policies are nothing but conditions that are set on the system to avoid accidental script runs. They work at different scopes.

There are three scopes in PowerShell, as we have already stated. The LocalSystem scope is at the end of the chain. Right above it is the CurrentUser scope. At the top is the Process scope. The level of precedence is Process > CurrentUser > LocalMachine. Therefore, if any policy other than Undefined is set at the Process scope, the session will use the policy that's currently set on the process. In case it is Undefined, it will look for the policy set on the CurrrentUser scope. If CurrentUser has the policy marked as Undefined as well, the session will apply the policy that was applied at the LocalMachine level. If LocalMachine has Undefined set, the session will pick the Default policy, which is based on what PowerShell has defined as the policy, which may vary based on the version of your operating system. On Windows 2016, for instance, the default policy is RemoteSigned.

The policies set at the CurrentUser and LocalMachine levels are stored in the Windows Registry. The policy set on the Process scope is stored in the ephemeral environment variable, that is, $env:PSExecutionPolicyPreference.

About the Authors

  • Prashanth Jayaram

    Prashanth Jayaram is a product design and automation expert in database technology with 12 years of rich, extensive, hands-on experience in designing database solutions with next-gen database technologies. He was awarded as the second-best SQL author of 2017 for his contribution to the SQL Server technology space. He has written over 200 articles about SQL, NoSQL, PowerShell, Python, SQL on Linux, SQL on Azure, and SQL on AWS.

    Browse publications by this author
  • Ram Iyer

    Ram Iyer is an automation and application performance management specialist with about eight years of experience in enterprise IT. While ensuring that the environment in his enterprise performs optimally is his primary role, he is passionate about automation using PowerShell, and has contributed to over 60 enterprise-grade automation solutions in Windows, Microsoft Exchange, Microsoft Active Directory, Microsoft System Center, Citrix XenApp, VMware PowerCLI, and Microsoft Azure, using PowerShell. He gives back to the community by conducting training sessions in PowerShell and blogging about administration using PowerShell.

    Browse publications by this author

Latest Reviews

(2 reviews total)
Quick and straight forward payment
Good Offering on Powershell

Recommended For You

Book Title
Access this book, plus 8,000 other titles for FREE
Access now