Fundamentals of PowerShell

Eyad Almuqhim
13/01/2021


Introduction
This blog will be an introductory about PowerShell. It will give an overview about what PowerShell is, what is it used for, and a simplified explanation of some of its important and frequently used cmdlets (pronounced "commandlets"). It is not a comprehensive cover of PowerShell, but should be a good start for people who are interested in learning the language.

What is PowerShell?
It's an object-oriented command shell and a scripting language built-in to Windows operating systems. It is intended to be the successor of CMD.exe for administrating and interacting with Windows systems through the command line. It can be used interactively through its command line host (powershell.exe) or through a GUI application that runs PowerShell cmdlets in the background. Several of Windows Graphical User Interface (GUI) administration tools that are used to manage Windows systems actually run PowerShell in the background.

Who is it Used by?
PowerShell is used by system administrators to manage Windows and other Microsoft systems, such as Active Directory and MSSQL. It is also used by cybersecurity incident responders and investigators, penetration testers, and of course, by attackers too. It is mostly used as a post-exploitation tool after landing on a Windows system. In summary, PowerShell can do what CMD.exe does and much more.

Windows PowerShell vs PowerShell Core
There are two types of PowerShell(s):

Windows PowerShell
A Windows-only, closed-source PowerShell that is built-in to Windows systems by default. Windows PowerShell has version numbers 1.x, 2.x, 3.x, 4.x, and 5.x which is the latest.

This is how Windows PowerShell (powershell.exe) version 5 looks like:
PowerShell Core
A cross-platform, open-source PowerShell that can run on Windows, Linux, and macOS. It is not built-in to Windows by default. PowerShell Core version numbers start from 6.x and the latest as of today is 7.x.

This is how PowerShell Core (pwsh.exe) version 7 looks like:
PowerShell Basics
Now that we have an idea about what PowerShell is, let's get into how it is different (being object-oriented) and explore some of its important and frequently used cmdlets.

Objects-oriented
PowerShell is object-oriented. The output of cmdlets is one or more objects, not text like CMD.exe or Bash—even though they are printed on the screen as text, they are actually stored as objects in memory. Objects possess properties and methods which can simply be defined as:

Property: Variable information about the object. A process object, for example, has properties such as Process ID, Process Name, Memory Usage, etc.

Method: A piece of code that performs some action on the object. A process object, for example, has methods such as kill the process, start the process, etc.

For example, when running a cmdlet, such as Get-Process, which shows the running processes on the machine, the output is properties of each of these processes, such as Process Name and Process ID. The output of the command is an array of objects. The objects here are of type "Process" (or "System.Diagnostics.Process" for the complete name).

Each row represents a single Process object:
Each process object has methods that can perform a certain action on that process, such as to start a process or kill it. Here, for example, we are using the method kill() which terminates any running process named Calculator. When we queried about the running Calculator processes again, we got an error because we have already terminated that process using the kill() method:
Now that we know what PowerShell objects are, let's explore the most important and useful cmdlets in PowerShell.

Get-Alias (gal)
Aliases are shorthands for cmdlets. They are meant to simplify long cmdlets so users can type them faster. They produce the same output as their original, longer cmdlet.

You can get an alias for a cmdlet by running the following:

Get-Alias -Definition Get-Process
Running the alias ps will output the same result as running the original cmdlet Get-Process:
Alternatively, you can find the original cmdlet for an alias by running the following:

Get-Alias -Name ps
Get-Help (help)
There are two important cmdlets you should memorize in PowerShell; any other cmdlets can be easily reached if you know these two. The first cmdlet is Get-Help which provides a help menu about the cmdlet, such as syntax. The following cmdlet will display the full help menu for Get-Process cmdlet:

Get-Help -Name Get-Process –Full
Event better, you can use the –Online switch instead to open Microsoft documentation page in the browser which provides more details about Get-Process cmdlet:

Get-Help –Name Get-Process -Online

Get-Member (gm)
Get-Member is the second important cmdlet to remember. It has an alias of gm. Once you pipe an object to Get-Member, you can see the object type, methods you can call on the object, and any properties that you can access.

Get-Process | Get-Member

Variables and Arrays

You can save the output of cmdlets to variables for later manipulation. The variables will save the output as object, not text. Variables in PowerShell start by a dollar sign ($) followed by the variable name: $var_name. Variables can be assigned a single object or an array of objects.

Assigning a variable named $signle_var with a single String value of "single_val":

$single_var ="single_val"
Assigning the variable $array to an array of objects of different types, String and Integer, can be done as follows:

$​array= "val_1", "val_2",1234
The first value is accessed by index 0, and the last value is accessed by index -1 and so on:
Typecasting
When creating a new object, PowerShell will assign the appropriate type for it if no type is explicitly assigned.

Assigning a variable to a number will create a variable of type Integer (Int32):

$var1 = 123
$var1 | Get-Member
Assigning to a text (anything enclosed by quotation marks) will create a variable of type String:

$var2 = "text"
$var2 | Get-Member
If we enclose a number by quotation marks, PowerShell will create an object of type String, not Integer:

$var3 = "123"
$var3 | Get-Member
Sometimes you need to explicitly change the type of variable to match the result you expect. In the example below, the two variables are assigned numbers, and we want to perform addition operation. But since they are enclosed by quotation marks, PowerShell automatically treats them as String variables. If you attempt to add the two numbers using the + operator, PowerShell will concatenate the two values and give an unexpected result since PowerShell treated them as Strings. However, by prepending [Int] before the first variable, you will instruct PowerShell to change the type to Integer instead of String and it will treat these values as numbers and perform the addition operation instead of concatenation:

