Skip to main content
← Back to lab
SEC401 - Windows Security | Printable command sheet
Lab 5.4 - Using PowerShell for Speed and Scale

Lab 5.4 - Using PowerShell for Speed and Scale

Windows Security | SEC401 | Apr 2026

Used PowerShell cmdlets, the object pipeline, Out-GridView, and Invoke-Command against three remote alpha-svr hosts to enumerate processes and services, then hunted a suspicious BrokerSvc service running broker.exe as LocalSystem and captured its SHA-256 for IOC sharing.

Tools: PowerShell, Invoke-Command, Get-WinEvent, Get-FileHash, Out-GridView

Commands

1. Process overview with Get-Process

Baseline enumeration of every running process with handles, memory (PM/WS), CPU seconds, PID, and ProcessName. This is the PowerShell equivalent of tasklist, but every row is a live object you can pipe into further filters.

Get-Process

2. Deep property view on a single process

Piped one process into Select-Object -Property * to expose every property the object exposes — FileVersion, Path, Company, HandleCount, WorkingSet, VirtualMemorySize, BasePriority. This is how you learn what you can filter on before writing a Where-Object clause.

Get-Process -Name explorer | Select-Object -Property *
-Name: match by process name Select-Object -Property *: dump every property on the pipeline object

3. Launch and inspect a process

Started Notepad with Start-Process, then introspected it with Select-Object *. Confirmed the AppX path under C:\Program Files\WindowsApps — useful detail when triaging whether a running binary is the Microsoft-signed Store build or a sideloaded copy.

Start-Process notepad.exe
Get-Process -Name notepad | Select-Object *

4. Capture a process into a variable

Stored the Notepad process object in $NotepadProc. Variables in PowerShell hold live objects (not strings), so $NotepadProc carries every method and property the process exposes — which is why the next step works.

$NotepadProc = Get-Process -Name notepad
$NotepadProc

5. Invoke a method on the stored object

Called .kill() on the stored object to terminate Notepad, then re-queried Get-Process to confirm the process is gone (ObjectNotFound error proves the kill succeeded). This pattern — capture, act, re-verify — is the bread-and-butter of automated incident response.

$NotepadProc.kill()
Get-Process -Name notepad

6. Enumerate Windows services

Get-Service returns every service with Status, Name, and DisplayName. Same object-pipeline story as Get-Process — downstream cmdlets operate on service objects, not parsed text.

Get-Service

7. Count services with Measure-Object

Piped Get-Service to Measure-Object — 278 services installed on this host. Measure-Object is the PowerShell analog to wc -l, except it counts pipeline objects, not lines of text.

Get-Service | Measure-Object

8. Filter services to only those Running

Where-Object -Property Status -like Running narrows the pipeline to active services. Same object flowing through: Get-Service produces, Where-Object filters.

Get-Service | Where-Object -Property Status -like Running
Where-Object: filter pipeline objects by a predicate -Property Status: property to test -like Running: comparison (-like is case-insensitive wildcard)

9. Count the running services

Chained the same filter into Measure-Object — 96 of 278 services are Running. Two cmdlets, one pipeline, zero intermediate files.

Get-Service | Where-Object -Property Status -like Running | Measure-Object

10. Out-GridView for interactive triage

Piped Get-Service to Out-GridView — a sortable, filterable GUI grid. Out-GridView is a triage tool: you can click-filter to a subset, then send the selection back to the pipeline for further processing.

Get-Service | Out-GridView

11. Live filter inside Out-GridView

Added a 'Status contains Running' criteria inside Out-GridView to narrow the grid interactively. Useful when you want to poke around without writing the full Where-Object in advance.

Get-Service | Out-GridView

12. Export to CSV and open in ISE

Dumped every service object to Services.csv with Export-Csv, then opened it in the PowerShell ISE for inspection. Export-Csv serializes every property of every pipeline object — great for offline analysis or evidence preservation.

Get-Service | Export-CSV -Path Services.csv
ise .\Services.csv

13. Directory listing and alias discovery

Used dir to list the lab directory, then Get-Alias dir to confirm dir is just an alias for Get-ChildItem. Knowing the underlying cmdlet is what lets you pipe dir into object-aware cmdlets like Sort-Object.

dir
Get-Alias dir

14. Inspect a file as an object

Piped one CSV into Format-List * to expose every property on the FileSystemInfo object — PSPath, VersionInfo, BaseName, Length. Same object-pipeline mental model as processes and services: a file is an object with properties, not just a name.

dir .\Services.csv | Format-List *

15. Sort directory listing by CreationTime

