PowerShell

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

VersionRelease DateOS 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

(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

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

ProfileLocation

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

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.

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 methodCode

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

$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

$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

$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).

The -match operator will populate the $Matches variable with all the matches if used on a single-line variable.

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

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

Logic & Loops

If / else / if-else statements

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

Switch statements

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

Try / catch / finally statements

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

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

For-each-object statement

Get-Process | % {$_.Name}

While / do-while statement

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:

Get-DomainUser | ? {$_.lastlogon -gt [DateTime]::TOday.AddDays(-1)}
  • Execute a scriptblock on each object:

Get-DomainUser -Domain domain.com | %{ if ($_.scriptpath) { $_.scriptpath.split("\\")[2] } }
  • Find property comparisons

$_ -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

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

Last updated