0% found this document useful (0 votes)
25 views12 pages

SystemInfo_v2

The document is a PowerShell script designed to collect system information for security health checks. It generates reports in text, HTML, and CSV formats, detailing aspects such as OS version, CPU, RAM, disk space, and antivirus status, while also logging execution details. The script includes compliance checks and redacts sensitive information as specified in a configuration file.

Uploaded by

odin080700
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
25 views12 pages

SystemInfo_v2

The document is a PowerShell script designed to collect system information for security health checks. It generates reports in text, HTML, and CSV formats, detailing aspects such as OS version, CPU, RAM, disk space, and antivirus status, while also logging execution details. The script includes compliance checks and redacts sensitive information as specified in a configuration file.

Uploaded by

odin080700
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
You are on page 1/ 12

# 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
}
}
#>

You might also like