Piped dir into Sort-Object CreationTime — Services.csv sorts last because it was just created, while the original .ps1 scripts share an older 12/16/2023 timestamp.

dir | Sort-Object CreationTime

16. Bootstrap the fleet and load the server list

Ran start-servers.ps1 to bring the alpha-svr fleet online, then loaded the server list into a typed array with [string[]]$AlphaServers = Get-Content. Typing matters: [string[]] tells Invoke-Command to treat $AlphaServers as a list of computer names, not one long string.

./start-servers.ps1
[string[]]$AlphaServers = Get-Content -Path 'C:\sec401\labs\5.4\alpha-servers.txt'
$AlphaServers

17. Invoke-Command across the fleet with credentials

Captured credentials with Get-Credential, then ran Get-CimInstance Win32_OperatingSystem remotely on all three alpha-svr hosts in one call. The output is a single table with a PSComputerName column — Invoke-Command returns deserialized objects from every remote host, merged into one pipeline.

$creds = Get-Credential
invoke-command -Authentication Basic -Credential $creds -ComputerName $AlphaServers -command { Get-CimInstance Win32_OperatingSystem | Select-Object CSName, Caption } | Format-Table
-Authentication Basic: simple auth (lab only — use Kerberos/CredSSP in prod) -Credential: PSCredential object from Get-Credential -ComputerName: array of targets -command { ... }: scriptblock executed on every remote host

18. Negative control: probe for a file that doesn't exist

Ran Get-ChildItem C:\Windows\System32\proxy.exe across the fleet — all three hosts returned PathNotFound. This is a deliberate negative control: it proves Invoke-Command is routing to all three hosts and that the hunt query below isn't silently failing.

invoke-command -Authentication Basic -Credential $creds -ComputerName $AlphaServers -command { Get-ChildItem C:\Windows\System32\proxy.exe } | Format-Table

19. Fleet-wide enumeration of C:\Windows\*.exe

Listed every EXE directly under C:\Windows on all three hosts. The output reveals the same five binaries on each host — bfsvc.exe, notepad.exe, regedit.exe, write.exe (expected Windows binaries) plus broker.exe with a 10/21/2023 timestamp. broker.exe is not a default Windows binary at that path and shows up on every host — a strong IOC signal.

invoke-command -Authentication Basic -Credential $creds -ComputerName $AlphaServers -command { Get-ChildItem C:\Windows\*.exe } | Format-Table

20. Correlate with Event ID 7045 (service installed)

Entered a remote session on alpha-svr3 and queried the System log for Event ID 7045 (Service Control Manager: a service was installed). Got a direct match: BrokerSvc, c:\Windows\broker.exe, user mode service, auto start, running as LocalSystem. That's the full install record — who installed it (SCM context), when (TimeCreated 12/12/2023), and with what privileges (LocalSystem = full admin on the box).

Get-WinEvent -FilterHashtable @{LogName='System'; ID=7045} -MaxEvents 3 | format-list
-FilterHashtable: server-side XPath-equivalent filter (fast) LogName: which log to query ID=7045: Service Control Manager 'a service was installed' event -MaxEvents 3: cap results

21. Hash the suspicious binary for IOC sharing

Ran Get-FileHash -Algorithm SHA256 against C:\Windows\broker.exe on the remote host. SHA-256: 646DF7C22A76C92CF6CD83A9B7970C95514047C9431B29909732C62F28963E31. That hash is the shareable IOC: feed it to VirusTotal, add it to a SIEM watchlist, or block it with Defender ASR — it's what turns this single-lab finding into fleet-wide detection content.

Get-FileHash -Algorithm SHA256 C:\Windows\broker.exe
-Algorithm SHA256: hash algorithm (MD5/SHA1/SHA256/SHA512 supported)

Key Findings

  • 278 services enumerated on the admin workstation; 96 Running
  • broker.exe present on alpha-svr1/2/3.local under C:\Windows with matching 10/21/2023 timestamp
  • Event ID 7045 shows BrokerSvc installed as auto-start user-mode service under LocalSystem
  • SHA-256 of broker.exe: 646DF7C22A76C92CF6CD83A9B7970C95514047C9431B29909732C62F28963E31
  • Invoke-Command successfully executed against three hosts in parallel from a single console

Security Controls

  • PowerShell remoting over WinRM (constrained to signed scriptblocks in prod)
  • Service installation auditing (Event ID 7045, 4697)
  • File integrity monitoring + SHA-256 IOC sharing
  • Endpoint detection (Defender for Endpoint, Sysmon)
  • Least-privilege service accounts (no LocalSystem for custom services)