Utils/Get-PCHealth.ps1
# ============================================================================= # Created On: 2018/07/09 @ 15:48 # Created By: Alcha # Organization: HassleFree Solutions, LLC # Filename: Get-PCHealth.ps1 # Description: This script was originally written by Robert Stahl and shared # on the Spiceworks community site: # https://community.spiceworks.com/scripts/show/3765-powershell-system-health-check # # Any changes between the linked script and this are made by myself to make it # either easier on the eyes or to be more targetted to my own preferences. # # Notes: The purpose of this script is to run a series of health checks # on a given server or array of servers. The health check queries the # following info which is then formatted to HTML and saved in a file at # "C:\Logs\SERVER_NAME_Health_Report_FormattedDateTime.html": # # 1) System Information - name, OS, Build #, Major Service Pack Level, and Last Boot Time # 2) Disk Information - DeviceID, Volume Name, Size in GB, Free Space in GB, Free Space in % # 3) Application Log Information - Warnings and errors added to the Application Log within the last 24 hours # 4) System Log Information - Warnings and errors added to the System Log within the last 24 hours # 5) Services Information - Sorted by Start Up Type and running or not. Shows the DisplayName, Name, StartMode, and State # ============================================================================= <# .SYNOPSIS A brief description of the Get-PCHealth.ps1 file. .DESCRIPTION A detailed description of the Get-PCHealth.ps1 file. .PARAMETER ParamaterName A description of the parameter. .PARAMETER ComputerName A description of the ComputerName parameter. .PARAMETER OpenLog A description of the OpenLog parameter. .EXAMPLE PS C:\> .\Get-PCHealth.ps1 .NOTES Additional information about the file. #> [CmdletBinding()] [Alias('Get-Health', 'PCHealth')] param ( [Parameter(Mandatory = $false, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, Position = 0)] [Alias('Name', 'Computer')] [System.String] $ComputerName = $env:COMPUTERNAME, [Parameter(Mandatory = $false, Position = 1)] [Alias('Open', 'Launch')] [switch] $OpenLog <# TODO: Add a DataOnly switch parameter that when present, only return the data for the PC health instead of all the fancy shit I do with it. #> ) . $PSScriptRoot\Get-InstalledSoftware.ps1 . $PSScriptRoot\..\Network\Send-DailyReportToDiscord.ps1 #region Variable Declarations $TOCContent = @" <ul> <li><a href="#System">System Information</a></li> <li><a href="#Disk">Disk Information</a></li> <li><a href="#Application_Log">Application Log Information</a></li> <li><a href="#System_Log">System Log Information</a></li> <li><a href="#Services">Services Information</a></li> <li><a href="#Installed_Programs">Installed Programs Information</a></li> </ul> "@ $Style = @" <style> BODY{ background-color: #b0c4de; } TABLE{ border-width: 1px; border-style: solid; border-color: black; border-collapse: collapse; } TH{ border-width: 1px; padding: 3px; border-style: solid; border-color: black; background-color: #778899 } TD{ border-width: 1px; padding: 3px; border-style: solid; border-color: black; } tr:nth-child(odd) { background-color: #d3d3d3; } tr:nth-child(even) { background-color: white; } </style> "@ #endregion Variable Declarations #region Helper Functions function Initialize-HTMLReportContent { [CmdletBinding()] param () $script:StatusColor = @{ Stopped = ' bgcolor="Red">Stopped<'; Running = ' bgcolor="Green">Running<'; } $script:EventColor = @{ Error = ' bgcolor="Red">Error<'; Warning = ' bgcolor="Yellow">Warning<'; } $script:ReportHead = ConvertTo-HTML -As Table -Fragment -PreContent '<h1>System Health Check</h1>' | Out-String $script:OSHead = ConvertTo-HTML -As Table -Fragment -PreContent '<h2 id="System">System Information</h2>' | Out-String $script:DiskHead = ConvertTo-HTML -As Table -Fragment -PreContent '<h2 id="Disk">Disk Information</h2>' | Out-String $script:AppLogHead = ConvertTo-HTML -As Table -Fragment -PreContent '<h2 id="Application_Log">Application Log Information</h2>' | Out-String $script:SysLogHead = ConvertTo-HTML -As Table -Fragment -PreContent '<h2 id="System_Log">System Log Information</h2>' | Out-String $script:ServHead = ConvertTo-HTML -As Table -Fragment -PreContent '<h2 id="Services">Services Information</h2>' | Out-String $script:InstalledAppsHead = ConvertTo-HTML -As Table -Fragment -PreContent '<h2 id="Installed_Programs">Installed Programs Information</h2>' | Out-String } function Initialize-TimestampData { [CmdletBinding()] param () $TimestampAtBoot = Get-WmiObject Win32_PerfRawData_PerfOS_System | Select-Object -ExpandProperty systemuptime $CurrentTimestamp = Get-WmiObject Win32_PerfRawData_PerfOS_System | Select-Object -ExpandProperty Timestamp_Object $Frequency = Get-WmiObject Win32_PerfRawData_PerfOS_System | Select-Object -ExpandProperty Frequency_Object $UptimeInSec = ($CurrentTimestamp - $TimestampAtBoot) / $Frequency $script:Time = (Get-Date) - (New-TimeSpan -Seconds $UptimeInSec) $script:FormattedDate = (Get-Date).ToString('yyyy-MM-dd') } function Get-Filename { [CmdletBinding()] param () $LogDirDate = Get-Date -UFormat "%Y-%m" $FileDir = "E:\Logs\$LogDirDate" Write-Verbose "FileDir = $FileDir" if (!(Test-Path $FileDir)) { New-Item -Path $FileDir -ItemType Directory -Force } $Filename = "$ComputerName`_Health_Report_$FormattedDate.html" Write-Verbose "Filename = $Filename" return Join-Path -Path $FileDir -ChildPath $Filename } function Get-AllData { $Freespace = @{ Expression = { [int]($_.Freespace / 1GB) } Name = 'Free Space (GB)' } $Size = @{ Expression = { [int]($_.Size / 1GB) } Name = 'Size (GB)' } $PercentFree = @{ Expression = { [int]($_.Freespace * 100 / $_.Size) } Name = 'Free (%)' } # Gathers information for System Name, Operating System, Microsoft Build Number, Major Service Pack Installed, and the last time the system was booted $script:OS = Get-WmiObject -class Win32_OperatingSystem -ComputerName $ComputerName | Select-Object -Property CSName, Caption, BuildNumber, ServicePackMajorVersion, @{ n = 'LastBootTime'; e = { $_.ConvertToDateTime($_.LastBootUpTime) } } $script:OSHtml = $scriptOS | ConvertTo-HTML -Fragment # Gathers information for Device ID, Volume Name, Size in Gb, Free Space in Gb, and Percent of Frree Space on each storage device that the system sees $script:Disk = Get-WmiObject -Class Win32_LogicalDisk -ComputerName $ComputerName | Select-Object -Property DeviceID, VolumeName, $Size, $Freespace, $PercentFree $script:DiskHtml = $script:Disk | ConvertTo-Html -Fragment # Gathers Warning and Errors out of the Application event log. Displays Event ID, Event Type, Source of event, Time the event was generated, and the message of the event. $script:AppEvent = Get-EventLog -ComputerName $ComputerName -LogName Application -EntryType "Error", "Warning" -after $script:Time | Select-Object -Property EventID, EntryType, Source, TimeGenerated, Message $script:AppEventHtml = $script:AppEvent | ConvertTo-Html -Fragment # Gathers Warning and Errors out of the System event log. Displays Event ID, Event Type, Source of event, Time the event was generated, and the message of the event. $script:SysEvent = Get-EventLog -ComputerName $ComputerName -LogName System -EntryType "Error", "Warning" -After $Time | Select-Object -Property EventID, EntryType, Source, TimeGenerated, Message $script:SysEventHtml = $script:SysEvent | ConvertTo-Html -Fragment # Gathers information on Services. Displays the service name, System name of the Service, Start Mode, and State. Sorted by Start Mode and then State. $script:Service = Get-WmiObject win32_service -ComputerName $ComputerName | Select-Object DisplayName, Name, StartMode, State | Sort-Object StartMode, State, DisplayName $script:ServiceHtml = $script:Service | ConvertTo-Html -Fragment # Gathers information about Installed Applications on the Machine. . $PSScriptRoot\Get-InstalledSoftware.ps1 $script:InstalledApps = Get-InstalledSoftware $script:InstalledAppsHtml = $script:InstalledApps | ConvertTo-Html -Fragment } #endregion Helper Functions # Retrieves current Disk Space Status Write-Verbose "Generating PC Health Checkup..." Initialize-HTMLReportContent Initialize-TimestampData Get-AllData # Applies color coding based on cell value $StatusColor.Keys | ForEach-Object { $Service = $Service -replace ">$_<", ($StatusColor.$_) } $EventColor.Keys | ForEach-Object { $AppEvent = $AppEvent -replace ">$_<", ($EventColor.$_) } $EventColor.Keys | ForEach-Object { $SysEvent = $SysEvent -replace ">$_<", ($EventColor.$_) } $FullPath = Get-Filename Write-Verbose "FullPath = $FullPath" # Builds the HTML report for output $PostContent = "$script:ReportHead $TOCContent $script:OSHead $script:OSHtml $script:DiskHead $script:DiskHtml ` $script:AppLogHead $script:AppEventHtml $script:SysLogHead $script:SysEventHtml $script:ServHead $script:ServiceHtml ` $script:InstalledAppsHead $script:InstalledAppsHtml" ConvertTo-HTML -Head $Style -PostContent $PostContent | Out-File $FullPath Write-Verbose 'PC Health Checkup generated...' if ($OpenLog.IsPresent) { Write-Verbose 'Opening the generated log file...' Start-Process -FilePath $FullPath } Write-Verbose 'Sending status messages to Discord webhook...' function ConvertFrom-StringToObject { [CmdletBinding()] [Alias('csto')] param ( [Parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] [Alias('Object', 'Data', 'Str')] [System.String] $ObjectString ) $ObjectString = $ObjectString.Substring($ObjectString.IndexOf("{") + 1) $OuterObjectArray = $ObjectString.Split([System.Environment]::NewLine) $ObjectCollection = @{ } foreach ($Line in $OuterObjectArray) { if ($Line -match ';') { $ObjectCollection += Get-SemiInnerObjects $Line } elseif ($Line -match ':') { $ObjectCollection += Get-ColonInnerObjects $Line } } $ObjectCollection } function Get-ColonInnerObjects { param ( [System.String] $LineIn ) $LineArr = $LineIn.sub $ObjectCollection = @{ } $ObjectCollection.Add($LineArr[0], $LineArr[1]) return $ObjectCollection } function Get-SemiInnerObjects { param ( [System.String] $LineIn ) $LineArr = $LineIn.Split(';') $ObjectCollection = @{ } foreach ($Item in $LineArr) { $Item = $Item.Trim() if ($Item -match '=') { $Name = $Item.Substring(0, $Item.IndexOf('=')) $Value = $Item.Substring($Item.IndexOf('=') + 1) $ObjectCollection.Add($Name, $Value) } elseif ($Item -match ':') { $Name = $Item.Substring(0, $Item.IndexOf(':')) $Value = $Item.Substring($Item.IndexOf(':') + 1) $ObjectCollection.Add($Name, $Value) } } return $ObjectCollection } $PackagedData = @{ InstalledApps = $script:InstalledApps; OS = $script:OS; Disk = $script:Disk; AppEvent = (ConvertFrom-StringToObject $script:AppEvent[0]); SysEvent = $script:SysEvent; Service = $script:Service; } Send-DailyReportToDiscord -Data $PackagedData |