WindowsHealthAudit/WindowsHealthAudit.ps1
2025-04-10 14:26:15 +00:00

195 lines
6.2 KiB
PowerShell

<#
.SYNOPSIS
Windows Device Health Audit with Auto-Elevation
.DESCRIPTION
Performs comprehensive system checks with automatic admin elevation when needed.
Logs to: C:\Logs\DeviceAudit\AUDIT_[HOSTNAME]_[DATE].log
.NOTES
Version: 1.2
Author: Your Name
.EXAMPLE
# Basic check (non-admin):
.\WindowsHealthAudit.ps1
.EXAMPLE
# Full check (auto-elevates to admin if needed):
.\WindowsHealthAudit.ps1 -Full
#>
param(
[switch]$Full = $false
)
#region Initial Setup
# ------------------
$logDir = "C:\Logs\DeviceAudit"
$logFile = "$logDir\AUDIT_$($env:COMPUTERNAME)_$(Get-Date -Format 'ddMMyyyy').log"
# Create log directory if missing
if (-not (Test-Path $logDir)) {
New-Item -Path $logDir -ItemType Directory -Force | Out-Null
}
# Clear previous log
if (Test-Path $logFile) {
Clear-Content $logFile
}
#endregion
#region Logging Function
# ---------------------
function Write-Log {
param (
[string]$Message,
[string]$Level = "INFO"
)
$timestamp = Get-Date -Format "dd-MM-yyyy HH:mm:ss"
$logEntry = "$timestamp $Level`: $Message"
Write-Output $logEntry
$logEntry | Out-File -FilePath $logFile -Append -Encoding UTF8
}
#endregion
#region Self-Elevation
# -------------------
$isAdmin = [bool](([System.Security.Principal.WindowsIdentity]::GetCurrent()).Groups -match 'S-1-5-32-544')
if ($Full -and (-not $isAdmin)) {
Write-Host "Re-launching as administrator..." -ForegroundColor Yellow
try {
$scriptPath = $MyInvocation.MyCommand.Path
Start-Process pwsh -ArgumentList "-NoProfile -ExecutionPolicy Bypass -File `"$scriptPath`" -Full" -Verb RunAs -WindowStyle Hidden
exit
} catch {
Write-Host "Failed to elevate! Running in basic mode." -ForegroundColor Red
$Full = $false
}
}
#endregion
#region Main Audit
# ---------------
Write-Log "=== WINDOWS DEVICE HEALTH AUDIT ==="
Write-Log "Host: $($env:COMPUTERNAME)"
Write-Log "User: $($env:USERNAME)"
Write-Log "Mode: $(if ($Full) {'FULL (Admin)'} else {'BASIC (Non-Admin)'})"
Write-Log "Date: $(Get-Date -Format 'dd-MM-yyyy HH:mm:ss')"
Write-Log ""
# 1. System Information
Write-Log "=== SYSTEM INFORMATION ==="
$os = Get-CimInstance Win32_OperatingSystem
$computer = Get-CimInstance Win32_ComputerSystem
$uptime = (Get-Date) - $os.LastBootUpTime
Write-Log "OS: $($os.Caption) (Build: $($os.BuildNumber))"
Write-Log "Uptime: $($uptime.Days)d $($uptime.Hours)h $($uptime.Minutes)m"
Write-Log "Manufacturer: $($computer.Manufacturer)"
Write-Log "Model: $($computer.Model)"
Write-Log "RAM: $([math]::Round($computer.TotalPhysicalMemory / 1GB, 2)) GB"
Write-Log ""
# 2. Performance Metrics
Write-Log "=== PERFORMANCE ==="
$cpuLoad = (Get-CimInstance Win32_Processor | Measure-Object -Property LoadPercentage -Average).Average
$memory = Get-CimInstance Win32_OperatingSystem
$usedMem = [math]::Round(($memory.TotalVisibleMemorySize - $memory.FreePhysicalMemory) / 1MB, 2)
$totalMem = [math]::Round($memory.TotalVisibleMemorySize / 1MB, 2)
Write-Log "CPU Load: $cpuLoad%"
Write-Log "Memory Usage: $usedMem/$totalMem GB ($([math]::Round(($usedMem/$totalMem)*100))% used)"
Write-Log ""
# 3. Disk Information
Write-Log "=== DISK STORAGE ==="
Get-CimInstance Win32_LogicalDisk -Filter "DriveType = 3" | ForEach-Object {
$freeGB = [math]::Round($_.FreeSpace / 1GB, 2)
$totalGB = [math]::Round($_.Size / 1GB, 2)
$pctUsed = [math]::Round(($totalGB - $freeGB) / $totalGB * 100, 2)
if ($pctUsed -gt 90) {
Write-Log "WARNING: $($_.DeviceID) low space: $freeGB GB free ($pctUsed% used)" -Level "WARNING"
} else {
Write-Log "$($_.DeviceID): $freeGB GB free of $totalGB GB ($pctUsed% used)"
}
}
Write-Log ""
# 4. Admin-Only Checks
if ($Full) {
Write-Log "=== ADMIN CHECKS ==="
# Disk Health (SMART)
try {
$disks = Get-PhysicalDisk | Select-Object FriendlyName, HealthStatus, OperationalStatus
$disks | ForEach-Object {
if ($_.HealthStatus -ne "Healthy") {
Write-Log "Disk health alert: $($_.FriendlyName) is $($_.HealthStatus)" -Level "ERROR"
} else {
Write-Log "Disk health: $($_.FriendlyName) is Healthy"
}
}
} catch {
Write-Log "WARNING: Could not retrieve disk health data" -Level "WARNING"
}
Write-Log ""
# BitLocker Status
if (Get-Command -Name Get-BitLockerVolume -ErrorAction SilentlyContinue) {
$bitlocker = Get-BitLockerVolume | Where-Object { $_.VolumeType -eq "OperatingSystem" }
if ($bitlocker.ProtectionStatus -eq "On") {
Write-Log "BitLocker: Enabled ($($bitlocker.EncryptionPercentage)% encrypted)"
} else {
Write-Log "WARNING: BitLocker is not enabled on OS drive" -Level "WARNING"
}
}
Write-Log ""
}
#endregion
#region Common Checks
# ------------------
# 5. Windows Updates
Write-Log "=== UPDATES ==="
$lastUpdate = Get-HotFix | Sort-Object InstalledOn -Descending | Select-Object -First 1
Write-Log "Last Update: $($lastUpdate.HotFixID) on $($lastUpdate.InstalledOn)"
Write-Log ""
# 6. Security Status
Write-Log "=== SECURITY ==="
$defender = Get-MpComputerStatus
if ($defender.AntivirusEnabled) {
Write-Log "Windows Defender: Active"
} else {
Write-Log "ERROR: Windows Defender is disabled" -Level "ERROR"
}
Write-Log ""
# 7. Event Log Errors
Write-Log "=== CRITICAL EVENTS (24h) ==="
$criticalEvents = Get-WinEvent -FilterHashtable @{
LogName = 'System','Application'
Level = 1,2
StartTime = (Get-Date).AddDays(-1)
} -MaxEvents 5 -ErrorAction SilentlyContinue
if ($criticalEvents) {
$criticalEvents | ForEach-Object {
Write-Log "Event $($_.Id) [$($_.ProviderName)]: $($_.Message)" -Level "ERROR"
}
} else {
Write-Log "No critical events found"
}
#endregion
#region Completion
# ---------------
Write-Log ""
Write-Log "=== AUDIT COMPLETE ==="
Write-Log "Mode: $(if ($Full) {'FULL (Admin)'} else {'BASIC (Non-Admin)'})"
Write-Log "Log saved to: $logFile"
# Open log file if running interactively
if ($Host.Name -match "ConsoleHost") {
Invoke-Item $logFile
}
#endregion