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.
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.
$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.txtLab: 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.
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.
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?