1655 lines
68 KiB
PowerShell
1655 lines
68 KiB
PowerShell
<#=================================================================================
|
|
PC Health Check - Remote Edition
|
|
=================================================================================
|
|
.SYNOPSIS
|
|
Performs comprehensive system health checks on local or remote Windows computers.
|
|
|
|
.DESCRIPTION
|
|
This script collects critical system information including disk space, CPU usage,
|
|
memory utilization, network connectivity, services status, event logs, and more.
|
|
Supports both interactive mode and automated command-line execution.
|
|
|
|
For remote computers, the script uses CIM over DCOM (Windows PowerShell 5.1
|
|
compatible) since WinRM is typically disabled on desktops in enterprise
|
|
environments.
|
|
|
|
.PARAMETER ComputerName
|
|
Specifies the target computer(s) to check. Accepts multiple comma-separated
|
|
values. If omitted, checks the local computer.
|
|
|
|
.PARAMETER Credential
|
|
Specifies a user account with permissions to query the remote computer(s).
|
|
Use Get-Credential to enter credentials securely.
|
|
|
|
.PARAMETER LogToFile
|
|
Saves results to a log file in the specified or default LogPath directory.
|
|
|
|
.PARAMETER LogPath
|
|
Specifies the directory where log files and HTML reports are saved.
|
|
Default: Desktop\PCHealthChecks
|
|
|
|
.PARAMETER Silent
|
|
Suppresses console output. Only applicable with -LogToFile or -ExportHTML.
|
|
Use with -LogToFile to run unattended scheduled tasks.
|
|
|
|
.PARAMETER ExportHTML
|
|
Creates an HTML report of the results in addition to log file output.
|
|
|
|
.PARAMETER RunAllChecks
|
|
Runs all checks automatically without user interaction. Use with -ComputerName
|
|
to check multiple remote computers in batch mode.
|
|
|
|
.PARAMETER IncludeNetwork
|
|
Includes network connectivity tests to external hosts (google.com, microsoft.com).
|
|
Disabled by default for remote checks to reduce execution time.
|
|
|
|
.PARAMETER IncludeUpdates
|
|
Checks for pending Windows updates. May require additional permissions.
|
|
|
|
.PARAMETER ThrottleLimit
|
|
Maximum number of concurrent remote connections when checking multiple computers.
|
|
Default: 5
|
|
|
|
.PARAMETER Timeout
|
|
Connection timeout in seconds for remote computers. Default: 30 seconds.
|
|
|
|
.PARAMETER Help
|
|
Displays this help information.
|
|
|
|
.INPUTS
|
|
None. You cannot pipe objects to this script.
|
|
|
|
.OUTPUTS
|
|
Console output and optionally log files and HTML reports.
|
|
|
|
.EXAMPLE
|
|
.\PCHealthCheck.ps1
|
|
Runs interactive health check on the local computer.
|
|
|
|
.EXAMPLE
|
|
.\PCHealthCheck.ps1 -RunAllChecks -LogToFile
|
|
Runs all checks on local computer and saves results to log file.
|
|
|
|
.EXAMPLE
|
|
.\PCHealthCheck.ps1 -ComputerName PC01,PC02,PC03 -RunAllChecks -LogToFile
|
|
Runs all checks on three remote computers and saves results to log file.
|
|
|
|
.EXAMPLE
|
|
.\PCHealthCheck.ps1 -ComputerName PC01 -Credential (Get-Credential) -ExportHTML
|
|
Checks remote computer PC01 with custom credentials and generates HTML report.
|
|
|
|
.EXAMPLE
|
|
.\PCHealthCheck.ps1 -ComputerName PC01 -Silent -LogToFile
|
|
Runs silent health check on remote computer (no console output).
|
|
|
|
.EXAMPLE
|
|
Get-Content computers.txt | ForEach-Object { .\PCHealthCheck.ps1 -ComputerName $_ -RunAllChecks -LogToFile }
|
|
Reads computer names from a text file and checks each one.
|
|
|
|
.NOTES
|
|
Author: Enterprise Admin
|
|
Version: 3.0
|
|
Date: 2026-10-04
|
|
|
|
REQUIREMENTS:
|
|
- PowerShell 5.1 (Windows PowerShell)
|
|
- Administrator or delegated permissions on target computers
|
|
- DCOM enabled (standard on Windows desktops/servers)
|
|
- Firewall ports: RPC (135) and dynamic RPC ports (1024-5000)
|
|
|
|
REMOTE MANAGEMENT NOTES:
|
|
- WinRM is typically disabled on enterprise desktops
|
|
- Uses CIM over DCOM for remote connections
|
|
- For servers with WinRM enabled, consider using Invoke-Command instead
|
|
- Check connectivity first: Test-Connection -ComputerName <name> -Count 1
|
|
|
|
.LINK
|
|
https://learn.microsoft.com/en-us/powershell/
|
|
================================================================================ #>
|
|
|
|
# Command-line parameters
|
|
[CmdletBinding(SupportsShouldProcess=$true)]
|
|
param (
|
|
[Parameter(Mandatory=$false)]
|
|
[string[]]$ComputerName,
|
|
|
|
[Parameter(Mandatory=$false)]
|
|
[pscredential]$Credential,
|
|
|
|
[Parameter(Mandatory=$false)]
|
|
[switch]$LogToFile,
|
|
|
|
[Parameter(Mandatory=$false)]
|
|
[string]$LogPath,
|
|
|
|
[Parameter(Mandatory=$false)]
|
|
[switch]$Silent,
|
|
|
|
[Parameter(Mandatory=$false)]
|
|
[switch]$ExportHTML,
|
|
|
|
[Parameter(Mandatory=$false)]
|
|
[switch]$RunAllChecks,
|
|
|
|
[Parameter(Mandatory=$false)]
|
|
[switch]$IncludeNetwork,
|
|
|
|
[Parameter(Mandatory=$false)]
|
|
[switch]$IncludeUpdates,
|
|
|
|
[Parameter(Mandatory=$false)]
|
|
[int]$ThrottleLimit = 5,
|
|
|
|
[Parameter(Mandatory=$false)]
|
|
[int]$Timeout = 30,
|
|
|
|
[Parameter(Mandatory=$false)]
|
|
[switch]$Help
|
|
)
|
|
|
|
# Show help if requested
|
|
if ($Help) {
|
|
Get-Help $MyInvocation.MyCommand.Path -Detailed
|
|
exit
|
|
}
|
|
|
|
# Define default log file path if not specified
|
|
if (-not $LogPath) {
|
|
$LogPath = "$([Environment]::GetFolderPath('Desktop'))\PCHealthChecks"
|
|
}
|
|
|
|
# Determine if running locally or remotely
|
|
$IsLocal = (-not $ComputerName) -or ($ComputerName -contains $env:COMPUTERNAME)
|
|
|
|
# Create HTML report file name
|
|
$htmlReportFile = "$LogPath\PCHealthCheck_$(Get-Date -Format 'yyyyMMdd_HHmmss').html"
|
|
|
|
# Create log file name (include computer name if remote)
|
|
if ($IsLocal) {
|
|
$logFile = "$LogPath\PCHealthCheck_$(Get-Date -Format 'yyyyMMdd_HHmmss').log"
|
|
} else {
|
|
$logFile = "$LogPath\PCHealthCheck_$(Get-Date -Format 'yyyyMMdd_HHmmss')_$(($ComputerName -join '_')).log"
|
|
}
|
|
|
|
# Initialize HTML report content if export is requested
|
|
$htmlReport = $null
|
|
$currentSection = $null
|
|
if ($ExportHTML) {
|
|
$htmlReport = @"
|
|
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>PC Health Check Report</title>
|
|
<style>
|
|
body {
|
|
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
|
margin: 0;
|
|
padding: 20px;
|
|
background-color: #f0f0f0;
|
|
color: #333;
|
|
}
|
|
.container {
|
|
max-width: 1000px;
|
|
margin: 0 auto;
|
|
background-color: #f8f8f8;
|
|
padding: 20px;
|
|
border-radius: 8px;
|
|
box-shadow: 0 2px 5px rgba(0,0,0,0.1);
|
|
}
|
|
h1 {
|
|
color: #0066cc;
|
|
padding-bottom: 10px;
|
|
border-bottom: 1px solid #ccc;
|
|
}
|
|
h2 {
|
|
color: #0066cc;
|
|
margin-top: 25px;
|
|
font-weight: bold;
|
|
}
|
|
.report-meta {
|
|
background-color: #e8f0f8;
|
|
padding: 10px;
|
|
border-radius: 5px;
|
|
margin-bottom: 20px;
|
|
}
|
|
.section {
|
|
margin-bottom: 30px;
|
|
border-left: 4px solid #0066cc;
|
|
padding-left: 15px;
|
|
}
|
|
.good {
|
|
color: #2e8b57;
|
|
font-weight: bold;
|
|
}
|
|
.warning {
|
|
color: #ff9900;
|
|
font-weight: bold;
|
|
}
|
|
.critical {
|
|
color: #cc3300;
|
|
font-weight: bold;
|
|
}
|
|
table {
|
|
width: 100%;
|
|
border-collapse: collapse;
|
|
margin: 15px 0;
|
|
}
|
|
th, td {
|
|
padding: 8px;
|
|
text-align: left;
|
|
border-bottom: 1px solid #ddd;
|
|
}
|
|
th {
|
|
background-color: #e8f0f8;
|
|
font-weight: bold;
|
|
}
|
|
tr:hover {
|
|
background-color: #f1f1f1;
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div class="container">
|
|
<h1>PC Health Check Report</h1>
|
|
<div class="report-meta">
|
|
<p><strong>System:</strong> $env:COMPUTERNAME</p>
|
|
<p><strong>User:</strong> $env:USERNAME</p>
|
|
<p><strong>Date:</strong> $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')</p>
|
|
</div>
|
|
"@
|
|
}
|
|
|
|
# Define functions first
|
|
function Write-ColorOutput {
|
|
param (
|
|
[Parameter(Mandatory=$true)]
|
|
[string]$Message,
|
|
|
|
[Parameter(Mandatory=$false)]
|
|
[string]$ForegroundColor = "White",
|
|
|
|
[Parameter(Mandatory=$false)]
|
|
[string]$StatusLevel = "Info",
|
|
|
|
[Parameter(Mandatory=$false)]
|
|
[string]$ComputerName = $env:COMPUTERNAME
|
|
)
|
|
|
|
# Only output to console if not in silent mode
|
|
if (-not $Silent) {
|
|
Write-Host $Message -ForegroundColor $ForegroundColor
|
|
}
|
|
|
|
# Log to file if requested
|
|
if ($LogToFile) {
|
|
Add-ToLog $Message $ComputerName
|
|
}
|
|
|
|
# Add to HTML report if requested
|
|
if ($ExportHTML) {
|
|
Add-ToHtmlReport $Message $StatusLevel $ComputerName
|
|
}
|
|
}
|
|
|
|
function Add-ToLog {
|
|
param (
|
|
[Parameter(Mandatory=$true)]
|
|
[string]$Message,
|
|
|
|
[Parameter(Mandatory=$false)]
|
|
[string]$ComputerName = $env:COMPUTERNAME
|
|
)
|
|
|
|
# Ensure log directory exists
|
|
if (-not (Test-Path -Path $LogPath)) {
|
|
New-Item -Path $LogPath -ItemType Directory -Force | Out-Null
|
|
}
|
|
|
|
# Add timestamp and append message to log file
|
|
$timestamp = Get-Date -Format 'yyyy-MM-dd HH:mm:ss'
|
|
"$timestamp [$ComputerName] - $Message" | Out-File -FilePath $logFile -Append
|
|
}
|
|
|
|
function Add-ToHtmlReport {
|
|
param (
|
|
[Parameter(Mandatory=$true)]
|
|
[string]$Message,
|
|
|
|
[Parameter(Mandatory=$false)]
|
|
[string]$StatusLevel = "Info",
|
|
|
|
[Parameter(Mandatory=$false)]
|
|
[string]$ComputerName = $env:COMPUTERNAME
|
|
)
|
|
|
|
# Determine CSS class based on status level
|
|
$cssClass = "info"
|
|
if ($StatusLevel -eq "Warning") { $cssClass = "warning" }
|
|
if ($StatusLevel -eq "Critical") { $cssClass = "critical" }
|
|
if ($StatusLevel -eq "Good") { $cssClass = "good" }
|
|
|
|
# Format content based on caller function
|
|
$callerName = (Get-PSCallStack)[1].Command
|
|
|
|
# Start a new section if this is a function header
|
|
if ($Message -match "^Checking|^Getting|^Testing|^Scanning") {
|
|
$sectionTitle = $Message -replace "\.\.\..*", ""
|
|
$script:htmlReport += "<div class='section'><h2>[$ComputerName] $sectionTitle</h2>"
|
|
$script:currentSection = $callerName
|
|
$script:htmlReport += "<p>$Message</p>"
|
|
}
|
|
elseif ($callerName -ne $script:currentSection -and $callerName -ne "Write-ColorOutput" -and $callerName -ne "Show-Banner") {
|
|
# If we've switched functions, close current section and start new one
|
|
if ($script:currentSection) {
|
|
$script:htmlReport += "</div>"
|
|
}
|
|
$script:htmlReport += "<div class='section'><h2>[$ComputerName] $callerName</h2>"
|
|
$script:currentSection = $callerName
|
|
$script:htmlReport += "<p>$Message</p>"
|
|
}
|
|
else {
|
|
# Regular message within current section
|
|
if ($cssClass -ne "info") {
|
|
$script:htmlReport += "<p class='$cssClass'>[$ComputerName] $Message</p>"
|
|
} else {
|
|
$script:htmlReport += "<p>[$ComputerName] $Message</p>"
|
|
}
|
|
}
|
|
}
|
|
|
|
function Start-HtmlTable {
|
|
param (
|
|
[Parameter(Mandatory=$true)]
|
|
[string[]]$Headers
|
|
)
|
|
|
|
if ($ExportHTML) {
|
|
$headerRow = $Headers | ForEach-Object { "<th>$_</th>" }
|
|
$script:htmlReport += "<table><tr>$headerRow</tr>"
|
|
}
|
|
}
|
|
|
|
function Add-HtmlTableRow {
|
|
param (
|
|
[Parameter(Mandatory=$true)]
|
|
[string[]]$Cells,
|
|
|
|
[Parameter(Mandatory=$false)]
|
|
[string]$StatusLevel = "Info"
|
|
)
|
|
|
|
if ($ExportHTML) {
|
|
$cssClass = "info"
|
|
if ($StatusLevel -eq "Warning") { $cssClass = "warning" }
|
|
if ($StatusLevel -eq "Critical") { $cssClass = "critical" }
|
|
if ($StatusLevel -eq "Good") { $cssClass = "good" }
|
|
|
|
$cellRows = $Cells | ForEach-Object { "<td>$_</td>" }
|
|
$script:htmlReport += "<tr class='$cssClass'>$cellRows</tr>"
|
|
}
|
|
}
|
|
|
|
function End-HtmlTable {
|
|
if ($ExportHTML) {
|
|
$script:htmlReport += "</table>"
|
|
}
|
|
}
|
|
|
|
function Save-HtmlReport {
|
|
param (
|
|
[Parameter(Mandatory=$false)]
|
|
[string]$ComputerName = $env:COMPUTERNAME
|
|
)
|
|
|
|
if ($ExportHTML) {
|
|
# Close any open section
|
|
if ($script:currentSection) {
|
|
$script:htmlReport += "</div>"
|
|
}
|
|
|
|
# Add footer and close HTML
|
|
$script:htmlReport += @"
|
|
<div class="section">
|
|
<h2>Report Summary</h2>
|
|
<p>PC Health Check completed on $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')</p>
|
|
<p>Target Computer: $ComputerName</p>
|
|
</div>
|
|
</div>
|
|
</body>
|
|
</html>
|
|
"@
|
|
|
|
# Ensure directory exists
|
|
if (-not (Test-Path -Path $LogPath)) {
|
|
New-Item -Path $LogPath -ItemType Directory -Force | Out-Null
|
|
}
|
|
|
|
# Save HTML to file
|
|
$script:htmlReport | Out-File -FilePath $htmlReportFile -Encoding utf8
|
|
|
|
# Return the file path for display
|
|
return $htmlReportFile
|
|
}
|
|
|
|
return $null
|
|
}
|
|
|
|
function Show-Banner {
|
|
param (
|
|
[Parameter(Mandatory=$false)]
|
|
[string]$ComputerName = $env:COMPUTERNAME
|
|
)
|
|
|
|
if (-not $Silent) {
|
|
Clear-Host
|
|
Write-Host "=======================================" -ForegroundColor Cyan
|
|
Write-Host " ENHANCED PC HEALTH CHECK " -ForegroundColor Cyan
|
|
Write-Host "=======================================" -ForegroundColor Cyan
|
|
Write-Host "System: $ComputerName" -ForegroundColor Cyan
|
|
Write-Host "User: $env:USERNAME" -ForegroundColor Cyan
|
|
Write-Host "Date: $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')" -ForegroundColor Cyan
|
|
if ($LogToFile) {
|
|
Write-Host "Log File: $logFile" -ForegroundColor Cyan
|
|
}
|
|
if ($ExportHTML) {
|
|
Write-Host "HTML Report: $htmlReportFile" -ForegroundColor Cyan
|
|
}
|
|
Write-Host "=======================================" -ForegroundColor Cyan
|
|
}
|
|
}
|
|
|
|
function Show-Menu {
|
|
if (-not $Silent) {
|
|
Write-Host "`nSelect an option:" -ForegroundColor Yellow
|
|
Write-Host "1. Check Disk Space" -ForegroundColor White
|
|
Write-Host "2. Check CPU Usage" -ForegroundColor White
|
|
Write-Host "3. Check Memory Usage" -ForegroundColor White
|
|
Write-Host "4. Test Network Connectivity" -ForegroundColor White
|
|
Write-Host "5. Check for Port Exhaustion" -ForegroundColor White
|
|
Write-Host "6. Check System Uptime" -ForegroundColor White
|
|
Write-Host "7. List Top Processes by Memory" -ForegroundColor White
|
|
Write-Host "8. List Top Processes by CPU" -ForegroundColor White
|
|
Write-Host "9. Check Windows Services Status" -ForegroundColor White
|
|
Write-Host "10. Scan Windows Event Logs" -ForegroundColor White
|
|
Write-Host "11. Check Windows Update Status" -ForegroundColor White
|
|
Write-Host "13. Check Pending Reboot Status" -ForegroundColor White
|
|
Write-Host "14. Check Network Adapters" -ForegroundColor White
|
|
Write-Host "12. Run All Checks" -ForegroundColor Green
|
|
Write-Host "E. Export HTML Report" -ForegroundColor Cyan
|
|
Write-Host "H. Help" -ForegroundColor Cyan
|
|
Write-Host "L. View Log Files" -ForegroundColor Cyan
|
|
Write-Host "Q. Quit" -ForegroundColor Red
|
|
}
|
|
}
|
|
|
|
function Get-CimSessionForComputer {
|
|
param (
|
|
[Parameter(Mandatory=$true)]
|
|
[string]$ComputerName,
|
|
|
|
[Parameter(Mandatory=$false)]
|
|
[pscredential]$Credential
|
|
)
|
|
|
|
# Try to create CIM session with auto-detection of protocol
|
|
$sessionOptions = New-CimSessionOption -Protocol Wsman
|
|
$cimSession = $null
|
|
|
|
try {
|
|
# Try WinRM first
|
|
$cimSession = New-CimSession -ComputerName $ComputerName -SessionOption $sessionOptions -Credential $Credential -ErrorAction Stop
|
|
return $cimSession
|
|
}
|
|
catch {
|
|
# WinRM failed, try DCOM
|
|
$sessionOptions = New-CimSessionOption -Protocol Dcom
|
|
try {
|
|
$cimSession = New-CimSession -ComputerName $ComputerName -SessionOption $sessionOptions -Credential $Credential -ErrorAction Stop
|
|
return $cimSession
|
|
}
|
|
catch {
|
|
Write-ColorOutput "Failed to connect to ${ComputerName}: $_" "Red" "Critical" $ComputerName
|
|
return $null
|
|
}
|
|
}
|
|
}
|
|
|
|
function Get-DiskSpace {
|
|
param (
|
|
[Parameter(Mandatory=$false)]
|
|
[string]$ComputerName = $env:COMPUTERNAME,
|
|
|
|
[Parameter(Mandatory=$false)]
|
|
[Microsoft.Management.Infrastructure.CimSession]$CimSession = $null
|
|
)
|
|
|
|
Write-ColorOutput "`nChecking Disk Space..." "Yellow" $ComputerName
|
|
|
|
try {
|
|
if (-not $CimSession -and $ComputerName -eq $env:COMPUTERNAME) {
|
|
$disks = Get-PSDrive -PSProvider FileSystem |
|
|
Select-Object Name, @{Name="FreeSpace(GB)";Expression={[math]::Round($_.Free/1GB, 2)}},
|
|
@{Name="TotalSpace(GB)";Expression={[math]::Round(($_.Used/1GB + $_.Free/1GB), 2)}},
|
|
@{Name="PercentFree";Expression={[math]::Round(($_.Free/($_.Used + $_.Free))*100, 2)}}
|
|
} else {
|
|
$disks = Get-CimInstance -ClassName Win32_LogicalDisk -Filter "DriveType=3" -CimSession $CimSession |
|
|
Select-Object DeviceID, @{Name="FreeSpace(GB)";Expression={[math]::Round($_.FreeSpace/1GB, 2)}},
|
|
@{Name="TotalSpace(GB)";Expression={[math]::Round(($_.FreeSpace/1GB + $_.Size/1GB), 2)}},
|
|
@{Name="PercentFree";Expression={[math]::Round(($_.FreeSpace/($_.FreeSpace + $_.Size))*100, 2)}}
|
|
}
|
|
|
|
if ($ExportHTML) {
|
|
Start-HtmlTable @("Drive", "Free Space (GB)", "Total Space (GB)", "Percent Free")
|
|
}
|
|
|
|
foreach ($disk in $disks) {
|
|
$color = "Green"
|
|
$status = "Good"
|
|
if ($disk."PercentFree" -lt 20) { $color = "Yellow"; $status = "Warning" }
|
|
if ($disk."PercentFree" -lt 10) { $color = "Red"; $status = "Critical" }
|
|
|
|
Write-ColorOutput "Drive $($disk.Name): $($disk.'FreeSpace(GB)') GB free of $($disk.'TotalSpace(GB)') GB ($($disk.PercentFree)% free)" $color $status $ComputerName
|
|
|
|
if ($ExportHTML) {
|
|
Add-HtmlTableRow @($disk.Name, $disk.'FreeSpace(GB)', $disk.'TotalSpace(GB)', "$($disk.PercentFree)%") $status
|
|
}
|
|
}
|
|
|
|
if ($ExportHTML) {
|
|
End-HtmlTable
|
|
}
|
|
}
|
|
catch {
|
|
Write-ColorOutput "Error checking disk space on ${ComputerName}: $_" "Red" "Critical" $ComputerName
|
|
}
|
|
}
|
|
|
|
function Get-CPUUsage {
|
|
param (
|
|
[Parameter(Mandatory=$false)]
|
|
[string]$ComputerName = $env:COMPUTERNAME,
|
|
|
|
[Parameter(Mandatory=$false)]
|
|
[Microsoft.Management.Infrastructure.CimSession]$CimSession = $null
|
|
)
|
|
|
|
Write-ColorOutput "`nChecking CPU Usage..." "Yellow" $ComputerName
|
|
|
|
try {
|
|
Write-ColorOutput "Taking 5 CPU utilization samples..." "Gray" $ComputerName
|
|
$samples = @()
|
|
|
|
if ($ExportHTML) {
|
|
Start-HtmlTable @("Sample", "CPU Usage (%)")
|
|
}
|
|
|
|
for ($i = 1; $i -le 5; $i++) {
|
|
if (-not $CimSession -and $ComputerName -eq $env:COMPUTERNAME) {
|
|
$counterData = Get-Counter -Counter "\Processor(_Total)\% Processor Time" -ErrorAction Stop
|
|
$cpuValue = [math]::Round($counterData.CounterSamples[0].CookedValue, 2)
|
|
} else {
|
|
$counterData = Get-CimInstance -ClassName Win32_PerfRawData_PerfOS_Processor -CimSession $CimSession -Filter "Name='_Total'"
|
|
$cpuValue = [math]::Round($counterData.PercentProcessorTime, 2)
|
|
}
|
|
|
|
$samples += $cpuValue
|
|
|
|
Write-ColorOutput " Sample $i of 5: $cpuValue%" "Gray" $ComputerName
|
|
|
|
if ($ExportHTML) {
|
|
Add-HtmlTableRow @("Sample $i", "$cpuValue%")
|
|
}
|
|
|
|
Start-Sleep -Seconds 1
|
|
}
|
|
|
|
if ($ExportHTML) {
|
|
End-HtmlTable
|
|
}
|
|
|
|
# Calculate average CPU usage
|
|
$avgCpu = ($samples | Measure-Object -Average).Average
|
|
$avgCpu = [math]::Round($avgCpu, 2)
|
|
|
|
# Calculate min and max values
|
|
$minCpu = ($samples | Measure-Object -Minimum).Minimum
|
|
$maxCpu = ($samples | Measure-Object -Maximum).Maximum
|
|
|
|
# Set color based on average CPU usage
|
|
$color = "Green"
|
|
$status = "Good"
|
|
if ($avgCpu -gt 70) { $color = "Yellow"; $status = "Warning" }
|
|
if ($avgCpu -gt 90) { $color = "Red"; $status = "Critical" }
|
|
|
|
Write-ColorOutput "`nCPU Usage Results:" "White" $ComputerName
|
|
Write-ColorOutput " Average: $avgCpu%" $color $status $ComputerName
|
|
Write-ColorOutput " Minimum: $minCpu%" "Gray" $ComputerName
|
|
Write-ColorOutput " Maximum: $maxCpu%" "Gray" $ComputerName
|
|
|
|
$processCount = (Get-Process).Count
|
|
Write-ColorOutput " Total Processes: $processCount" "White" $ComputerName
|
|
|
|
# Get top processes by CPU
|
|
Write-ColorOutput "`nTop Processes by CPU Usage:" "White" $ComputerName
|
|
|
|
if (-not $CimSession -and $ComputerName -eq $env:COMPUTERNAME) {
|
|
$numProcs = [Environment]::ProcessorCount
|
|
$processes = Get-CimInstance Win32_PerfFormattedData_PerfProc_Process |
|
|
Where-Object { $_.Name -notmatch '_Total|Idle' } |
|
|
Select-Object IDProcess,
|
|
@{Name='ProcessName';Expression={$_.Name -replace '#\d+$', ''}},
|
|
@{Name='PID';Expression={$_.IDProcess}},
|
|
@{Name='CPU_Percent';Expression={[math]::Round($_.PercentProcessorTime / $numProcs, 2)}} |
|
|
Sort-Object -Property CPU_Percent -Descending |
|
|
Select-Object -First 10
|
|
} else {
|
|
$numProcs = (Get-CimInstance Win32_ComputerSystem -CimSession $CimSession).NumberOfLogicalProcessors
|
|
$processes = Get-CimInstance Win32_PerfFormattedData_PerfProc_Process -CimSession $CimSession |
|
|
Where-Object { $_.Name -notmatch '_Total|Idle' } |
|
|
Select-Object IDProcess,
|
|
@{Name='ProcessName';Expression={$_.Name -replace '#\d+$', ''}},
|
|
@{Name='PID';Expression={$_.IDProcess}},
|
|
@{Name='CPU_Percent';Expression={[math]::Round($_.PercentProcessorTime / $numProcs, 2)}} |
|
|
Sort-Object -Property CPU_Percent -Descending |
|
|
Select-Object -First 10
|
|
}
|
|
|
|
$processes | Format-Table -AutoSize | Out-String | ForEach-Object { Write-ColorOutput $_ "White" "Info" $ComputerName }
|
|
|
|
if ($ExportHTML) {
|
|
Start-HtmlTable @("ProcessName", "PID", "CPU_Percent")
|
|
foreach ($proc in $processes) {
|
|
Add-HtmlTableRow @($proc.ProcessName, $proc.PID, "$($proc.CPU_Percent)%") "Info"
|
|
}
|
|
End-HtmlTable
|
|
}
|
|
|
|
if ($ExportHTML) {
|
|
Start-HtmlTable @("Measurement", "Value", "Status")
|
|
$cpuStatus = "Good"
|
|
if ($avgCpu -gt 90) { $cpuStatus = "Critical" }
|
|
elseif ($avgCpu -gt 70) { $cpuStatus = "Warning" }
|
|
Add-HtmlTableRow @("Average CPU Usage", "$avgCpu%", $cpuStatus) $status
|
|
Add-HtmlTableRow @("Minimum CPU Usage", "$minCpu%", "Info")
|
|
Add-HtmlTableRow @("Maximum CPU Usage", "$maxCpu%", "Info")
|
|
End-HtmlTable
|
|
}
|
|
}
|
|
catch {
|
|
Write-ColorOutput "Error checking CPU usage on ${ComputerName}: $_" "Red" "Critical" $ComputerName
|
|
}
|
|
}
|
|
|
|
function Get-MemoryUsage {
|
|
param (
|
|
[Parameter(Mandatory=$false)]
|
|
[string]$ComputerName = $env:COMPUTERNAME,
|
|
|
|
[Parameter(Mandatory=$false)]
|
|
[Microsoft.Management.Infrastructure.CimSession]$CimSession = $null
|
|
)
|
|
|
|
Write-ColorOutput "`nChecking Memory Usage..." "Yellow" $ComputerName
|
|
|
|
try {
|
|
if (-not $CimSession -and $ComputerName -eq $env:COMPUTERNAME) {
|
|
$os = Get-CimInstance -ClassName Win32_OperatingSystem -ErrorAction Stop
|
|
} else {
|
|
$os = Get-CimInstance -ClassName Win32_OperatingSystem -CimSession $CimSession -ErrorAction Stop
|
|
}
|
|
|
|
$totalMemoryGB = [math]::Round($os.TotalVisibleMemorySize / 1MB, 2)
|
|
$freeMemoryGB = [math]::Round($os.FreePhysicalMemory / 1MB, 2)
|
|
$usedMemoryGB = [math]::Round($totalMemoryGB - $freeMemoryGB, 2)
|
|
$percentUsed = [math]::Round(($usedMemoryGB / $totalMemoryGB) * 100, 2)
|
|
|
|
$color = "Green"
|
|
$status = "Good"
|
|
if ($percentUsed -gt 70) { $color = "Yellow"; $status = "Warning" }
|
|
if ($percentUsed -gt 90) { $color = "Red"; $status = "Critical" }
|
|
|
|
Write-ColorOutput "Total Memory: $totalMemoryGB GB" "White" $ComputerName
|
|
Write-ColorOutput "Used Memory: $usedMemoryGB GB ($percentUsed%)" $color $status $ComputerName
|
|
Write-ColorOutput "Free Memory: $freeMemoryGB GB" "White" $ComputerName
|
|
|
|
$pageFileUsage = Get-CimInstance -ClassName Win32_PageFileUsage | Select-Object -First 1
|
|
if ($pageFileUsage) {
|
|
$pageFileTotal = $pageFileUsage.AllocatedBaseSize
|
|
$pageFileUsed = $pageFileUsage.CurrentUsage
|
|
$pageFilePercent = if ($pageFileTotal -gt 0) { [math]::Round(($pageFileUsed / $pageFileTotal) * 100, 2) } else { 0 }
|
|
$pageFileColor = "Green"
|
|
$pageFileStatus = "Good"
|
|
if ($pageFilePercent -gt 70) { $pageFileColor = "Yellow"; $pageFileStatus = "Warning" }
|
|
if ($pageFilePercent -gt 90) { $pageFileColor = "Red"; $pageFileStatus = "Critical" }
|
|
Write-ColorOutput "Page File Usage: $pageFileUsed MB / $pageFileTotal MB ($pageFilePercent%)" $pageFileColor $pageFileStatus $ComputerName
|
|
}
|
|
|
|
# Get top processes by memory with percentage
|
|
Write-ColorOutput "`nTop Processes by Memory Usage:" "White" $ComputerName
|
|
|
|
if (-not $CimSession -and $ComputerName -eq $env:COMPUTERNAME) {
|
|
$processes = Get-Process |
|
|
Sort-Object -Property WorkingSet -Descending |
|
|
Select-Object -First 10 -Property ProcessName, Id, @{Name="Memory(MB)";Expression={[math]::Round($_.WorkingSet / 1MB, 2)}},
|
|
@{Name="Memory(%)";Expression={[math]::Round(($_.WorkingSet / ($os.TotalVisibleMemorySize * 1KB)) * 100, 2)}}
|
|
} else {
|
|
$totalMemBytes = $os.TotalVisibleMemorySize * 1KB
|
|
$processes = Get-CimInstance -ClassName Win32_Process -CimSession $CimSession |
|
|
Sort-Object -Property WorkingSet -Descending |
|
|
Select-Object -First 10 -Property Name, ProcessId, @{Name="Memory(MB)";Expression={[math]::Round($_.WorkingSetSize / 1MB, 2)}},
|
|
@{Name="Memory(%)";Expression={[math]::Round(($_.WorkingSetSize / $totalMemBytes) * 100, 2)}}
|
|
}
|
|
|
|
$processes | Format-Table -AutoSize | Out-String | ForEach-Object { Write-ColorOutput $_ "White" "Info" $ComputerName }
|
|
|
|
if ($ExportHTML) {
|
|
Start-HtmlTable @("ProcessName", "Id", "Memory(MB)", "Memory(%)")
|
|
foreach ($proc in $processes) {
|
|
Add-HtmlTableRow @($proc.ProcessName, $proc.Id, $proc.'Memory(MB)', "$($proc.'Memory(%)')%") "Info"
|
|
}
|
|
End-HtmlTable
|
|
}
|
|
|
|
if ($ExportHTML) {
|
|
Start-HtmlTable @("Measurement", "Value", "Status")
|
|
$memStatus = "Good"
|
|
if ($percentUsed -gt 90) { $memStatus = "Critical" }
|
|
elseif ($percentUsed -gt 70) { $memStatus = "Warning" }
|
|
Add-HtmlTableRow @("Total Memory", "$totalMemoryGB GB", "Info")
|
|
Add-HtmlTableRow @("Used Memory", "$usedMemoryGB GB ($percentUsed%)", $memStatus) $status
|
|
Add-HtmlTableRow @("Free Memory", "$freeMemoryGB GB", "Info")
|
|
if ($pageFileUsage) {
|
|
Add-HtmlTableRow @("Page File Usage", "$pageFileUsed MB / $pageFileTotal MB ($pageFilePercent%)", $pageFileStatus) $pageFileStatus
|
|
}
|
|
End-HtmlTable
|
|
|
|
# Add a simple memory usage visualization
|
|
$barColor = "#2e8b57"
|
|
if ($percentUsed -gt 70) { $barColor = "#ff9900" }
|
|
if ($percentUsed -gt 90) { $barColor = "#cc3300" }
|
|
|
|
$script:htmlReport += @"
|
|
<div style="margin-top: 15px; margin-bottom: 15px;">
|
|
<div style="background-color: #f0f0f0; border-radius: 5px; height: 30px; width: 100%; overflow: hidden;">
|
|
<div style="background-color: $barColor; height: 100%; width: $percentUsed%; text-align: center; color: white; line-height: 30px;">
|
|
$percentUsed%
|
|
</div>
|
|
</div>
|
|
<div style="font-size: 12px; text-align: center; margin-top: 5px;">Memory Usage</div>
|
|
</div>
|
|
"@
|
|
}
|
|
}
|
|
catch {
|
|
Write-ColorOutput "Error checking memory usage on ${ComputerName}: $_" "Red" "Critical" $ComputerName
|
|
}
|
|
}
|
|
|
|
function Test-NetworkConnectivity {
|
|
param (
|
|
[Parameter(Mandatory=$false)]
|
|
[string]$ComputerName = $env:COMPUTERNAME,
|
|
|
|
[Parameter(Mandatory=$false)]
|
|
[Microsoft.Management.Infrastructure.CimSession]$CimSession = $null
|
|
)
|
|
|
|
Write-ColorOutput "`nTesting Network Connectivity..." "Yellow" $ComputerName
|
|
|
|
$allPassed = $true
|
|
|
|
try {
|
|
if (-not $CimSession -and $ComputerName -eq $env:COMPUTERNAME) {
|
|
$networkAdapters = Get-CimInstance -ClassName Win32_NetworkAdapterConfiguration -Filter "IPEnabled=True" -ErrorAction Stop
|
|
} else {
|
|
$networkAdapters = Get-CimInstance -ClassName Win32_NetworkAdapterConfiguration -Filter "IPEnabled=True" -CimSession $CimSession -ErrorAction Stop
|
|
}
|
|
|
|
if ($networkAdapters) {
|
|
$gateway = $networkAdapters | ForEach-Object { $_.DefaultIPGateway } | Where-Object { $_ -ne $null } | Select-Object -First 1
|
|
$dnsServers = $networkAdapters | ForEach-Object { $_.DNSServerSearchOrder } | Where-Object { $_ -ne $null } | Select-Object -First 2
|
|
|
|
if ($gateway) {
|
|
Write-ColorOutput "Testing Gateway connectivity..." "White" $ComputerName
|
|
try {
|
|
$ping = Test-Connection -ComputerName $gateway -Count 2 -ErrorAction Stop
|
|
$avgTime = [math]::Round(($ping | Measure-Object -Property ResponseTime -Average).Average, 2)
|
|
Write-ColorOutput " Gateway - PASS" "Green" $ComputerName
|
|
Write-ColorOutput " Gateway IP: $gateway" "White" $ComputerName
|
|
Write-ColorOutput " Avg Response: $avgTime ms" "Gray" $ComputerName
|
|
}
|
|
catch {
|
|
Write-ColorOutput " Gateway - FAIL" "Red" $ComputerName
|
|
Write-ColorOutput " Gateway IP: $gateway" "White" $ComputerName
|
|
Write-ColorOutput " Error: $_" "Red" $ComputerName
|
|
$allPassed = $false
|
|
}
|
|
} else {
|
|
Write-ColorOutput " Gateway - FAIL" "Red" $ComputerName
|
|
Write-ColorOutput " No gateway configured" "Red" $ComputerName
|
|
$allPassed = $false
|
|
}
|
|
|
|
if ($dnsServers) {
|
|
Write-ColorOutput "`nTesting DNS servers..." "White" $ComputerName
|
|
foreach ($dns in $dnsServers) {
|
|
try {
|
|
$ping = Test-Connection -ComputerName $dns -Count 2 -ErrorAction Stop
|
|
$avgTime = [math]::Round(($ping | Measure-Object -Property ResponseTime -Average).Average, 2)
|
|
Write-ColorOutput " DNS - PASS" "Green" $ComputerName
|
|
Write-ColorOutput " DNS IP: $dns" "White" $ComputerName
|
|
Write-ColorOutput " Avg Response: $avgTime ms" "Gray" $ComputerName
|
|
}
|
|
catch {
|
|
Write-ColorOutput " DNS - FAIL" "Red" $ComputerName
|
|
Write-ColorOutput " DNS IP: $dns" "White" $ComputerName
|
|
Write-ColorOutput " Error: $_" "Red" $ComputerName
|
|
$allPassed = $false
|
|
}
|
|
}
|
|
} else {
|
|
Write-ColorOutput " DNS - FAIL" "Red" $ComputerName
|
|
Write-ColorOutput " No DNS servers configured" "Red" $ComputerName
|
|
$allPassed = $false
|
|
}
|
|
|
|
Write-ColorOutput "`nTesting external connectivity (8.8.8.8)..." "White" $ComputerName
|
|
try {
|
|
$ping = Test-Connection -ComputerName "8.8.8.8" -Count 2 -ErrorAction Stop
|
|
$avgTime = [math]::Round(($ping | Measure-Object -Property ResponseTime -Average).Average, 2)
|
|
Write-ColorOutput " External - PASS" "Green" $ComputerName
|
|
Write-ColorOutput " Target: 8.8.8.8" "White" $ComputerName
|
|
Write-ColorOutput " Avg Response: $avgTime ms" "Gray" $ComputerName
|
|
}
|
|
catch {
|
|
Write-ColorOutput " External - FAIL" "Red" $ComputerName
|
|
Write-ColorOutput " Target: 8.8.8.8" "White" $ComputerName
|
|
Write-ColorOutput " Error: $_" "Red" $ComputerName
|
|
$allPassed = $false
|
|
}
|
|
} else {
|
|
Write-ColorOutput " Network connectivity - FAIL" "Red" $ComputerName
|
|
Write-ColorOutput " No IP-enabled network adapters found" "Red" $ComputerName
|
|
$allPassed = $false
|
|
}
|
|
}
|
|
catch {
|
|
Write-ColorOutput " Network connectivity - FAIL" "Red" $ComputerName
|
|
Write-ColorOutput " Error: $_" "Red" $ComputerName
|
|
$allPassed = $false
|
|
}
|
|
|
|
if ($allPassed) {
|
|
Write-ColorOutput "`nNetwork connectivity test: SUCCESS" "Green" $ComputerName
|
|
} else {
|
|
Write-ColorOutput "`nNetwork connectivity test: FAILED" "Red" $ComputerName
|
|
}
|
|
}
|
|
|
|
function Test-PortExhaustion {
|
|
param (
|
|
[Parameter(Mandatory=$false)]
|
|
[string]$ComputerName = $env:COMPUTERNAME,
|
|
|
|
[Parameter(Mandatory=$false)]
|
|
[Microsoft.Management.Infrastructure.CimSession]$CimSession = $null
|
|
)
|
|
|
|
Write-ColorOutput "`nChecking for Port Exhaustion..." "Yellow" $ComputerName
|
|
|
|
try {
|
|
if (-not $CimSession -and $ComputerName -eq $env:COMPUTERNAME) {
|
|
$netstatOutput = netstat -ano | Out-String
|
|
$maxUserPorts = (Get-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters" -Name "MaxUserPort" -ErrorAction SilentlyContinue).MaxUserPort
|
|
if (-not $maxUserPorts) { $maxUserPorts = 16383 }
|
|
} else {
|
|
# Get MaxUserPort from registry via CIM
|
|
$regKey = "SYSTEM\CurrentControlSet\Services\Tcpip\Parameters"
|
|
$maxUserPorts = (Get-CimInstance -ClassName StdRegProv -Namespace "root\cimv2" -CimSession $CimSession -ErrorAction SilentlyContinue).GetDWordValue(2147483650, $regKey, "MaxUserPort").uValue
|
|
if (-not $maxUserPorts) { $maxUserPorts = 16383 }
|
|
|
|
# Get TCP connections via CIM
|
|
$tcpConnections = Get-CimInstance -ClassName MSFT_NetTCPConnection -Namespace "root\standardcimv2" -CimSession $CimSession -ErrorAction SilentlyContinue
|
|
$netstatOutput = $tcpConnections | Format-Table -AutoSize | Out-String
|
|
}
|
|
|
|
$connections = $netstatOutput -split "`r`n" | Where-Object { $_ -match "TCP" }
|
|
|
|
$totalConnections = @($connections).Count
|
|
$ephemeralStates = @("ESTABLISHED", "TIME_WAIT", "CLOSE_WAIT")
|
|
$ephemeralConnections = @($connections | Where-Object {
|
|
$parts = $_.Trim() -split "\s+"
|
|
if ($parts.Count -ge 4) {
|
|
$parts[3] -in $ephemeralStates
|
|
} else {
|
|
$false
|
|
}
|
|
})
|
|
$ephemeralCount = $ephemeralConnections.Count
|
|
|
|
$establishedCount = @($ephemeralConnections | Where-Object { $_ -match 'ESTABLISHED' }).Count
|
|
$timeWaitCount = @($ephemeralConnections | Where-Object { $_ -match 'TIME_WAIT' }).Count
|
|
$closeWaitCount = @($ephemeralConnections | Where-Object { $_ -match 'CLOSE_WAIT' }).Count
|
|
|
|
$portUsagePercent = [math]::Round(($ephemeralCount / $maxUserPorts) * 100, 2)
|
|
|
|
$color = "Green"
|
|
$status = "PASS"
|
|
if ($ephemeralCount -gt 5000) { $color = "Red"; $status = "FAIL" }
|
|
elseif ($ephemeralCount -ge 2500) { $color = "Yellow"; $status = "WARNING" }
|
|
|
|
Write-ColorOutput "TCP connections: $totalConnections" "White" $ComputerName
|
|
Write-ColorOutput "Ephemeral port connections: $ephemeralCount" $color $status $ComputerName
|
|
Write-ColorOutput " ESTABLISHED: $establishedCount" "White" $ComputerName
|
|
Write-ColorOutput " TIME_WAIT: $timeWaitCount" "White" $ComputerName
|
|
Write-ColorOutput " CLOSE_WAIT: $closeWaitCount" "White" $ComputerName
|
|
Write-ColorOutput "Max User Ports: $maxUserPorts" "White" $ComputerName
|
|
Write-ColorOutput "Port Exhaustion: $status" $color $ComputerName
|
|
|
|
if ($status -eq "FAIL") {
|
|
Write-ColorOutput "WARNING: High number of ephemeral connections detected. Port exhaustion may occur!" "Red" $ComputerName
|
|
} elseif ($status -eq "WARNING") {
|
|
Write-ColorOutput "WARNING: Ephemeral connection count approaching threshold. Monitor closely." "Yellow" $ComputerName
|
|
}
|
|
}
|
|
catch {
|
|
Write-ColorOutput "Error checking port exhaustion on ${ComputerName}: $_" "Red" $ComputerName
|
|
}
|
|
}
|
|
|
|
function Get-SystemUptime {
|
|
param (
|
|
[Parameter(Mandatory=$false)]
|
|
[string]$ComputerName = $env:COMPUTERNAME,
|
|
|
|
[Parameter(Mandatory=$false)]
|
|
[Microsoft.Management.Infrastructure.CimSession]$CimSession = $null
|
|
)
|
|
|
|
Write-ColorOutput "`nChecking System Uptime..." "Yellow" $ComputerName
|
|
|
|
try {
|
|
$bootUpTime = if (-not $CimSession -and $ComputerName -eq $env:COMPUTERNAME) {
|
|
(Get-CimInstance -ClassName Win32_OperatingSystem -ErrorAction Stop).LastBootUpTime
|
|
} else {
|
|
(Get-CimInstance -ClassName Win32_OperatingSystem -CimSession $CimSession -ErrorAction Stop).LastBootUpTime
|
|
}
|
|
|
|
# Handle both DateTime (from CIM) and string (from legacy WMI) types
|
|
if ($bootUpTime -is [DateTime]) {
|
|
$lastBootTime = $bootUpTime
|
|
} else {
|
|
# Parse WMI datetime format (yyyyMMddHHmmss.mmmmmm+UUU)
|
|
$year = [int]$bootUpTime.Substring(0, 4)
|
|
$month = [int]$bootUpTime.Substring(4, 2)
|
|
$day = [int]$bootUpTime.Substring(6, 2)
|
|
$hour = [int]$bootUpTime.Substring(8, 2)
|
|
$minute = [int]$bootUpTime.Substring(10, 2)
|
|
$second = [int]$bootUpTime.Substring(12, 2)
|
|
$lastBootTime = New-Object DateTime($year, $month, $day, $hour, $minute, $second)
|
|
}
|
|
|
|
$uptime = (Get-Date) - $lastBootTime
|
|
|
|
$formattedUptime = "{0} days, {1} hours, {2} minutes, {3} seconds" -f `
|
|
$uptime.Days, $uptime.Hours, $uptime.Minutes, $uptime.Seconds
|
|
|
|
Write-ColorOutput "System Last Boot: $($lastBootTime.ToString('yyyy-MM-dd HH:mm:ss'))" "White" $ComputerName
|
|
Write-ColorOutput "System Uptime: $formattedUptime" "White" $ComputerName
|
|
}
|
|
catch {
|
|
Write-ColorOutput "Error checking system uptime on ${ComputerName}: $_" "Red" $ComputerName
|
|
}
|
|
}
|
|
|
|
function Get-TopProcessesByMemory {
|
|
param (
|
|
[Parameter(Mandatory=$false)]
|
|
[string]$ComputerName = $env:COMPUTERNAME,
|
|
|
|
[Parameter(Mandatory=$false)]
|
|
[Microsoft.Management.Infrastructure.CimSession]$CimSession = $null
|
|
)
|
|
|
|
Write-ColorOutput "`nGetting Top Processes by Memory Usage..." "Yellow" $ComputerName
|
|
|
|
try {
|
|
if (-not $CimSession -and $ComputerName -eq $env:COMPUTERNAME) {
|
|
$os = Get-CimInstance -ClassName Win32_OperatingSystem -ErrorAction Stop
|
|
$totalMemBytes = $os.TotalVisibleMemorySize * 1KB
|
|
$processes = Get-Process |
|
|
Sort-Object -Property WorkingSet -Descending |
|
|
Select-Object -First 10 -Property ProcessName, Id,
|
|
@{Name="Memory(MB)";Expression={[math]::Round($_.WorkingSet / 1MB, 2)}},
|
|
@{Name="Memory(%)";Expression={[math]::Round(($_.WorkingSet / $totalMemBytes) * 100, 2)}}
|
|
} else {
|
|
$os = Get-CimInstance -ClassName Win32_OperatingSystem -CimSession $CimSession -ErrorAction Stop
|
|
$totalMemBytes = $os.TotalVisibleMemorySize * 1KB
|
|
$processes = Get-CimInstance -ClassName Win32_Process -CimSession $CimSession |
|
|
Sort-Object -Property WorkingSet -Descending |
|
|
Select-Object -First 10 -Property Name, ProcessId,
|
|
@{Name="Memory(MB)";Expression={[math]::Round($_.WorkingSetSize / 1MB, 2)}},
|
|
@{Name="Memory(%)";Expression={[math]::Round(($_.WorkingSetSize / $totalMemBytes) * 100, 2)}}
|
|
}
|
|
|
|
$processes | Format-Table -AutoSize | Out-String | ForEach-Object { Write-ColorOutput $_ "White" "Info" $ComputerName }
|
|
}
|
|
catch {
|
|
Write-ColorOutput "Error getting top memory processes on ${ComputerName}: $_" "Red" $ComputerName
|
|
}
|
|
}
|
|
|
|
function Get-TopProcessesByCPU {
|
|
param (
|
|
[Parameter(Mandatory=$false)]
|
|
[string]$ComputerName = $env:COMPUTERNAME,
|
|
|
|
[Parameter(Mandatory=$false)]
|
|
[Microsoft.Management.Infrastructure.CimSession]$CimSession = $null
|
|
)
|
|
|
|
Write-ColorOutput "`nGetting Top Processes by CPU Usage..." "Yellow" $ComputerName
|
|
|
|
try {
|
|
if (-not $CimSession -and $ComputerName -eq $env:COMPUTERNAME) {
|
|
$numProcs = [Environment]::ProcessorCount
|
|
$processes = Get-CimInstance Win32_PerfFormattedData_PerfProc_Process |
|
|
Where-Object { $_.Name -notmatch '_Total|Idle' } |
|
|
Select-Object IDProcess,
|
|
@{Name='ProcessName';Expression={$_.Name -replace '#\d+$', ''}},
|
|
@{Name='PID';Expression={$_.IDProcess}},
|
|
@{Name='CPU_Percent';Expression={[math]::Round($_.PercentProcessorTime / $numProcs, 2)}} |
|
|
Sort-Object -Property CPU_Percent -Descending |
|
|
Select-Object -First 10
|
|
} else {
|
|
$numProcs = (Get-CimInstance Win32_ComputerSystem -CimSession $CimSession).NumberOfLogicalProcessors
|
|
$processes = Get-CimInstance Win32_PerfFormattedData_PerfProc_Process -CimSession $CimSession |
|
|
Where-Object { $_.Name -notmatch '_Total|Idle' } |
|
|
Select-Object IDProcess,
|
|
@{Name='ProcessName';Expression={$_.Name -replace '#\d+$', ''}},
|
|
@{Name='PID';Expression={$_.IDProcess}},
|
|
@{Name='CPU_Percent';Expression={[math]::Round($_.PercentProcessorTime / $numProcs, 2)}} |
|
|
Sort-Object -Property CPU_Percent -Descending |
|
|
Select-Object -First 10
|
|
}
|
|
|
|
$processes | Format-Table -AutoSize | Out-String | ForEach-Object { Write-ColorOutput $_ "White" "Info" $ComputerName }
|
|
}
|
|
catch {
|
|
Write-ColorOutput "Error getting top CPU processes on ${ComputerName}: $_" "Red" $ComputerName
|
|
}
|
|
}
|
|
|
|
function Get-ServicesStatus {
|
|
param (
|
|
[Parameter(Mandatory=$false)]
|
|
[string]$ComputerName = $env:COMPUTERNAME,
|
|
|
|
[Parameter(Mandatory=$false)]
|
|
[Microsoft.Management.Infrastructure.CimSession]$CimSession = $null
|
|
)
|
|
|
|
Write-ColorOutput "`nChecking Critical Windows Services..." "Yellow" $ComputerName
|
|
|
|
$criticalServices = @(
|
|
"wuauserv", # Windows Update
|
|
"WinDefend", # Windows Defender
|
|
"wscsvc", # Security Center
|
|
"Dhcp", # DHCP Client
|
|
"Dnscache", # DNS Client
|
|
"LanmanServer", # Server
|
|
"LanmanWorkstation", # Workstation
|
|
"nsi", # Network Store Interface Service
|
|
"W32Time", # Windows Time
|
|
"eventlog" # Windows Event Log
|
|
)
|
|
|
|
foreach ($serviceName in $criticalServices) {
|
|
try {
|
|
if (-not $CimSession -and $ComputerName -eq $env:COMPUTERNAME) {
|
|
$service = Get-Service -Name $serviceName -ErrorAction Stop
|
|
} else {
|
|
$service = Get-CimInstance -ClassName Win32_Service -Filter "Name='$serviceName'" -CimSession $CimSession -ErrorAction Stop
|
|
}
|
|
|
|
$color = "Green"
|
|
$statusLevel = "Good"
|
|
if ($service.Status -ne "Running") { $color = "Red"; $statusLevel = "Warning" }
|
|
|
|
Write-ColorOutput "$($service.DisplayName): $($service.Status)" $color $statusLevel $ComputerName
|
|
}
|
|
catch {
|
|
Write-ColorOutput "Error checking service $serviceName on $ComputerName" "Red" $ComputerName
|
|
}
|
|
}
|
|
}
|
|
|
|
function Get-EventLogErrors {
|
|
param (
|
|
[Parameter(Mandatory=$false)]
|
|
[string]$ComputerName = $env:COMPUTERNAME,
|
|
|
|
[Parameter(Mandatory=$false)]
|
|
[Microsoft.Management.Infrastructure.CimSession]$CimSession = $null
|
|
)
|
|
|
|
Write-ColorOutput "`nScanning Windows Event Logs for errors (past 24 hours)..." "Yellow" $ComputerName
|
|
|
|
$startTime = (Get-Date).AddHours(-24)
|
|
$criticalLogs = @("System", "Application")
|
|
$errorCount = 0
|
|
|
|
foreach ($logName in $criticalLogs) {
|
|
Write-ColorOutput "Scanning $logName log..." "Gray" $ComputerName
|
|
|
|
try {
|
|
if (-not $CimSession -and $ComputerName -eq $env:COMPUTERNAME) {
|
|
$errors = Get-EventLog -LogName $logName -EntryType Error -After $startTime -ErrorAction SilentlyContinue
|
|
} else {
|
|
$allEvents = Get-CimInstance -ClassName Win32_NTLogEvent -Filter "Logfile='$logName'" -CimSession $CimSession -ErrorAction SilentlyContinue
|
|
$errors = $allEvents | Where-Object { $_.Type -eq 1 } | ForEach-Object {
|
|
$dt = [System.Management.ManagementDateTimeConverter]::ToDateTime($_.TimeGenerated)
|
|
if ($dt -ge $startTime) { $_ }
|
|
}
|
|
}
|
|
|
|
if ($errors -and $errors.Count -gt 0) {
|
|
$errorCount += $errors.Count
|
|
$topErrors = $errors | Group-Object -Property Source | Sort-Object -Property Count -Descending | Select-Object -First 3
|
|
|
|
foreach ($errorGroup in $topErrors) {
|
|
$latestError = $errors | Where-Object { $_.Source -eq $errorGroup.Name } | Sort-Object -Property TimeGenerated -Descending | Select-Object -First 1
|
|
$messagePreview = if ($latestError.Message.Length -gt 100) { $latestError.Message.Substring(0, 97) + "..." } else { $latestError.Message }
|
|
|
|
Write-ColorOutput "[$logName] $($errorGroup.Name) (EventID: $($latestError.EventID)): $($errorGroup.Count) occurrences" "Red" $ComputerName
|
|
Write-ColorOutput " Last occurred: $($latestError.TimeGenerated)" "Gray" $ComputerName
|
|
Write-ColorOutput " $messagePreview" "Gray" $ComputerName
|
|
}
|
|
}
|
|
}
|
|
catch {
|
|
Write-ColorOutput " Unable to retrieve events from $logName log on ${ComputerName}: $_" "Yellow" $ComputerName
|
|
}
|
|
}
|
|
|
|
# Display summary count
|
|
if ($errorCount -gt 0) {
|
|
Write-ColorOutput "Found $errorCount Error events in the past 24 hours" "Red" $ComputerName
|
|
}
|
|
else {
|
|
Write-ColorOutput "No Error events found in the past 24 hours" "Green" $ComputerName
|
|
}
|
|
}
|
|
|
|
function Get-WindowsUpdateStatus {
|
|
param (
|
|
[Parameter(Mandatory=$false)]
|
|
[string]$ComputerName = $env:COMPUTERNAME,
|
|
|
|
[Parameter(Mandatory=$false)]
|
|
[Microsoft.Management.Infrastructure.CimSession]$CimSession = $null
|
|
)
|
|
|
|
Write-ColorOutput "`nChecking Windows Update Status..." "Yellow" $ComputerName
|
|
|
|
# Get update service status
|
|
try {
|
|
if (-not $CimSession -and $ComputerName -eq $env:COMPUTERNAME) {
|
|
$wuauserv = Get-Service -Name "wuauserv" -ErrorAction SilentlyContinue
|
|
} else {
|
|
$wuauserv = Get-CimInstance -ClassName Win32_Service -Filter "Name='wuauserv'" -CimSession $CimSession -ErrorAction SilentlyContinue
|
|
}
|
|
|
|
if ($wuauserv) {
|
|
$color = "Green"
|
|
if ($wuauserv.Status -ne "Running") { $color = "Red" }
|
|
|
|
Write-ColorOutput "Windows Update Service: $($wuauserv.Status)" $color $ComputerName
|
|
if ($wuauserv.Status -ne "Running") {
|
|
Write-ColorOutput "WARNING: Windows Update service is not running!" "Red" $ComputerName
|
|
}
|
|
}
|
|
else {
|
|
Write-ColorOutput "Windows Update Service: Status unknown" "Red" $ComputerName
|
|
}
|
|
|
|
# Try COM object approach for more detailed update info
|
|
if ($IncludeUpdates) {
|
|
try {
|
|
$updateSession = New-Object -ComObject Microsoft.Update.Session
|
|
$updateSearcher = $updateSession.CreateUpdateSearcher()
|
|
|
|
# Check for pending updates
|
|
$pendingUpdates = $updateSearcher.Search("IsInstalled=0")
|
|
|
|
# Display Pending Updates
|
|
if ($pendingUpdates.Updates.Count -gt 0) {
|
|
Write-ColorOutput "`nPending Updates: $($pendingUpdates.Updates.Count)" "Yellow" $ComputerName
|
|
|
|
$count = 1
|
|
foreach ($update in $pendingUpdates.Updates) {
|
|
Write-ColorOutput "$count. $($update.Title)" "White" $ComputerName
|
|
$count++
|
|
|
|
# Limit to top 5 to avoid flooding console
|
|
if ($count -gt 5 -and $pendingUpdates.Updates.Count -gt 5) {
|
|
Write-ColorOutput " (and $($pendingUpdates.Updates.Count - 5) more...)" "Gray" $ComputerName
|
|
break
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
Write-ColorOutput "`nNo pending Windows updates found." "Green" $ComputerName
|
|
}
|
|
}
|
|
catch {
|
|
Write-ColorOutput "Limited Windows Update information available: $_" "Red" $ComputerName
|
|
}
|
|
}
|
|
}
|
|
catch {
|
|
Write-ColorOutput "Error checking Windows Update status on ${ComputerName}: $_" "Red" $ComputerName
|
|
}
|
|
}
|
|
|
|
function Show-Help {
|
|
Write-ColorOutput "`n===== HELP =====" "Magenta"
|
|
Write-ColorOutput "This script performs various system health checks to diagnose performance issues." "White"
|
|
Write-ColorOutput "`nAvailable Command-line Parameters:" "Cyan"
|
|
Write-ColorOutput " -ComputerName Target computer(s) to check (comma-separated)" "White"
|
|
Write-ColorOutput " -Credential Credentials for remote access (use Get-Credential)" "White"
|
|
Write-ColorOutput " -LogToFile Saves results to a log file" "White"
|
|
Write-ColorOutput " -LogPath Specifies custom log directory (default: Desktop\PCHealthChecks)" "White"
|
|
Write-ColorOutput " -Silent Suppresses console output (use with -LogToFile)" "White"
|
|
Write-ColorOutput " -ExportHTML Creates an HTML report of the results" "White"
|
|
Write-ColorOutput " -RunAllChecks Runs all checks automatically without user interaction" "White"
|
|
Write-ColorOutput " -IncludeNetwork Includes external network connectivity tests" "White"
|
|
Write-ColorOutput " -IncludeUpdates Checks for pending Windows updates" "White"
|
|
Write-ColorOutput " -ThrottleLimit Max concurrent connections (default: 5)" "White"
|
|
Write-ColorOutput " -Timeout Connection timeout in seconds (default: 30)" "White"
|
|
Write-ColorOutput " -Help Displays this help information" "White"
|
|
Write-ColorOutput "`nExample Usage:" "Cyan"
|
|
Write-ColorOutput " .\PCHealthCheck.ps1 -ComputerName PC01 -RunAllChecks -LogToFile" "White"
|
|
Write-ColorOutput " .\PCHealthCheck.ps1 -ComputerName PC01,PC02 -ExportHTML" "White"
|
|
Write-ColorOutput " .\PCHealthCheck.ps1 -ComputerName PC01 -Credential (Get-Credential)" "White"
|
|
Write-ColorOutput "`nPress any key to return to the menu..." "Yellow"
|
|
$null = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
|
|
}
|
|
|
|
function Show-LogFiles {
|
|
Write-ColorOutput "`nAvailable Log Files:" "Yellow"
|
|
|
|
try {
|
|
if (Test-Path -Path $LogPath) {
|
|
$logs = Get-ChildItem -Path $LogPath -Filter "PCHealthCheck_*.log" |
|
|
Sort-Object -Property LastWriteTime -Descending
|
|
|
|
if ($logs.Count -gt 0) {
|
|
$counter = 1
|
|
foreach ($log in $logs) {
|
|
Write-Host "$counter. $($log.Name) - $($log.LastWriteTime)" -ForegroundColor White
|
|
$counter++
|
|
|
|
# Limit to top 10 to avoid flooding console
|
|
if ($counter -gt 10 -and $logs.Count -gt 10) {
|
|
Write-Host " (and $($logs.Count - 10) more...)" -ForegroundColor Gray
|
|
break
|
|
}
|
|
}
|
|
|
|
Write-ColorOutput "`nLog location: $LogPath" "Cyan"
|
|
}
|
|
else {
|
|
Write-ColorOutput "No log files found." "Yellow"
|
|
}
|
|
}
|
|
else {
|
|
Write-ColorOutput "Log directory does not exist yet. Run some checks first." "Yellow"
|
|
}
|
|
}
|
|
catch {
|
|
Write-ColorOutput "Error listing log files: $_" "Red"
|
|
}
|
|
}
|
|
|
|
function Get-AutomaticServicesNotRunning {
|
|
param (
|
|
[Parameter(Mandatory=$false)]
|
|
[string]$ComputerName = $env:COMPUTERNAME,
|
|
|
|
[Parameter(Mandatory=$false)]
|
|
[Microsoft.Management.Infrastructure.CimSession]$CimSession = $null
|
|
)
|
|
|
|
Write-ColorOutput "`nChecking Automatic Services Not Running..." "Yellow" $ComputerName
|
|
|
|
try {
|
|
if (-not $CimSession -and $ComputerName -eq $env:COMPUTERNAME) {
|
|
$services = Get-Service | Where-Object { $_.StartType -eq "Automatic" -and $_.Status -ne "Running" } |
|
|
Sort-Object DisplayName
|
|
} else {
|
|
$services = Get-CimInstance -ClassName Win32_Service -CimSession $CimSession |
|
|
Where-Object { $_.StartMode -eq "Auto" -and $_.State -ne "Running" } |
|
|
Sort-Object Name
|
|
}
|
|
|
|
if ($services.Count -eq 0) {
|
|
Write-ColorOutput "All automatic services are running." "Green" "Good" $ComputerName
|
|
} else {
|
|
Write-ColorOutput "Found $($services.Count) automatic service(s) not running:" "Red" "Warning" $ComputerName
|
|
foreach ($service in $services) {
|
|
$serviceName = if (-not $CimSession -and $ComputerName -eq $env:COMPUTERNAME) { $service.DisplayName } else { $service.Name }
|
|
Write-ColorOutput " - $serviceName" "Red" "Warning" $ComputerName
|
|
}
|
|
}
|
|
}
|
|
catch {
|
|
Write-ColorOutput "Error checking automatic services on ${ComputerName}: $_" "Red" "Critical" $ComputerName
|
|
}
|
|
}
|
|
|
|
function Run-AllChecks {
|
|
param (
|
|
[Parameter(Mandatory=$false)]
|
|
[string]$ComputerName = $env:COMPUTERNAME
|
|
)
|
|
|
|
Write-ColorOutput "`n===== Running All System Checks =====" "Cyan" $ComputerName
|
|
|
|
# Create CIM session for remote computers
|
|
$cimSession = $null
|
|
if ($ComputerName -ne $env:COMPUTERNAME) {
|
|
$cimSession = Get-CimSessionForComputer -ComputerName $ComputerName -Credential $Credential
|
|
}
|
|
|
|
try {
|
|
# Run all check functions with CIM session
|
|
Get-DiskSpace -ComputerName $ComputerName -CimSession $cimSession
|
|
Get-MemoryUsage -ComputerName $ComputerName -CimSession $cimSession
|
|
Get-CPUUsage -ComputerName $ComputerName -CimSession $cimSession
|
|
Test-NetworkConnectivity -ComputerName $ComputerName -CimSession $cimSession
|
|
Test-PortExhaustion -ComputerName $ComputerName -CimSession $cimSession
|
|
Get-SystemUptime -ComputerName $ComputerName -CimSession $cimSession
|
|
Get-ServicesStatus -ComputerName $ComputerName -CimSession $cimSession
|
|
Get-EventLogErrors -ComputerName $ComputerName -CimSession $cimSession
|
|
Get-WindowsUpdateStatus -ComputerName $ComputerName -CimSession $cimSession
|
|
Get-AutomaticServicesNotRunning -ComputerName $ComputerName -CimSession $cimSession
|
|
Check-PendingReboot -ComputerName $ComputerName -CimSession $cimSession
|
|
Check-NetworkAdapters -ComputerName $ComputerName -CimSession $cimSession
|
|
|
|
Write-ColorOutput "`nSystem Check Complete!" "Cyan" $ComputerName
|
|
|
|
if ($LogToFile) {
|
|
Write-ColorOutput "Results saved to: $logFile" "Cyan" $ComputerName
|
|
}
|
|
|
|
if ($ExportHTML) {
|
|
$reportPath = Save-HtmlReport -ComputerName $ComputerName
|
|
if (-not $Silent) {
|
|
Write-Host "`nHTML report generated: $reportPath" -ForegroundColor Green
|
|
}
|
|
}
|
|
}
|
|
finally {
|
|
# Clean up CIM session
|
|
if ($cimSession) {
|
|
Remove-CimSession $cimSession
|
|
}
|
|
}
|
|
}
|
|
|
|
function Check-PendingReboot {
|
|
param (
|
|
[Parameter(Mandatory=$false)]
|
|
[string]$ComputerName = $env:COMPUTERNAME,
|
|
|
|
[Parameter(Mandatory=$false)]
|
|
[Microsoft.Management.Infrastructure.CimSession]$CimSession = $null
|
|
)
|
|
|
|
Write-ColorOutput "`nChecking Pending Reboot Status..." "Yellow" $ComputerName
|
|
|
|
$rebootPending = $false
|
|
$rebootReasons = @()
|
|
|
|
try {
|
|
if (-not $CimSession -and $ComputerName -eq $env:COMPUTERNAME) {
|
|
# Check Component Based Servicing reboot pending
|
|
$csbPath = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Component Based Servicing\RebootPending"
|
|
if (Test-Path $csbPath) {
|
|
$rebootPending = $true
|
|
$rebootReasons += "Component Based Servicing (CBS)"
|
|
}
|
|
|
|
# Check Windows Update reboot required
|
|
$wuPath = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update\RebootRequired"
|
|
if (Test-Path $wuPath) {
|
|
$rebootPending = $true
|
|
$rebootReasons += "Windows Update"
|
|
}
|
|
|
|
# Check pending file rename operations
|
|
$pendingRenamePath = "HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager\PendingFileRenameOperations"
|
|
$pendingRename = Get-ItemProperty -Path $pendingRenamePath -Name "PendingFileRenameOperations" -ErrorAction SilentlyContinue
|
|
if ($pendingRename -and $pendingRename.PendingFileRenameOperations) {
|
|
$rebootPending = $true
|
|
$rebootReasons += "Pending File Rename Operations"
|
|
}
|
|
|
|
# Check Server Manager reboot attempts (if present)
|
|
$smPath = "HKLM:\SOFTWARE\Microsoft\ServerManager\CurrentRebootAttempts"
|
|
if (Test-Path $smPath) {
|
|
$rebootPending = $true
|
|
$rebootReasons += "Server Manager Reboot Attempt"
|
|
}
|
|
} else {
|
|
# Remote CIM session - use StdRegProv
|
|
$regKey = "SOFTWARE\Microsoft\Windows\CurrentVersion\Component Based Servicing"
|
|
$regProv = Get-CimInstance -ClassName StdRegProv -Namespace "root\cimv2" -CimSession $CimSession -ErrorAction SilentlyContinue
|
|
|
|
if ($regProv) {
|
|
# Check CBS RebootPending
|
|
$csbValue = $regProv.GetStringValue(2147483650, "$regKey\RebootPending", "")
|
|
if ($csbValue -and $csbValue.sValue -eq "1") {
|
|
$rebootPending = $true
|
|
$rebootReasons += "Component Based Servicing (CBS)"
|
|
}
|
|
|
|
# Check Windows Update RebootRequired
|
|
$wuKey = "SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update"
|
|
$wuValue = $regProv.GetStringValue(2147483650, "$wuKey\RebootRequired", "")
|
|
if ($wuValue -and $wuValue.sValue -eq "1") {
|
|
$rebootPending = $true
|
|
$rebootReasons += "Windows Update"
|
|
}
|
|
|
|
# Check pending file rename operations
|
|
$sessionKey = "SYSTEM\CurrentControlSet\Control\Session Manager"
|
|
$renameValue = $regProv.GetMultiStringValue(2147483650, $sessionKey, "PendingFileRenameOperations")
|
|
if ($renameValue.sValue -and $renameValue.sValue.Count -gt 0) {
|
|
$rebootPending = $true
|
|
$rebootReasons += "Pending File Rename Operations"
|
|
}
|
|
|
|
# Check Server Manager
|
|
$smKey = "SOFTWARE\Microsoft\ServerManager"
|
|
$smValue = $regProv.GetDWORDValue(2147483650, "$smKey\CurrentRebootAttempts", "")
|
|
if ($smValue -and $smValue.uValue -gt 0) {
|
|
$rebootPending = $true
|
|
$rebootReasons += "Server Manager Reboot Attempt"
|
|
}
|
|
}
|
|
}
|
|
|
|
if ($rebootPending) {
|
|
Write-ColorOutput "PENDING REBOOT DETECTED!" "Red" "Warning" $ComputerName
|
|
Write-ColorOutput "Reboot required by:" "Yellow" $ComputerName
|
|
foreach ($reason in $rebootReasons) {
|
|
Write-ColorOutput " - $reason" "Yellow" $ComputerName
|
|
}
|
|
} else {
|
|
Write-ColorOutput "No pending reboot detected" "Green" "Good" $ComputerName
|
|
}
|
|
}
|
|
catch {
|
|
Write-ColorOutput "Error checking pending reboot status on ${ComputerName}: $_" "Red" "Critical" $ComputerName
|
|
}
|
|
}
|
|
|
|
function Check-NetworkAdapters {
|
|
param (
|
|
[Parameter(Mandatory=$false)]
|
|
[string]$ComputerName = $env:COMPUTERNAME,
|
|
|
|
[Parameter(Mandatory=$false)]
|
|
[Microsoft.Management.Infrastructure.CimSession]$CimSession = $null
|
|
)
|
|
|
|
Write-ColorOutput "`nChecking Network Adapters..." "Yellow" $ComputerName
|
|
|
|
try {
|
|
if (-not $CimSession -and $ComputerName -eq $env:COMPUTERNAME) {
|
|
$adapters = Get-CimInstance -ClassName Win32_NetworkAdapter -ErrorAction Stop |
|
|
Where-Object { $_.PhysicalAdapter -eq $true -or $_.PhysicalAdapter -eq $null } |
|
|
Sort-Object Name
|
|
} else {
|
|
$adapters = Get-CimInstance -ClassName Win32_NetworkAdapter -CimSession $CimSession -ErrorAction Stop |
|
|
Where-Object { $_.PhysicalAdapter -eq $true -or $_.PhysicalAdapter -eq $null } |
|
|
Sort-Object Name
|
|
}
|
|
|
|
Write-ColorOutput "`nActive Network Adapters:" "White" $ComputerName
|
|
|
|
foreach ($adapter in $adapters) {
|
|
if ($adapter.NetConnectionStatus -eq 2) {
|
|
$status = "Connected"
|
|
$statusColor = "Green"
|
|
} else {
|
|
$status = "Disconnected"
|
|
$statusColor = "Red"
|
|
}
|
|
|
|
$speed = if ($adapter.Speed) { [math]::Round($adapter.Speed / 1GB, 2) } else { 0 }
|
|
$speedStr = if ($speed -gt 0) { "$speed Gbps" } else { "Unknown" }
|
|
|
|
Write-ColorOutput "`nAdapter: $($adapter.Name)" "White" $ComputerName
|
|
Write-ColorOutput " Description: $($adapter.Description)" "White" $ComputerName
|
|
Write-ColorOutput " Status: $status" $statusColor $ComputerName
|
|
Write-ColorOutput " Speed: $speedStr" "White" $ComputerName
|
|
Write-ColorOutput " MAC Address: $($adapter.MACAddress)" "White" $ComputerName
|
|
|
|
# Get IP configuration
|
|
if (-not $CimSession -and $ComputerName -eq $env:COMPUTERNAME) {
|
|
$ipConfig = Get-CimInstance -ClassName Win32_NetworkAdapterConfiguration -Filter "InterfaceIndex=$($adapter.InterfaceIndex)" -ErrorAction SilentlyContinue
|
|
} else {
|
|
$ipConfig = Get-CimInstance -ClassName Win32_NetworkAdapterConfiguration -CimSession $CimSession -Filter "InterfaceIndex=$($adapter.InterfaceIndex)" -ErrorAction SilentlyContinue
|
|
}
|
|
|
|
if ($ipConfig) {
|
|
if ($ipConfig.IPAddress) {
|
|
Write-ColorOutput " IP Addresses:" "White" $ComputerName
|
|
foreach ($ip in $ipConfig.IPAddress) {
|
|
$ipType = if ($ip -like "*:*") { "IPv6" } else { "IPv4" }
|
|
Write-ColorOutput " ${ipType}: $ip" "White" $ComputerName
|
|
}
|
|
}
|
|
if ($ipConfig.DefaultIPGateway) {
|
|
Write-ColorOutput " Default Gateway: $($ipConfig.DefaultIPGateway -join ', ')" "White" $ComputerName
|
|
}
|
|
if ($ipConfig.DNSServerSearchOrder) {
|
|
Write-ColorOutput " DNS Servers: $($ipConfig.DNSServerSearchOrder -join ', ')" "White" $ComputerName
|
|
}
|
|
}
|
|
}
|
|
|
|
# Throughput monitoring (1-second sample)
|
|
Write-ColorOutput "`nNetwork Throughput (1-second sample):" "White" $ComputerName
|
|
|
|
if (-not $CimSession -and $ComputerName -eq $env:COMPUTERNAME) {
|
|
$perfData = Get-CimInstance -ClassName Win32_PerfFormattedData_Tcpip_NetworkInterface -ErrorAction SilentlyContinue
|
|
} else {
|
|
$perfData = Get-CimInstance -ClassName Win32_PerfFormattedData_Tcpip_NetworkInterface -CimSession $CimSession -ErrorAction SilentlyContinue
|
|
}
|
|
|
|
if ($perfData) {
|
|
foreach ($iface in $perfData) {
|
|
$bytesSent = [math]::Round($iface.BytesSentPerSec / 1MB, 2)
|
|
$bytesRecv = [math]::Round($iface.BytesReceivedPerSec / 1MB, 2)
|
|
Write-ColorOutput "$($iface.Name): Sent $bytesSent MB/s, Received $bytesRecv MB/s" "White" $ComputerName
|
|
}
|
|
} else {
|
|
Write-ColorOutput " Unable to retrieve throughput data" "Gray" $ComputerName
|
|
}
|
|
}
|
|
catch {
|
|
Write-ColorOutput "Error checking network adapters on ${ComputerName}: $_" "Red" "Critical" $ComputerName
|
|
}
|
|
}
|
|
|
|
# Main program
|
|
# Run command-line mode if switches are used
|
|
if (($RunAllChecks) -or ($Silent)) {
|
|
if (($LogToFile) -or ($ExportHTML)) {
|
|
if ($ComputerName) {
|
|
foreach ($computer in $ComputerName) {
|
|
Show-Banner -ComputerName $computer
|
|
Run-AllChecks -ComputerName $computer
|
|
}
|
|
} else {
|
|
Show-Banner
|
|
Run-AllChecks
|
|
}
|
|
exit
|
|
}
|
|
}
|
|
|
|
# Otherwise run in interactive mode
|
|
Show-Banner
|
|
|
|
$exitRequested = $false
|
|
|
|
while (-not $exitRequested) {
|
|
Show-Menu
|
|
$choice = Read-Host "Enter your choice"
|
|
|
|
switch ($choice.ToUpper()) {
|
|
"1" { Get-DiskSpace }
|
|
"2" { Get-CPUUsage }
|
|
"3" { Get-MemoryUsage }
|
|
"4" { Test-NetworkConnectivity }
|
|
"5" { Test-PortExhaustion }
|
|
"6" { Get-SystemUptime }
|
|
"7" { Get-TopProcessesByMemory }
|
|
"8" { Get-TopProcessesByCPU }
|
|
"9" { Get-ServicesStatus }
|
|
"10" { Get-EventLogErrors }
|
|
"11" { Get-WindowsUpdateStatus }
|
|
"12" { Run-AllChecks }
|
|
"13" { Check-PendingReboot }
|
|
"14" { Check-NetworkAdapters }
|
|
"H" { Show-Help }
|
|
"L" { Show-LogFiles }
|
|
"E" {
|
|
# Generate and open HTML report
|
|
$originalExportHTML = $ExportHTML
|
|
$ExportHTML = $true
|
|
Run-AllChecks
|
|
$ExportHTML = $originalExportHTML
|
|
}
|
|
"Q" {
|
|
Write-ColorOutput "Exiting script..." "Cyan"
|
|
$exitRequested = $true
|
|
}
|
|
default { Write-ColorOutput "Invalid choice. Please try again." "Red" "Critical" }
|
|
}
|
|
|
|
if (-not $exitRequested) {
|
|
Write-ColorOutput "`nPress any key to continue..." "Yellow"
|
|
$null = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
|
|
Clear-Host
|
|
Show-Banner
|
|
}
|
|
}
|