# PowerShell Basics

PowerShell isn’t just the interactive `powershell.exe` and `powershell_ise.exe` binaries, Powershell itself is actually `System.Management.Automation.dll` which is a dependency of various hosts.

The following is a table that represents the different versions of Powershell supported over time

| Version              | Release Date | OS Support                        |
| -------------------- | ------------ | --------------------------------- |
| PowerShell V1        | 2006         | Windows Server 2008               |
| PowerShell V2        | 2009         | Windows 7, Windows Server 2008 R2 |
| PowerShell V3 / WMF3 | 2013         | Windows 8, Windows Server 2012    |
| PowerShell V4        | 2013         | Windows 8.1                       |
| PowerShell V5        | 2015         | Windows 10, Windows Server 2016   |
| PowerShell Core      | 2016         | Nano Server, Windows 10 IoT       |
| PowerShell V6 (Core) | 2017         | Windows, macOS, \*UNIX            |

To determine what PowerShell versions we have installed on a system we use

```powershell
(Get-ItemProperty HKLM:\SOFTWARE\Microsoft\PowerShell\*\PowerShellEngine -Name PowerShellVersion).PowerShellVersion
```

Execution policy is **NOT** a security protection as it can be disabled with something as simple as

```powershell
Set-ExecutionPolicy -ExecutionPolicy Bypass -Scope Process
```

or

```
powershell.exe -exec bypass
```

PowerShell files can come in different formats:

* `.ps1`: a single PowerShell script, completely self-contained and can be loaded into memory in one go
* `.psm1`: a PowerShell module file, this allows to do things like exporting only specific functions / variables and it's often used to give a better structure to more complex PowerShell code
* `.psd1`: a PowerShell module manifest that specifies information about the module itself and what variables / functions are exported
* `.ps1xml`: a object formatting file for a PowerShell module that allows for granular control of how custom objects are displayed

#### PowerShell Profile Locations

| Profile                           | Location                                                                                      |
| --------------------------------- | --------------------------------------------------------------------------------------------- |
| AllUsersAllHosts                  | `%windir%\System32\WindowsPowerShell\v1.0\profile.ps1`                                        |
| AllUsersAllHosts (WoW64)          | `%windir%\SysWOW64\WindowsPowerShell\v1.0\profile.ps1`                                        |
| AllUsersCurrentHost               | `%windir%\System32\WindowsPowerShell\v1.0\Microsoft.PowerShell_profile.ps1`                   |
| AllUsersCurrentHost (ISE)         | `%windir%\System32\WindowsPowerShell\v1.0\Microsoft.PowerShellISE_profile.ps1`                |
| AllUsersCurrentHost (WoW64)       | `%windir%\SysWOW64\WindowsPowerShell\v1.0\Microsoft.PowerShell_profile.ps1`                   |
| AllUsersCurrentHost (ISE - Wow64) | `%windir%\SysWOW64\WindowsPowerShell\v1.0\Microsoft.PowerShellISE_profile.ps1`                |
| CurrentUserAllHosts               | `%homedrive%\%homepath%\[My ]Documents\WindowsPowerShell\profile.ps1`                         |
| CurrentUserCurrentHost            | `%homedrive%\%homepath%\[My ]Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1`    |
| CurrentUserCurrentHost (ISE)      | `%homedrive%\%homepath%\[My ]Documents\WindowsPowerShell\Microsoft.PowerShellISE_profile.ps1` |

#### Exporting/Importing PowerShell Objects

To import / export PowerShell objects we use the `Import-Clixml` and `Export-Clixml` functions

```powershell
Get-Process | Export-Clixml processes.xml
$processes = Import-Clixml .\processes.xml
```

#### Variables & Operators

Variables are defined with `$` followed by any combination of numbers and (case-insensitive) letters but we can also use `New-Variable` to specify non-printable characters as well.

```powershell
New-Variable -Name ([Char] 7) -Value 'something'
```

