7.1 Modifying Bash, Python, and PowerShell for Recon

Key Takeaways

  • Objective 2.3 tests modifying short Bash, Python, and PowerShell recon scripts for information gathering and data manipulation — not authoring exploit frameworks.
  • Pick the language from the OS in the stem: Bash for Linux recon glue and pipes, Python for libraries/functions/classes (requests, dnspython), PowerShell for Windows AD and DNS cmdlets.
  • Read loops, conditionals, Boolean operators, string operators, and arithmetic operators in order; a ping-fail `continue` skips a host, and `base + i` on `range(3)` yields three ports, not four.
  • Functions and classes beat copy-paste: change a timeout or resolver once, then reuse `grab(url)` or `enumerator.a_records(name)`.
  • Data manipulation is split banners, regex-extract IPv4, and write CSV (`csv.writer`, `Export-Csv`, or `printf`) so 2.2 enumeration receives a clean list.
Last updated: August 2026

Objective 2.3 on CompTIA PenTest+ PT0-003 is Given a scenario, modify scripts for recon and enumeration. Domain 2 (Reconnaissance and Enumeration) is 21 percent of the exam. This objective is not "author a 200-line framework from a blank editor." The item shows a short Bash, Python, or PowerShell snippet and asks what the loop does, which conditional skips a dead host, which language belongs on a domain-joined Windows workstation versus a Linux jump box, or which one-line edit exports CSV instead of printing banners. The official uses are information gathering and data manipulation. You collect hostnames, banners, WHOIS blobs, and resolver answers, then split, filter, concatenate, and export those strings so 2.2 enumeration can consume a clean list.

Work example.com the same way as 2.1 and 2.2: stay inside written rules of engagement (RoE). A recon script that loops the agreed hostnames is in play. A script that blindly probes a payment-processor CIDR that only appeared on a certificate SAN is not. Modify the snippet you are given. Do not replace a working ping-skip loop with an unrelated attack framework. Objective 2.3 stops at gathering and shaping data; exploitation scripting is a later domain.

Pick the language from the operating system in the stem

Bash is recon glue on Linux tester boxes (Kali, Parrot, a Linux jump host) and most macOS terminals: pipes (|), redirects (> and >>), command substitution, and one-liners that stitch ping, dig, curl, and cut. If the stem puts you on Linux and the job is "glue existing CLI tools," start in Bash unless the item names a Python library Bash does not ship.

Python is the language of libraries, functions, and classes. requests speaks HTTP, dnspython returns structured DNS records, socket grabs banners, re runs regular expressions, and csv writes a spreadsheet the report can ingest. When the item mentions import, instantiating a class, or calling a named function with arguments, the answer is Python even if a Bash pipeline could scrape the same page.

PowerShell is the language of Windows Active Directory, DNS, and CIM/WMI cmdlets. Resolve-DnsName, Get-ADComputer, Get-NetTCPConnection, and object pipelines (| Select-Object) are the tells. Do not pick Bash to query Active Directory from a domain-joined Windows workstation unless the stem put you on WSL and forbade cmdlets.

Exam trap: language follows the OS, not your favorite lab

The "best" language is the one that already has the API for that operating system. Python requests is wrong when the stem is "list domain computers with an existing AD cmdlet." Bash /etc/passwd is wrong when the stem is a Windows member server with no WSL. PowerShell is wrong when the only box in the screenshot is Kali and the pipeline is dig | cut. Match the interpreter to the screenshot, then modify the smallest construct that changes the output.

Logic constructs: loops, conditionals, and operators

CompTIA lists loops, conditionals, Boolean operators, string operators, and arithmetic operators. Read every snippet top to bottom: initialize, loop, test, transform, write. PT0-003 is testing whether you can modify that flow, not whether you can recite operator-precedence tables.

Loop over hostnames and skip if ping fails (Bash — illustrative, not an exploit):

for h in web mail vpn; do
  ping -c 1 "$h.example.com" >/dev/null 2>&1 || continue
  echo "$h up"
done

The for loop iterates names. || continue is a conditional plus a Boolean or: if ping returns non-zero, skip the rest of that iteration. 2>&1 is I/O redirection — Bash data manipulation, not an attack. >/dev/null discards the ping body so the useful output is only the hosts that answered. If the exam asks what prints when mail is down and web is up, the answer is web up only.

Python with a Boolean and and a string operator that concatenates labels onto the zone:

base = "example.com"
for name in ["web", "mail", "vpn"]:
    host = name + "." + base
    if reachable(host) and name != "vpn":
        print(host)

+ concatenates. and is Boolean. The if also excludes vpn if RoE carved that hostname out. If the exam asks which hosts print, the answer is only names that are reachable and not vpn. Changing != to == inverts the filter — a classic one-character modification item.

