# SystemInfo.
ps1
# Custom PowerShell script to collect system information for security health checks
# Author: [Your Name]
# Date: April 30, 2025
# Set output directory and timestamp
$Timestamp = Get-Date -Format "yyyyMMdd_HHmmss"
$OutputDir = "$env:USERPROFILE\Desktop\SystemInfo_$Timestamp"
New-Item -ItemType Directory -Path $OutputDir -Force | Out-Null
$TextReport = "$OutputDir\SystemInfo_$env:COMPUTERNAME.txt"
$HtmlReport = "$OutputDir\SystemInfo_$env:COMPUTERNAME.html"
$AuditLog = "$OutputDir\Audit_Log.txt"
$SummaryCsv = "$OutputDir\Summary_$env:COMPUTERNAME.csv"
# Initialize global variables
$global:HtmlContent = "<html><head><style>body{font-family:Arial,sans-
serif;}table{border-collapse:collapse;width:100%;}th,td{border:1px solid
#ddd;padding:8px;text-align:left;}th{background-color:#f2f2f2;}tr:nth-child(even)
{background-color:#f9f9f9;}.status-uptodate{color:green;}.status-
outofdate{color:red;}.status-warning{color:orange;}</style></head><body><h2>System
Information Report</h2><p>Generated on: $(Get-Date)</p><p>Hostname:
$env:COMPUTERNAME</p>"
$global:ErrorLog = @()
$global:Summary = [PSCustomObject]@{
"Hostname" = $env:COMPUTERNAME
"Windows Version" = ""
"Total RAM" = ""
"Disk C Free Space" = ""
"Antivirus Name" = ""
"Definition Status" = ""
"Latest Hotfix" = ""
"BitLocker Enabled" = ""
"Compliance Issues" = ""
}
# Initialize text report
"System Information Report" | Out-File -FilePath $TextReport
"Generated on: $(Get-Date)" | Out-File -FilePath $TextReport -Append
"Hostname: $env:COMPUTERNAME" | Out-File -FilePath $TextReport -Append
"" | Out-File -FilePath $TextReport -Append
# Audit logging
$AuditEntry = "Script executed on $env:COMPUTERNAME by $env:USERNAME at $(Get-
Date)"
$AuditEntry | Out-File -FilePath $AuditLog
# Load configuration from Config.json (sample config below)
$ConfigPath = Join-Path -Path $PSScriptRoot -ChildPath "Config.json"
$Config = @{
"HotfixLimit" = 5
"AntivirusUpdateDays" = 2
"Sections" = @("OS", "CPU", "RAM", "Disk", "PhysicalDisk", "Antivirus",
"Hotfixes", "Network", "Software", "Performance", "Battery", "MissingUpdates",
"Firewall", "UserAccounts", "Encryption")
"RedactFields" = @("IPAddress", "UserName")
"Compliance" = @{
"MinWindowsVersion" = "10.0.19044" # 21H2
"RequireAntivirus" = $true
"RequireBitLocker" = $true
}
}
if (Test-Path $ConfigPath) {
$Config = Get-Content $ConfigPath | ConvertFrom-Json -AsHashtable
}
# Function to redact sensitive data
function Redact-Data {
param ($Value, $FieldName)
if ($Config.RedactFields -contains $FieldName -and $Value) {
return "REDACTED"
}
return $Value
}
# Function to add to reports
function Add-ReportSection {
param (
$Title,
$Data,
$CsvFileName
)
try {
# Text report
"=== $Title ===" | Out-File -FilePath $TextReport -Append
$Data | Format-Table -AutoSize | Out-File -FilePath $TextReport -Append
"" | Out-File -FilePath $TextReport -Append
# HTML report
$global:HtmlContent += "<h3>$Title</h3>"
if ($Data -is [array]) {
foreach ($Item in $Data) {
$global:HtmlContent +=
"<table><tr><th>Property</th><th>Value</th></tr>"
foreach ($Property in $Item.PSObject.Properties) {
$Value = Redact-Data -Value $Property.Value -FieldName
$Property.Name
$Class = if ($Property.Name -eq "Definition Status" -or
$Property.Name -eq "BitLocker Status") { if ($Value -eq "Up to date" -or $Value -eq
"Enabled") { "status-uptodate" } else { "status-outofdate" } } else { "" }
$global:HtmlContent += "<tr><td>$($Property.Name)</td><td
class='$Class'>$Value</td></tr>"
}
$global:HtmlContent += "</table>"
}
}
else {
$global:HtmlContent +=
"<table><tr><th>Property</th><th>Value</th></tr>"
foreach ($Property in $Data.PSObject.Properties) {
$Value = Redact-Data -Value $Property.Value -FieldName
$Property.Name
$Class = if ($Property.Name -eq "Definition Status" -or
$Property.Name -eq "BitLocker Status") { if ($Value -eq "Up to date" -or $Value -eq
"Enabled") { "status-uptodate" } else { "status-outofdate" } } else { "" }
$global:HtmlContent += "<tr><td>$($Property.Name)</td><td
class='$Class'>$Value</td></tr>"
}
$global:HtmlContent += "</table>"
}
# CSV report
if ($CsvFileName -and $Config.Sections -contains ($Title -replace " .*",
"")) {
$CsvPath = "$OutputDir\$CsvFileName"
$Data | Export-Csv -Path $CsvPath -NoTypeInformation -Force
}
}
catch {
Write-Warning "Error in $Title section: $_"
$global:ErrorLog += "Error in ${Title}: $_"
"Error in ${Title}: $_" | Out-File -FilePath $TextReport -Append
}
}
# Function to generate ASCII disk usage chart
function Get-DiskUsageChart {
param ($FreeSpace, $TotalSpace)
$UsedSpace = $TotalSpace - $FreeSpace
$FreePercent = [math]::Round(($FreeSpace / $TotalSpace) * 100)
$UsedPercent = 100 - $FreePercent
$FreeBars = [math]::Round($FreePercent / 5)
$UsedBars = [math]::Round($UsedPercent / 5)
$Chart = "Free ($FreePercent%): " + ("█" * $FreeBars) + "`n"
$Chart += "Used ($UsedPercent%): " + ("█" * $UsedBars)
return $Chart
}
# Function to convert HTML to PDF (placeholder; requires wkhtmltopdf)
function ConvertTo-Pdf {
param ($HtmlFile, $PdfFile)
# Placeholder: Install wkhtmltopdf on USB and uncomment
# & "E:\wkhtmltopdf\bin\wkhtmltopdf.exe" $HtmlFile $PdfFile
Write-Host "PDF export skipped. Install wkhtmltopdf and update ConvertTo-Pdf
function."
}
# Function to consolidate reports (run post-collection)
function Consolidate-Reports {
param ($ReportDir)
$AllSummaries = @()
Get-ChildItem -Path $ReportDir -Filter "Summary_*.csv" | ForEach-Object {
$AllSummaries += Import-Csv $_.FullName
}
$AllSummaries | Export-Csv -Path "$ReportDir\All_Summary.csv" -
NoTypeInformation -Force
Write-Host "Consolidated summary saved to $ReportDir\All_Summary.csv"
}
# 1. Windows Version
if ($Config.Sections -contains "OS") {
try {
$OS = Get-CimInstance -ClassName Win32_OperatingSystem -ErrorAction Stop
$OSInfo = [PSCustomObject]@{
"Windows Version" = $OS.Caption
"Build Number" = $OS.BuildNumber
"Service Pack" = $OS.ServicePackMajorVersion
"Install Date" = $OS.InstallDate
"Last Boot Time" = $OS.LastBootUpTime
}
$global:Summary."Windows Version" = "$($OS.Caption) ($($OS.BuildNumber))"
if ($OS.BuildNumber -lt $Config.Compliance.MinWindowsVersion) {
$global:Summary."Compliance Issues" += "Unsupported Windows version; "
}
Add-ReportSection -Title "Operating System" -Data $OSInfo -CsvFileName
"OS_$env:COMPUTERNAME.csv"
}
catch {
Write-Warning "Failed to retrieve OS info: $_"
$global:ErrorLog += "Failed to retrieve OS info: $_"
}
}
# 2. CPU Information
if ($Config.Sections -contains "CPU") {
try {
$CPU = Get-CimInstance -ClassName Win32_Processor -ErrorAction Stop
$CPUInfo = [PSCustomObject]@{
"Processor" = $CPU.Name
"Cores" = $CPU.NumberOfCores
"Threads" = $CPU.ThreadCount
"Current Clock Speed" = "$($CPU.CurrentClockSpeed) MHz"
"Max Clock Speed" = "$($CPU.MaxClockSpeed) MHz"
}
Add-ReportSection -Title "CPU" -Data $CPUInfo -CsvFileName
"CPU_$env:COMPUTERNAME.csv"
}
catch {
Write-Warning "Failed to retrieve CPU info: $_"
$global:ErrorLog += "Failed to retrieve CPU info: $_"
}
}
# 3. RAM Information
if ($Config.Sections -contains "RAM") {
try {
$OS = Get-CimInstance -ClassName Win32_OperatingSystem -ErrorAction Stop
$RAM = Get-CimInstance -ClassName Win32_PhysicalMemory -ErrorAction Stop
$TotalRAM = [math]::Round(($OS.TotalVisibleMemorySize / 1MB), 2)
$RAMInfo = [PSCustomObject]@{
"Total RAM" = "$TotalRAM GB"
"Used RAM" = "$([math]::Round(($OS.TotalVisibleMemorySize -
$OS.FreePhysicalMemory) / 1MB, 2)) GB"
"Memory Type" = $RAM[0].SMBIOSMemoryType
"Speed" = if ($RAM[0].Speed) { "$($RAM[0].Speed) MHz" } else
{ "Unknown" }
}
$global:Summary."Total RAM" = "$TotalRAM GB"
Add-ReportSection -Title "RAM" -Data $RAMInfo -CsvFileName
"RAM_$env:COMPUTERNAME.csv"
}
catch {
Write-Warning "Failed to retrieve RAM info: $_"
$global:ErrorLog += "Failed to retrieve RAM info: $_"
}
}
# 4. Disk Information
if ($Config.Sections -contains "Disk") {
try {
$Disks = Get-CimInstance -ClassName Win32_LogicalDisk -ErrorAction Stop |
Where-Object {$_.DriveType -eq 3}
foreach ($Disk in $Disks) {
$FreeSpaceGB = [math]::Round($Disk.FreeSpace / 1GB, 2)
$TotalSpaceGB = [math]::Round($Disk.Size / 1GB, 2)
$DiskInfo = [PSCustomObject]@{
"Drive Letter" = $Disk.DeviceID
"Volume Name" = $Disk.VolumeName
"Total Space" = "$TotalSpaceGB GB"
"Free Space" = "$FreeSpaceGB GB"
"Used Space" = "$([math]::Round(($Disk.Size - $Disk.FreeSpace) /
1GB, 2)) GB"
"Usage Chart" = Get-DiskUsageChart -FreeSpace $FreeSpaceGB -
TotalSpace $TotalSpaceGB
}
if ($Disk.DeviceID -eq "C:") {
$global:Summary."Disk C Free Space" = "$FreeSpaceGB GB"
if ($FreeSpaceGB -lt 20) {
$global:Summary."Compliance Issues" += "Low disk space on C:; "
}
}
$SafeDriveID = $Disk.DeviceID -replace ":", ""
Add-ReportSection -Title "Disk $($Disk.DeviceID)" -Data $DiskInfo -
CsvFileName "Disk_${SafeDriveID}_$env:COMPUTERNAME.csv"
}
}
catch {
Write-Warning "Failed to retrieve disk info: $_"
$global:ErrorLog += "Failed to retrieve disk info: $_"
}
}
# 5. HDD/SSD Health (S.M.A.R.T. Status)
if ($Config.Sections -contains "PhysicalDisk") {
try {
$PhysicalDisks = Get-CimInstance -ClassName Win32_DiskDrive -ErrorAction
Stop
foreach ($PhysicalDisk in $PhysicalDisks) {
$DiskHealth = [PSCustomObject]@{
"Model" = $PhysicalDisk.Model
"Serial Number" = Redact-Data -Value $PhysicalDisk.SerialNumber -
FieldName "Serial Number"
"Interface Type" = $PhysicalDisk.InterfaceType
"Status" = $PhysicalDisk.Status
}
Add-ReportSection -Title "Physical Disk $($PhysicalDisk.Index)" -Data
$DiskHealth -CsvFileName "PhysicalDisk_$
($PhysicalDisk.Index)_$env:COMPUTERNAME.csv"
}
}
catch {
Write-Warning "Failed to retrieve physical disk info: $_"
$global:ErrorLog += "Failed to retrieve physical disk info: $_"
}
}
# 6. Antivirus Status
if ($Config.Sections -contains "Antivirus") {
try {
$AntivirusProducts = Get-CimInstance -Namespace root/SecurityCenter2 -
ClassName AntiVirusProduct -ErrorAction Stop
$AntivirusInfoArray = @()
foreach ($Antivirus in $AntivirusProducts) {
$IsDefender = $Antivirus.displayName -like "*Windows Defender*"
$AntivirusInfo = [PSCustomObject]@{
"Antivirus Name" = $Antivirus.displayName
"Product State" = if ($Antivirus.productState -band 0x1000)
{ "Enabled" } else { "Disabled" }
"Definition Status" = "Unknown"
"Note" = ""
}
if ($IsDefender) {
try {
$DefenderStatus = Get-MpComputerStatus -ErrorAction Stop
$AntivirusInfo."Definition Status" = if
($DefenderStatus.AntivirusSignatureLastUpdated -gt (Get-Date).AddDays(-
$Config.AntivirusUpdateDays)) { "Up to date" } else { "Out of date" }
$AntivirusInfo.Note = "Checked via Defender module. Last
updated: $($DefenderStatus.AntivirusSignatureLastUpdated)"
}
catch {
$AntivirusInfo."Definition Status" = "Unknown (Defender check
failed)"
$AntivirusInfo.Note = "Failed to check Defender status: $_"
}
}
else {
$AntivirusInfo."Definition Status" = if ($Antivirus.productState -
band 0x10000) { "Up to date" } else { "Out of date" }
$AntivirusInfo.Note = "Checked via WMI. May be inaccurate for
third-party products."
}
$AntivirusInfoArray += $AntivirusInfo
}
if ($AntivirusInfoArray) {
$global:Summary."Antivirus Name" = $AntivirusInfoArray[0]."Antivirus
Name"
$global:Summary."Definition Status" =
$AntivirusInfoArray[0]."Definition Status"
if ($Config.Compliance.RequireAntivirus -and
($AntivirusInfoArray[0]."Product State" -ne "Enabled" -or
$AntivirusInfoArray[0]."Definition Status" -ne "Up to date")) {
$global:Summary."Compliance Issues" += "Antivirus not enabled or
outdated; "
}
}
Add-ReportSection -Title "Antivirus Products" -Data $AntivirusInfoArray -
CsvFileName "Antivirus_$env:COMPUTERNAME.csv"
}
catch {
Write-Warning "Failed to retrieve antivirus info: $_"
$global:ErrorLog += "Failed to retrieve antivirus info: $_"
$ErrorInfo = [PSCustomObject]@{
"Antivirus Name" = "Unknown"
"Product State" = "Unknown"
"Definition Status" = "Unknown"
"Note" = "Failed to retrieve antivirus info: $_"
}
Add-ReportSection -Title "Antivirus Products" -Data $ErrorInfo -CsvFileName
"Antivirus_$env:COMPUTERNAME.csv"
}
}
# 7. Installed Hotfixes (Patches)
if ($Config.Sections -contains "Hotfixes") {
try {
$Hotfixes = Get-CimInstance -ClassName Win32_QuickFixEngineering -
ErrorAction Stop | Sort-Object InstalledOn -Descending | Select-Object -First
$Config.HotfixLimit
foreach ($Hotfix in $Hotfixes) {
$HotfixInfo = [PSCustomObject]@{
"Hotfix ID" = $Hotfix.HotFixID
"Description" = $Hotfix.Description
"Installed On" = $Hotfix.InstalledOn
}
if (-not $global:Summary."Latest Hotfix") {
$global:Summary."Latest Hotfix" = "$($Hotfix.HotFixID) ($
($Hotfix.InstalledOn))"
}
$SafeHotfixID = $Hotfix.HotFixID -replace "[^a-zA-Z0-9]", "_"
Add-ReportSection -Title "Hotfix $($Hotfix.HotFixID)" -Data $HotfixInfo
-CsvFileName "Hotfix_${SafeHotfixID}_$env:COMPUTERNAME.csv"
}
}
catch {
Write-Warning "Failed to retrieve hotfix info: $_"
$global:ErrorLog += "Failed to retrieve hotfix info: $_"
}
}
# 8. Network Configuration
if ($Config.Sections -contains "Network") {
try {
$NetConfig = Get-NetIPConfiguration -ErrorAction Stop | Where-Object
{$_.IPv4Address}
$FirewallProfiles = Get-NetFirewallProfile -ErrorAction Stop
$NetInfo = [PSCustomObject]@{
"IPAddress" = Redact-Data -Value ($NetConfig.IPv4Address.IPAddress -
join ", ") -FieldName "IPAddress"
"Subnet Mask" = $NetConfig.IPv4Address.PrefixLength
"Default Gateway" = $NetConfig.IPv4DefaultGateway.NextHop
"DNS Servers" = $NetConfig.DNSServer.ServerAddresses -join ", "
"Firewall Profile" = ($FirewallProfiles | Where-Object {$_.Enabled} |
Select-Object -ExpandProperty Name) -join ", "
}
Add-ReportSection -Title "Network Configuration" -Data $NetInfo -
CsvFileName "Network_$env:COMPUTERNAME.csv"
}
catch {
Write-Warning "Failed to retrieve network info: $_"
$global:ErrorLog += "Failed to retrieve network info: $_"
}
}
# 9. Installed Software
if ($Config.Sections -contains "Software") {
try {
$Software = Get-Package -Provider Programs -ErrorAction Stop | Select-
Object -First 10
$SoftwareInfo = $Software | ForEach-Object {
[PSCustomObject]@{
"Name" = $_.Name
"Version" = $_.Version
"Publisher" = $_.Publisher
}
}
Add-ReportSection -Title "Installed Software" -Data $SoftwareInfo -
CsvFileName "Software_$env:COMPUTERNAME.csv"
}
catch {
Write-Warning "Failed to retrieve software info: $_"
$global:ErrorLog += "Failed to retrieve software info: $_"
}
}
# 10. System Performance
if ($Config.Sections -contains "Performance") {
try {
$OS = Get-CimInstance -ClassName Win32_OperatingSystem -ErrorAction Stop
$Processes = Get-Process -ErrorAction Stop
$PerformanceInfo = [PSCustomObject]@{
"Uptime" = "$([math]::Round(($OS.LastBootUpTime - (Get-
Date)).TotalDays, 2)) days"
"CPU Usage" = "$([math]::Round(($Processes | Measure-Object -Property
CPU -Sum).Sum / ($OS.NumberOfProcessors * 1000), 2)) %"
"Memory Usage" = "$([math]::Round(($OS.TotalVisibleMemorySize -
$OS.FreePhysicalMemory) / $OS.TotalVisibleMemorySize * 100, 2)) %"
"Running Processes" = $Processes.Count
}
Add-ReportSection -Title "System Performance" -Data $PerformanceInfo -
CsvFileName "Performance_$env:COMPUTERNAME.csv"
}
catch {
Write-Warning "Failed to retrieve performance info: $_"
$global:ErrorLog += "Failed to retrieve performance info: $_"
}
}
# 11. Battery Health
if ($Config.Sections -contains "Battery") {
try {
$Battery = Get-CimInstance -ClassName Win32_Battery -ErrorAction Stop
if ($Battery) {
$BatteryInfo = [PSCustomObject]@{
"Design Capacity" = "$($Battery.DesignCapacity) mWh"
"Full Charge Capacity" = "$($Battery.FullChargeCapacity) mWh"
"Health Percentage" = if ($Battery.FullChargeCapacity -and
$Battery.DesignCapacity) { "$([math]::Round(($Battery.FullChargeCapacity /
$Battery.DesignCapacity) * 100, 2)) %" } else { "Unknown" }
}
Add-ReportSection -Title "Battery Health" -Data $BatteryInfo -
CsvFileName "Battery_$env:COMPUTERNAME.csv"
}
}
catch {
Write-Warning "Failed to retrieve battery info: $_"
$global:ErrorLog += "Failed to retrieve battery info: $_"
}
}
# 12. Missing Windows Updates
if ($Config.Sections -contains "MissingUpdates") {
try {
# Fallback WMI check (offline)
$UpdateInfo = [PSCustomObject]@{
"Status" = "PSWindowsUpdate module not installed. Install for detailed
update check."
"Note" = "Run 'Install-Module PSWindowsUpdate' on a system with
internet access."
}
# Uncomment for PSWindowsUpdate (requires module)
# $Updates = Get-WindowsUpdate -MicrosoftUpdate -ErrorAction Stop
# $UpdateInfo = $Updates | ForEach-Object {
# [PSCustomObject]@{
# "KB Article" = $_.KBArticleIDs
# "Title" = $_.Title
# "Severity" = $_.MsrcSeverity
# }
# }
Add-ReportSection -Title "Missing Updates" -Data $UpdateInfo -CsvFileName
"MissingUpdates_$env:COMPUTERNAME.csv"
}
catch {
Write-Warning "Failed to retrieve missing updates: $_"
$global:ErrorLog += "Failed to retrieve missing updates: $_"
}
}
# 13. Firewall Rules Audit
if ($Config.Sections -contains "Firewall") {
try {
$FirewallRules = Get-NetFirewallRule -Direction Inbound -Enabled True -
ErrorAction Stop | Select-Object -First 5
$FirewallInfo = $FirewallRules | ForEach-Object {
[PSCustomObject]@{
"Name" = $_.Name
"Display Name" = $_.DisplayName
"Action" = $_.Action
"Local Ports" = $_.LocalPort
}
}
Add-ReportSection -Title "Firewall Rules" -Data $FirewallInfo -CsvFileName
"Firewall_$env:COMPUTERNAME.csv"
}
catch {
Write-Warning "Failed to retrieve firewall rules: $_"
$global:ErrorLog += "Failed to retrieve firewall rules: $_"
}
}
# 14. User Account Security
if ($Config.Sections -contains "UserAccounts") {
try {
$Users = Get-LocalUser -ErrorAction Stop
$UAC = (Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows\
CurrentVersion\Policies\System" -Name "EnableLUA").EnableLUA
$UserInfo = $Users | ForEach-Object {
[PSCustomObject]@{
"UserName" = Redact-Data -Value $_.Name -FieldName "UserName"
"Enabled" = $_.Enabled
"IsAdmin" = ($_.PrincipalSource -eq "Local" -and (net user $_.Name
| Select-String "Local Group Memberships" | Select-String "Administrators"))
}
}
$UserInfo += [PSCustomObject]@{
"UserName" = "UAC Status"
"Enabled" = if ($UAC) { "Enabled" } else { "Disabled" }
"IsAdmin" = ""
}
Add-ReportSection -Title "User Accounts" -Data $UserInfo -CsvFileName
"UserAccounts_$env:COMPUTERNAME.csv"
}
catch {
Write-Warning "Failed to retrieve user account info: $_"
$global:ErrorLog += "Failed to retrieve user account info: $_"
}
}
# 15. Encryption Status
if ($Config.Sections -contains "Encryption") {
try {
$BitLocker = Get-BitLockerVolume -ErrorAction Stop
$TPM = Get-Tpm -ErrorAction Stop -ErrorAction SilentlyContinue
$EncryptionInfo = $BitLocker | ForEach-Object {
[PSCustomObject]@{
"Drive Letter" = $_.MountPoint
"BitLocker Status" = if ($_.VolumeStatus -eq "FullyEncrypted")
{ "Enabled" } else { "Disabled" }
"Encryption Method" = $_.EncryptionMethod
}
}
if ($TPM) {
$EncryptionInfo += [PSCustomObject]@{
"Drive Letter" = "TPM"
"BitLocker Status" = if ($TPM.TpmPresent) { "Present" } else { "Not
Present" }
"Encryption Method" = ""
}
}
if ($Config.Compliance.RequireBitLocker -and ($EncryptionInfo | Where-
Object { $_.MountPoint -eq "C:" -and $_.BitLockerStatus -ne "Enabled" })) {
$global:Summary."Compliance Issues" += "BitLocker not enabled on C:; "
}
$global:Summary."BitLocker Enabled" = ($EncryptionInfo | Where-Object
{ $_.MountPoint -eq "C:" }).BitLockerStatus
Add-ReportSection -Title "Encryption Status" -Data $EncryptionInfo -
CsvFileName "Encryption_$env:COMPUTERNAME.csv"
}
catch {
Write-Warning "Failed to retrieve encryption info: $_"
$global:ErrorLog += "Failed to retrieve encryption info: $_"
}
}
# 16. Error Summary
if ($global:ErrorLog) {
$ErrorSummary = $global:ErrorLog | ForEach-Object {
[PSCustomObject]@{
"Error Message" = $_
}
}
Add-ReportSection -Title "Error Summary" -Data $ErrorSummary -CsvFileName
"Errors_$env:COMPUTERNAME.csv"
}
# 17. Executive Summary
$SummaryText = "<h3>Executive
Summary</h3><table><tr><th>Metric</th><th>Value</th></tr>"
foreach ($Prop in $global:Summary.PSObject.Properties) {
$Value = $Prop.Value
$Class = if ($Prop.Name -eq "Compliance Issues" -and $Value) { "status-warning"
} else { "" }
$SummaryText += "<tr><td>$($Prop.Name)</td><td class='$Class'>$Value</td></tr>"
}
$SummaryText += "</table>"
$global:HtmlContent = $global:HtmlContent -replace "<h2>System Information
Report</h2>", "<h2>System Information Report</h2>$SummaryText"
# Finalize reports
$global:HtmlContent += "</body></html>"
$global:HtmlContent | Out-File -FilePath $HtmlReport
$global:Summary | Export-Csv -Path $SummaryCsv -NoTypeInformation -Force
# Generate PDF (placeholder)
$PdfReport = "$OutputDir\SystemInfo_$env:COMPUTERNAME.pdf"
ConvertTo-Pdf -HtmlFile $HtmlReport -PdfFile $PdfReport
# Audit file hashes
Get-ChildItem -Path $OutputDir -File | ForEach-Object {
$Hash = Get-FileHash -Path $_.FullName -Algorithm SHA256
"File: $($_.Name), Hash: $($Hash.Hash)" | Out-File -FilePath $AuditLog -Append
}
# Output completion message
Write-Host "System information collected. Reports saved to:"
Write-Host "- Text: $TextReport"
Write-Host "- HTML: $HtmlReport"
Write-Host "- PDF: $PdfReport (if enabled)"
Write-Host "- CSVs: $OutputDir\*.csv"
Write-Host "- Audit Log: $AuditLog"
# Instructions for batch execution (uncomment for remote execution)
<#
$Computers = @("Laptop1", "Laptop2") # Replace with target hostnames
Invoke-Command -ComputerName $Computers -FilePath $PSCommandPath -Credential (Get-
Credential)
# For USB-based batch:
# 1. Copy script to USB (e.g., E:\Scripts\SystemInfo.ps1).
# 2. Run on each laptop: powershell -File E:\Scripts\SystemInfo.ps1
# 3. Move outputs to E:\Reports\Laptop1, E:\Reports\Laptop2, etc.
# 4. Run Consolidate-Reports -ReportDir E:\Reports
#>
# Sample Config.json
<#
{
"HotfixLimit": 5,
"AntivirusUpdateDays": 2,
"Sections": ["OS", "CPU", "RAM", "Disk", "PhysicalDisk", "Antivirus",
"Hotfixes", "Network", "Software", "Performance", "Battery", "MissingUpdates",
"Firewall", "UserAccounts", "Encryption"],
"RedactFields": ["IPAddress", "UserName"],
"Compliance": {
"MinWindowsVersion": "10.0.19044",
"RequireAntivirus": true,
"RequireBitLocker": true
}
}
#>