PowerShell Introduction


PowerShell is an essential tool for anyone working with or within Microsoft Windows ecosystem.

This module is a brief overview of PowerShell for people completely new to it, with some initial handy tips to get started.

Short overview of PowerShell

PowerShell is a newer command line interface, a newer shell, from Microsoft, geared towards management of your Microsoft environment. That is up until version 5.11. From 6.02 and onwards, Microsoft has made PowerShell available for other popular platforms, like Linux, MacOS and ARM, although with reduced functionality. Making interoperability possible with some limitations.

NOTE: PowerShell was known as Windows PowerShell up to 5.1. 6.x versions were called PowerShell Core and 7.x will be named just PowerShell.

With every version, PowerShell has grown more powerful and more secure, but versions 1.x3 and 2.x4 had little to no security features, so if you can, you should disable/remove these versions from your environment.

NOTE: Although Windows 7 SP1 comes with Windows PowerShell 2.0, you can update it by downloading and installing Windows Management Framework 5.1, but know that you will not get functional parity with Windows PowerShell 5.1 on Windows 10, due to underlying OS differences.

The Environment you will be working in, throughout this training modules, is a newer Windows 10 instance, which has Windows PowerShell 5.1 included by default. Curious of what version of PowerShell your OS has? Try these built-in variables, which hold version information:

  • $PSVersionTable
  • $Host (Alias for Get-Host cmdlet)

NOTE: These variables show the version number of the current session of PowerShell. When you install PowerShell 7.x side-by-side with existing Windows PowerShell 5.1 and running $Host in your 5.1 window will show version 5.1 and version 7.x in the window you have PowerShell 7 running.

Another set of special variables you will be seeing:

  • $PSItem
  • $_

These variables represent the current object in pipeline. $_ has been around since Windows PowerShell 1.0, $PSItem was introduced in Windows PowerShell 3.05, to make it look more user friendly. Other than the name, they are identical. Throughout this module, you will be seeing the $PSItem one.

Since PowerShell is built on .NET, everything in PowerShell is an object, which is what gives the real power to that shell. Data displayed and data passed through a pipe is by default, an object, where as your usual shell, only text will be passed on. There are some exceptions, which you will encounter later in this article.

In PowerShell environment, a PowerShell native command is called a cmdlet, which consists of a verb and a noun, separated by - (Get-Help). The reason PowerShell native was specified is that you can still run older commands/programs you may have used in Command Prompt, such as ping, netstat and so on.

Useful Note: cmdlets and their parameters support tab completion. Depending on how the parameter is built, you may even be able to tab through valid values.

Get Help!

The first cmdlet you want to familiarize yourself with is Get-Help.

In a well written PowerShell module, help information will be included alongside module function documentation and syntax, also examples, which will help out anyone, new and seasoned PowerShell users.

Following example will show you examples of how to use Get-Process cmdlet: Get-Help Get-Process -Examples.

NOTE: Keep in mind the examples shown are made by the PowerShell module creator/maintainer and the actual possibilities are most likely wider.

When you run Get-Help with a cmdlet name and no other Parameters, you will get the basic Help information on a cmdlet. You will see possible syntax paths. Parameter Name enclosed in immediate square brackets ([[-Property] <Object[]>]) means that this Parameter is Optional.

For example: Get-Help Select-Object

If you want to get all the Help Information available for a cmdlet, you would use the -Full parameter, like so: Get-Help Get-Process -Full.

If you run the command and receive no information, that means that the Help files are not yet downloaded. These files are not present on a fresh Windows install. In that case you would update the Help using the following cmdlet within an elevated PowerShell: Update-Help.

When updating the entire Help, you will more than likely see the following errors:

Update-Help : Failed to update Help for the module(s) 'AppvClient, Defender, Microsoft.PowerShell.ODataUtils,
Microsoft.PowerShell.Operation.Validation, UEV, WindowsDeveloperLicense' with UI culture(s) {en-US} : Unable to
connect to Help content. The server on which Help content is stored might not be available. Verify that the server is
available, or wait until the server is back online, and then try the command again.

Update-Help : Failed to update Help for the module(s) 'WindowsUpdateProvider' with UI culture(s) {en-US} : Unable to
retrieve the HelpInfo XML file for UI culture en-US. Make sure the HelpInfoUri property in the module manifest is
valid or check your network connection and then try the command again.

As described by the error messages, these PowerShell Modules do not have Help Content available by the Module Creator/Maintainer. Unless you are after the Help of a PowerShell Module listed in the errors, this error is not an issue. Rest, also majority, of the Help is still updated.

What cmdlets can I run?

To get a list of modules currently loaded, run the following cmdlet: Get-Module.

You’ll see a short list of modules already loaded, but that’s not all! When you run the cmdlet again with -ListAvailable parameter (Get-Module -ListAvailable), PowerShell will show you all the modules currently available, but not loaded. Since PowerShell 3.0, Microsoft introduced autoloading of modules, which means that, for example, if you wanted to use the Get-NetConnectionProfile cmdlet, that is part of a NetConnection module, that is not loaded by default, by running the cmdlet, the module containing the cmdlet would get automatically loaded. Before that you needed to manually load the module like so: Import-Module NetConnection and then run the cmdlet.

