HackBlue

Tools · Python and Bash for security automation · 16 / 20

Collecting security inventory from many Windows hosts with PowerShell remoting

Use Invoke-Command over WinRM to run the same read-only audit on several lab hosts in parallel, collect results with the computer name, and handle offline hosts.

10 min read · practice only with authorization

How remoting works

PowerShell remoting uses WinRM, listening on 5985 (HTTP) and 5986 (HTTPS). In a domain, Kerberos authenticates and encrypts the session even over 5985. Invoke-Command runs a script block on many computers in parallel and returns objects tagged with PSComputerName. Restrict who can use remoting with group membership and firewall rules, and log it with PowerShell script block logging.

A read-only inventory

The script block below collects OS version, last boot, Defender status, and local administrators. -ErrorVariable captures hosts that failed so you can report them.

Snippet
$computers = Get-Content .\hosts.txt
$sb = {
    $os = Get-CimInstance Win32_OperatingSystem
    $mp = Get-MpComputerStatus
    [pscustomobject]@{
        OS              = $os.Caption
        Build           = $os.BuildNumber
        LastBoot        = $os.LastBootUpTime
        AVEnabled       = $mp.AntivirusEnabled
        RealTime        = $mp.RealTimeProtectionEnabled
        SignatureAgeDays = $mp.AntivirusSignatureAge
        Admins          = (Get-LocalGroupMember Administrators | ForEach-Object Name) -join '; '
    }
}
$results = Invoke-Command -ComputerName $computers -ScriptBlock $sb -ThrottleLimit 16 -ErrorAction SilentlyContinue -ErrorVariable failed
$results | Select-Object PSComputerName, OS, Build, LastBoot, AVEnabled, RealTime, SignatureAgeDays, Admins | Export-Csv inventory.csv -NoTypeInformation
$failed | ForEach-Object { $_.TargetObject } | Sort-Object -Unique | Set-Content unreachable.txt

Lab: two VMs and a report

Set up two Windows lab VMs in a lab domain, or enable remoting in a workgroup with Enable-PSRemoting and TrustedHosts set only to your lab IPs. Run the inventory, open the CSV, and flag hosts with real-time protection off or signatures older than three days. Shut one VM down and confirm it appears in unreachable.txt.

Snippet
Enable-PSRemoting -Force                                  # on each lab VM
Set-Item WSMan:\localhost\Client\TrustedHosts -Value '192.168.56.21,192.168.56.22'   # workgroup lab only
Import-Csv inventory.csv | Where-Object { $_.RealTime -eq 'False' -or [int]$_.SignatureAgeDays -gt 3 }

Safety

Keep inventory script blocks read-only and review them before running across many hosts. Avoid broad TrustedHosts wildcards outside a lab. Use Just Enough Administration (JEA) endpoints in production to restrict what remote sessions can do.

Diagram

Inventory results by host

Each row carries PSComputerName.

PSComputerNameRealTimeunreachable

WS01

Windows 11, RealTime True, SignatureAgeDays 0
OK

WS02

Windows 11, RealTime False, SignatureAgeDays 9
Flag

WS03

Connection failed
unreachable.txt

Check yourself

1. Which ports does WinRM use by default?

2. Which property identifies which host returned each result?

3. What restricts what users can do in remote sessions in production?