To list all variables in the current scope we can use `Get-ChildItem Variable:\` and to cast a variable to another data type we use `[Type]$variableName`.

The following are common operators used with variables and their attributes

* Math: `+`, `-`, `*`, `/`, `%`
* Assignment: `=`, `+=`, `-=`, `*=`, `/=`, `%=`
* Comparison: `-eq`, `-ne`, `-gt`, `-lt`, `-le`, `-ge`, regex operations
* Logical: `-and`, `-or`, `-xor`, `-not` or `!`
* Redirection: `>`, `>>`, `2>`, `2>>`, `2>&1`
* Type: `-is`, `-isnot`, `-as`

It's possible to get more information about operators with `Get-Help about_Operators`.

#### Arrays & Hash Tables

There are many ways to create arrays

| Creation method   | Code                                    |
| ----------------- | --------------------------------------- |
| Implicit creation | `$array = 4,6,1,60,23,53`               |
| Explicit creation | `$array = @(4,6,”s”,60,”yes”,5.3)`      |
| Ranged creation   | `$array = 1..100`                       |
| Strongly typed    | `[int32[]]$array = 1500,1600,1700,1800` |

and there are several operations we can perform on an array object

* count the number of elements: `$array.Count`
* indexing: `$array[0]`
* reversing an array: `$array[-1..-$array.Lenght]`
* append a value to an array: `$array += $value`

Since arrays are immutable we have to perform extra steps to append or remove elements from one

```powershell
$arrayList = New-Object System.Collections.ArrayList
$arrayList.Add($value)
# or
$arrayList.Remove($value)
$arrayList.ToArray()
```

HashTables in PowerShell are the equivalent of dictionaries

```
$hashtable = @{ Number = 1; Color = "Purple"}
$hashtable["Number"] # prints 1
```

Common operations we can perform on hash tables are

* return the keys of the hash table: `$hashtable.keys`
* return the values of the hash table: `$hashtable.values`
* add a key or value

```powershell
$hashtable.Add("Key", "Value")
# or
$hashtable = $hashtable + @{Key="Value}
```

* remove a key: `$hashtable.Remove("Key")`

Hash tables can also be used as parameters for function calls

```powershell
$Args = @{ Path = "source.txt"; Destination = "destination.txt"; WhatIf = $true }
Copy-Item @Args
```

#### Strings

Double-quoted strings - both single and multi-line - expand sub-expressions and variables while single-quoted strings don't.

* Case-insensitive comparison (returns 0 if strings are the same): `$a.CompareTo($b)`
* Case-sensitive comparison: `[string]::Compare($a, $b, $True)`
* Case-sensitive prefix / suffix: `$a.StartsWith("prefix")`, `$a.EndsWith("suffix")`
* Turn string lowercase / uppercase: `$a.ToLower()`, `$a.ToUpper()`
* Check for substring (case-sensitive): `$a.Contains("substring")`
* Replace a string or substring: `$a.Replace("old string", "new string")`
* Substring: `$a.SubString(index)` returns `a[index..$a.Length-1]` or `$a.SubString(start, end)` returns `$a[start..end]`
* Split a string: `$a.Split("separator")` returns an array of the string split by the separator
* Pad a string: `$a.PadLeft(1)`, `$a.PadRight(1)` pads the string to the specified length
* Convert string to a byte array: `$a.ToByteArray()`

#### Regular Expressions

Strings can also be used to match regular expressions with operators like `-match`, `-notmatch` (case-insensitive) or `-cmatch`, `-cnotmatch` (case-sensitive).

{% hint style="info" %}
The `-match` operator will populate the `$Matches` variable with all the matches if used on a single-line variable.
{% endhint %}

To match and replace part of a string we use `-replace` and `-creplace`

```powershell
"date: 11/11/2011" -replace "\d{2}/\d{2}/\d{4}", (get-date -f "DD/MM/YYYY")
```

#### Logic & Loops

If / else / if-else statements

```powershell
if ($var -lt 0) {
	# something
}
elseif ($var -lt 10) {
	# something
}
else {
	# something
}
```

Switch statements

```powershell
$output = switch -wildcard ($var) {
	"var a" { "first output" }
	"var b" { "second output" }
	default { "default output" }
}
```

Try / catch / finally statements

```powershell
try {
	$client = new-object System.Net.WebClient
	$client.DownloadFile("http://domain.com/a")
}
catch [System.Net.WebException],[System.IO.IOException] {
	"Unable to download file"
}
catch {
	"Could not resolve error"
}
```

For-each statements

```powershell
ForEach($number in $numbers) {
	# do something
}
```

For-each-object statement

```powershell
Get-Process | % {$_.Name}
```

While / do-while statement

```powershell
while ($var -ne 100) {
	# do something
}
```

#### Filtering

When piping output from other commands it's possible to filter it

* Find an object with specific properties:

```powershell
Get-DomainUser | ? {$_.lastlogon -gt [DateTime]::TOday.AddDays(-1)}
```

* Execute a scriptblock on each object:

```powershell
Get-DomainUser -Domain domain.com | %{ if ($_.scriptpath) { $_.scriptpath.split("\\")[2] } }
```

* Find property comparisons

```powershell
$_ -eq number
$_ -Like *string*
$_ -match 'regex'
```

We can also sort objects by a set property with `Sort-Object property`, group objects with `GroupObject property` or select only some objects with

```powershell
Select-Object -Property firstProperty,secondProperty
select -expand property
select -First 1
select -Last 1
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://otter.gitbook.io/red-teaming/notes/powershell/powershell-basics.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
