Lab 5.4 - Using PowerShell for Speed and Scale
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.
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 *
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
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-Table18. 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-Table19. 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-Table20. 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-list21. 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
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)