Arithmetic on port numbers is a common performance-based flavor:

base = 8000
for i in range(3):
    port = base + i
    print("try", port)

range(3) is the loop. base + i is arithmetic. The script tries 8000, 8001, and 8002 — not 8003. A frequent wrong answer is "it scans 8000 through 8003" from miscounting range. If the stem changes range(3) to range(1, 4), the ports become 8001, 8002, and 8003. Read the bounds before you pick.

PowerShell string operator on a banner:

if ($banner -like "*OpenSSH*") {
  $os = "unix-like"
}

-like with a wildcard is a string operator. -eq, -ne, -and, -or, and -not are the Boolean family stems reuse. If the exam changes -like "*OpenSSH*" to -notlike "*OpenSSH*", the branch flips: you no longer label that banner unix-like. -match is the regex cousin; do not confuse it with -eq, which is exact equality.

Libraries, functions, and classes beat copy-paste

A function packages a repeated action so you change the timeout or the URL in one place. Copy-pasting four raw socket calls is how testers miss an in-scope host when the timeout changes from 2 seconds to 5.

import requests

def grab(url):
    r = requests.get(url, timeout=5)
    return r.headers.get("Server", "")

requests is a library. grab is a function. A class appears when the snippet wraps state — for example a DnsEnumerator that stores a resolver and exposes .a_records(name). You do not author the class on the exam. You recognize that enumerator.a_records("example.com") calls a method on an instance, and that changing the constructor's resolver changes every later lookup. import dns.resolver (dnspython) is the same idea: the library returns objects, not a raw dig string you have to cut yourself.

PowerShell's analog is a script or advanced function. Cmdlets such as Resolve-DnsName example.com are already compiled functions. Import-Module ActiveDirectory is the Windows analog of Python import. If the stem says the tester keeps pasting the same Get-ADComputer filter in five places, the modification the exam wants is wrapping it in a function (or a reusable script) so the filter is edited once.

Data manipulation: split banners, regex IPs, write CSV

Raw recon is messy. Banner Apache/2.4.58 (Ubuntu) is one string; split on spaces or / to isolate product and version. Regex extracts IPv4 from mixed WHOIS text: a pattern for four decimal octets, not a guess from the hostname. After filtering, write CSV (csv.writer in Python, Export-Csv in PowerShell, printf '%s,%s\n' in Bash) so findings enter the report without retyping.

Typical exam edit: change print(ip) so the script appends a host,ip,port row. That is data manipulation, not an exploit payload. Another common edit: skip writing a row when the regex finds no IP (if not match: continue). Boolean plus conditional again. A third: concatenate a scheme onto a hostname ("https://" + host) with a string operator before requests.get.

Worked example.com modification

A performance-based item shows a Python loop over ["www", "api", "dev"], concatenates "." + "example.com", calls grab(), and writes CSV. The RoE excluded dev. The modification is adding if name == "dev": continue (conditional) before the request. You did not rewrite the library. You added a Boolean skip so information gathering stays in scope, then you still export www and api rows. That is 2.3 in one screen.

free PenTest+ practice questionsPractice questions with detailed explanations

Language and construct table

Need in the stemLanguageConstruct or API to modify
Pipe dig into cut on KaliBashLoop, `
HTTP Server header via requestsPythonFunction, library import, timeout=
Structured DNS answers in PythonPythondnspython class or method
AD computer list on WindowsPowerShellGet-ADComputer, -Filter
Skip dead hostsAnyConditional + Boolean (or / -or / `
Build web. plus the zoneAnyString operator (+, concatenation, -like)
Ports 8000–8002AnyArithmetic in a loop (base + i)
Banner to spreadsheetAnySplit or regex, then CSV write

Keep snippets tiny. If a choice shows a 40-line attack payload, it is the wrong domain. For 2.3, the winning edit is almost always a loop bound, a continue, a string join, an arithmetic port, or a CSV write.

Loading diagram...
OS picks the language; constructs shape the output
Test Your Knowledge

A Linux jump box runs this Bash snippet during recon: for h in web mail; do ping -c 1 "$h.example.com" >/dev/null || continue; echo "$h"; done. Mail does not answer ping. What does the script do?

A
B
C
D
Test Your Knowledge

A tester sits at a domain-joined Windows workstation and must list computer objects in Active Directory as part of recon. Which language and API match the stem?

A
B
C
D
Test Your Knowledge

A Python recon script holds mixed WHOIS text for example.com. The tester must extract IPv4 addresses and write host,ip rows for the report. Which modification is the data-manipulation step objective 2.3 is testing?

A
B
C
D