# PowerShell Windows Host Security Audit Script Generator

> Source: https://netray.co/tools/powershell-windows-host-security-audit-script-generator
> Publisher: Netray (netray.co), AI and integration engineering for ERP and manufacturing systems.
> Section: Free Tools

## Short answer

Produce a read-only script that gathers local administrators, listening ports, installed updates and scheduled tasks from a list of servers into CSV files.

## Category

developer

## Industry

Manufacturing

## Audience

- IT security lead
- System administrator

## Tool

**Kind:** template

**Output:** code

**Language:** powershell

**Fields:**

#### Server names (comma separated)

**Key:** servers

**Type:** text

**Default:** ERP-APP01,MES-DB01,HMI-SRV02

**Help:** Hosts reachable with WinRM from your admin workstation.

#### Output folder

**Key:** out_dir

**Type:** text

**Default:** C:\SecAudit

#### Flag updates older than (days)

**Key:** stale_days

**Type:** number

**Default:** 60

**Blocks:**

#### Setup and inventory

**Body:** # Read-only audit. Run from an admin workstation with WinRM access.
$servers = '{{servers}}' -split ','
$outDir  = '{{out_dir}}'
New-Item -ItemType Directory -Force -Path $outDir | Out-Null
$stamp = Get-Date -Format 'yyyyMMdd-HHmm'

#### Local administrators

**Body:** $admins = Invoke-Command -ComputerName $servers -ScriptBlock {
  Get-LocalGroupMember -Group 'Administrators' | Select-Object Name, ObjectClass, PrincipalSource
}
$admins | Select-Object PSComputerName, Name, ObjectClass, PrincipalSource |
  Export-Csv "$outDir\local-admins-$stamp.csv" -NoTypeInformation

#### Listening ports and owning process

**Body:** $ports = Invoke-Command -ComputerName $servers -ScriptBlock {
  Get-NetTCPConnection -State Listen | ForEach-Object {
    $p = Get-Process -Id $_.OwningProcess -ErrorAction SilentlyContinue
    [pscustomobject]@{ Port = $_.LocalPort; Address = $_.LocalAddress; Process = $p.ProcessName }
  }
}
$ports | Select-Object PSComputerName, Port, Address, Process |
  Export-Csv "$outDir\listening-ports-$stamp.csv" -NoTypeInformation

#### Installed updates and staleness

**Body:** $hotfixes = Invoke-Command -ComputerName $servers -ScriptBlock {
  Get-HotFix | Sort-Object InstalledOn -Descending | Select-Object -First 1 HotFixID, InstalledOn
}
$hotfixes | ForEach-Object {
  $age = if ($_.InstalledOn) { (New-TimeSpan -Start $_.InstalledOn -End (Get-Date)).Days } else { -1 }
  [pscustomobject]@{ Server = $_.PSComputerName; LastKB = $_.HotFixID; Installed = $_.InstalledOn; AgeDays = $age; Stale = ($age -gt {{stale_days}}) }
} | Export-Csv "$outDir\last-update-$stamp.csv" -NoTypeInformation

#### Non-Microsoft scheduled tasks

**Body:** $tasks = Invoke-Command -ComputerName $servers -ScriptBlock {
  Get-ScheduledTask | Where-Object { $_.TaskPath -notlike '\Microsoft\*' } |
    Select-Object TaskName, TaskPath, State, @{n='RunAs';e={$_.Principal.UserId}}
}
$tasks | Select-Object PSComputerName, TaskName, TaskPath, State, RunAs |
  Export-Csv "$outDir\scheduled-tasks-$stamp.csv" -NoTypeInformation
Write-Host "Audit files written to $outDir"

**Notes:** Read-only commands, but test on one non-production host first. Requires PowerShell remoting enabled for the target hosts and an account with local administrator rights. Get-LocalGroupMember can fail when an orphaned domain SID is in the group, so review errors. Check the script with your change process before running it on plant servers.

## Content

**Intro:** Before you can harden plant and ERP servers you need to know who is a local administrator, what is listening and when each host last patched. This generator builds a read-only script that collects exactly that into CSV files.

**Sections:**

#### How to use it

**Body:** Enter your server names, an output folder and the age in days at which an update should be treated as stale. Copy the blocks into one script, review it, and run it from an admin workstation that has WinRM access. The script writes four time-stamped CSV files you can open in Excel and attach to an audit record or a risk register entry.

**Bullets:**

- Start with three to five hosts
- Keep CSVs in a restricted folder
- Re-run monthly and compare to the last file

#### What to look for

**Body:** In the administrator list, look for personal accounts, shared service accounts and domain groups that nobody remembers adding. In listening ports, look for remote management services, old FTP or Telnet, and database ports reachable from places they should not be. In the update file, a host months behind is a finding. In scheduled tasks, look for tasks running as high-privilege accounts from user-writable paths.

#### Fit for OT hosts

**Body:** HMI and historian servers may run vendor-certified builds where patching follows a vendor schedule. A stale flag there is a prompt to check the vendor bulletin, not an instruction to patch immediately. Document the compensating controls, such as segmentation and application allow lists, next to the finding.

#### Common mistakes

**Body:** Running a new script against a production line server without a change window is risky even when it only reads. Another error is leaving output CSVs on a shared drive: they are a map of your attack surface. Finally, do not treat a clean report as proof of security. It shows four facts about each host, nothing more.

**Cta:** If you want the output of audits like this fed into a single risk register or ERP-linked asset record, Netray can help build that pipeline.

**Faq:**

#### Is the script safe to run?

**Answer:** It only reads information and writes CSV files to the folder you name. Still test on a non-production host and follow your change process. Remoting and local admin rights are required, which is itself a sensitive permission.

#### Why use Invoke-Command?

**Answer:** It runs the block on each remote host through WinRM in parallel and returns objects tagged with PSComputerName, which keeps the exported CSV tidy and avoids installing anything on the targets.

#### What if WinRM is not enabled?

**Answer:** Enable it through group policy on managed servers, or run the script locally on each host with the server list reduced to localhost. Do not open WinRM broadly just to run an audit.

#### Can I extend it?

**Answer:** Yes. Add blocks for local users, installed software from the registry uninstall keys, or firewall profile status. Keep each block read-only and write its own CSV for easy comparison over time.

## Search terms

powershell audit local administrators, powershell list listening ports, powershell get-hotfix export csv, windows server security audit script, powershell scheduled tasks export, invoke-command multiple servers audit, plant server audit script

---
Talk to an engineer: https://netray.co/contact?intent=erp_ai | Machine catalog: https://netray.co/agent/catalog.json