Now you see all the modules available to you, but you also notice that some modules that contain many cmdlets, or have a few cmdlets with really long names, the information in ExportedCommand column gets truncated, how can you see all the cmdlets a module has?

In that case you would run the following cmdlet, where PKI is a sample, but existing, module name: Get-Command -Module PKI.

Now that you know how to get the commands of a module, you decide that you don’t need a possibly long list of cmdlets, you don’t need to set, update, remove anything anyway, you just want to retrive data, you want to query stuff. In such case you would use -Verb parameter with Get-Command cmdlet, which would look like so: Get-Command -Module PKI -Verb Get.

While using -Verb Parameter without the -Module Parameter isn’t going to give you much useful information in terms of specifics, you could use -Noun Parameter alone and get something useful: Get-Command -Noun *start*

NOTE: You could also run the command like so: Get-Command *start*, but then you get all cmdlets that have start in a Verb or a Noun and the list may end up containing cmdlets you were not looking for.

You could also look for cmdlets that have a specific parameter, for example: Get-Command -ParameterName Username

NOTE: Get-Command will search only within loaded modules, unless you specify the name of a cmdlet in an unloaded module.

I’m new to any sort of shell, how else could I leverage “piping”?

Piping lets you pass an object from one cmdlet to another, which is a very useful capability when administering systems.

Lets start with something simple, we’re going to use Get-Process again and use Stop-Process cmdlet to stop a process:

Get-Process -Name Excel | Stop-Process

The way this works is that the Process Name, in this case Excel, is sent to the next cmdlet, Stop-Process, which means that the Process Name doesn’t have to be specified down the line.

You will be seeing a lot of piping examples throughout the modules.

I get a long list processes, how would I filter the output? Or sort it?

These are the main cmdlets you’ll use to manipulate the output in one form, or another:

  • Select-Object allows you to pick out the properties you want to see, instead of just the default ones.
  • Sort-Object allows you to sort the output.
  • Where-Object allows you filter out the data you want.
  • Group-Object allows you to group output by a certain property.

Examples:

  • Select-Object
    • Display only Id, Process Name of the running processes

      Get-Process | Select-Object -Property Id, ProcessName

    • Display first or last 5 running processes

      Get-Process | Select-Object -First 5 Get-Process | Select-Object -Last 5

  • Sort-Object
    • Sort running processes by Id in a descending order

      Get-Process | Sort-Object -Property Id -Descending

  • Where-Object
    • Filter output by specific criteria. A simple, single filtering criteria. This type of filtering was made available in PowerShell 3.0. Before that you had to use -FilterScript parameter kind of filtering (next example).

      Get-Process | Where-Object -Property ProcessName -like '*svchost*'

    • When you need to filter by two or more criterias, you would use -FilterScript parameter, instead of -Property:

      Get-Process | Where-Object -FilterScript { $PSItem.Id -eq '25496' -and $PSItem.ProcessName -eq 'vmmem' }

  • Group-Object (Grouping running processes by Process Name)

    Get-Process | Group-Object -Property ProcessName

And now, combine some of these cmdlets:

Get-Process | Select-Object -Property Id, ProcessName | Where-Object -FilterScript { $PSItem.Id -eq '14944' -and $PSItem.ProcessName -eq 'Skype' } | Sort-Object -Property Id -Descending

Some of the cmdlet names are awfully long, any workaround for that?

PowerShell has some pre-made aliases and you can create your own as well.

To see what aliases already exist, you can run Get-Alias. Linux users will probably notice that there are familiar aliases, such as ls, mv, man, cat, etc. Keep in mind that these are just aliases to PowerShell cmdlets. So, although ls, mv, etc look familiar, the syntax is not the same as their Linux native counterparts.

You can create your own alias with New-Alias cmdlet:

New-Alias -Name 'lprocs' -Value Get-Process

However, this alias will be deleted once you close your current session.

Conclusion

You now should have the initial knowledge of PowerShell to get started with using PowerShell daily and build upon the acquired skills.

References:

  1. Windows PowerShell 5.1 is included in Windows 10 since version 1607 (Anniversary Update). 

  2. PowerShell Core 6.x and PowerShell 7.x can be downloaded separately and installed side-by-side with Windows PowerShell 5.1. 

  3. Windows PowerShell 1.0 is included in Windows XP SP2, Windows Server 2003 SP1 and Windows Vista. Optional for Windows Server 2008. 

  4. Windows PowerShell 2.0 is included in Windows 7 and Windows Server 2008 R2. Optional for Windows XP SP3, Windows Vista SP1, Windows Server 2003 SP2. 

  5. Windows PowerShell 3.x is included in Windows 8 and Windows Server 2012. Optional for Windows 7 SP1, Windows Server 2008 SP1, Windows Server 2008 R2 SP1. 

Ramil Rohi