$num1 = "3"
$num2 = "4"
$num1 + $num2
[Int]$num1 + $num2
Sort-Object (sort)
This cmdlet will sorts piped objects, by ascending order by default:

$array = 4, 7, 2, 4, 9, 11, 4, 15, 3, 1, 0, 9, 13, 4, 2, 9, 4
$array | Sort-Object
You can change the sorting to descending order by appending the –Descending switch:

$array | Sort-Object -Descending
Additionally, you can only display unique items by using the –Unique switch:

$array | Sort-Object –Descending -Unique
Comparison
There are many comparison operators in PowerShell. Comparing objects will yield either a True or False value depending on the result of the comparison. Comparisons are important when we want to perform certain action if a specific condition is met. Some of the comparison operators are:

-eq: Equals.
-lt: Less than.
-le: Less than or equals.

Examples:

5 –eq 5
5 –lt 10
5 –lt 5
5 –le 5
-like: Uses a (*) to compare if the first object contains the second one.

Examples:

Does the first string end with "sync"?

"Cyber Sync" –like "*sync" 
Does the first string start with "cyber"?

"Cyber Sync" –like "cyber*"
Does the first string contain "ber" anywhere within the string?

"Cyber Sync" –like "*ber*"
More about comparison operators

Select-Object (select)
Select-Object is used to select specific properties from a piped object—similar to SELECT in SQL language.

Running Get-Process alone displays various properties about the running processes:
Selecting only ProcessName and ID of the running processes:

Get-Process | Select-Object ProcessName, Id
Formatters
You can format the output of a cmdlet to different types: table, list, etc. Format-Table is the default for most cmdlets if no specific format is explicitly used.

Format-Table is implicit:

Get-Process
Same as using Format-Table explicitly:

Get-Process | Format-Table
Displaying the output in a list format:

Get-Process | Format-List
More about formatters

Outputters
You can output the result of a cmdlet in different ways. Out-Host is the default for most cmdlets if no explicit outputter is used. Out-Host means the data is displayed on the host process running PowerShell—which is the console.

Out-Host is implicit:

Get-Process
Same as using Out-Host explicitly:

Get-Process | Out-Host
Saving the output to a text file using Out-File and reading its content using Get-Content:

Get-Process | Out-File process_list.txt
Get-Content .\process_list.txt
Viewing the output in a graphical window where you can search and filter the result in a user-friendly way using Out-GridView:

Get-Process | Out-GridView
Where-Object (?)
This cmdlet is used to only output objects matching a certain condition. It has an alias of a question mark ?. Every piped object is placed in a temporary variable named $_ and the property of each variable is accessed by appending a dot (.) to it followed by the variable name. The comparison operation must be enclosed by curly braces {}.

Only display processes that have a Name equals to "Calculator":

Get-Process | Where-Object {$_.Name –eq "Calculator"}
ForEach-Object (%)
This cmdlet is used to loop through the piped objects one by one to perform a certain operation on them. ForEach-Object has an alias of percentage sign %. Passed objects through the pipeline are also accessed by a temporary variable named $_. The comparison operation must also be enclosed by curly braces too {}.

Multiply each object of the array by 5:

$array = 1, 2, 3, 4, 5
$array | ForEach-Object {$_ * 5}
Functions
A function is a block of code with a name assigned to it that you can call to execute that block of code. A function can have zero or more parameters to it where you can pass arguments that will be used as part of the code inside the function.

The following is a function named Find-Flag that when executed, it will run the code inside it which searches through the file system starting from C:\ for a file that has the word flag in it and has a .txt extension:

function Find-Flag(){
Get-ChildItem -Path C:\ -Recurse -File -ErrorAction Ignore| Where-Object{$_.Name -like "*flag*.txt"}
}
After defining the function in the first line, we can call it using its name Find-Flag and it returns that the flag is located in System32 folder:
We can also define a function that accepts an argument that performs certain operation involving the passed argument. The parameters defined in the function have the same format as variables, a dollar sign ($) followed by the parameter name: $Param.

The below function accepts a String object as an argument for the –Text parameter and it will convert it to Base64:

function Base64-Encode($Text){
$Text + " --> " + [Convert]::ToBase64String([Text.Encoding]::Unicode.GetBytes($Text))
}

Base64-Encode –Text "Cyber Sync"
In addition to passing parameters, we can also define a switch as part of the function. Switches are like parameters except they do not accept arguments. They are either there or not. If they are used when the function is called, the switch variable will have a value of True in the block of code. If not used, it will have a value of False. It can be used in an if statement to run additional commands if it has the value of True (if used while calling the function).

The following is a function that decodes Base64 values passed to it through the –B64 parameter. Optionally, if the –Execute switch is used, the Base64 will also be executed as PowerShell code and the output of the command is displayed:

function Base64-Decode($B64, [Switch]$Execute){
$B64 + " --> " + [System.Text.Encoding]::Unicode.GetString([System.Convert]::FromBase64String($B64))
#This will only execute if -Execute switch is used
if($Execute){
"Output ==> " + (powershell -EncodedCommand $B64)
}
}

Base64-Decode -B64 aABvAHMAdABuAGEAbQBlAA==
Base64-Decode -B64 aABvAHMAdABuAGEAbQBlAA== -Execute
Conclusion
Being object-oriented makes PowerShell easy to learn and work with. This article only covered the basics of PowerShell and some of its important and frequently used cmdlets. More details about PowerShell can be found in Microsoft documentation:

Get-Help Get-Help –Online

Share this blog
Follow us
Advance your skills by reading the latest blog created by our team.
Other Blogs