Public/Get-EFEndpointSummary.ps1
|
function Get-EFEndpointSummary { <# .SYNOPSIS Gets one combined computer health and Windows settings checkup. .DESCRIPTION Provides the recommended first check for EndpointForge. It reads computer details, everyday health, restart status, and important Windows settings, then explains what needs attention. It does not change Windows. EndpointForge calls the Windows settings checklist a baseline in script properties so existing automation remains compatible. No knowledge of configuration frameworks is required to use the returned guidance. .PARAMETER Baseline The checklist of expected Windows settings: a built-in name, JSON path, or validated checklist object. .PARAMETER ControlId Limits the check to selected checklist item IDs. .PARAMETER IncludeSoftware Includes installed software in the nested Inventory object. .PARAMETER MinimumFreeSpacePercent The system-drive free-space warning threshold. .PARAMETER MaximumUptimeDays The endpoint uptime warning threshold. .PARAMETER NoProgress Suppresses the progress display for non-interactive automation hosts. .EXAMPLE Get-EFEndpointSummary .EXAMPLE Get-EFEndpointSummary -NoProgress | Show-EFEndpointSummary -Detailed .OUTPUTS EndpointForge.EndpointSummary #> [CmdletBinding()] param( [Parameter(Position = 0)] [AllowNull()] [object]$Baseline = 'EnterpriseRecommended', [string[]]$ControlId, [switch]$IncludeSoftware, [ValidateRange(1, 99)] [int]$MinimumFreeSpacePercent = 15, [ValidateRange(1, 3650)] [int]$MaximumUptimeDays = 30, [switch]$NoProgress ) $null = Test-EFWindows -Throw $timer = [Diagnostics.Stopwatch]::StartNew() $correlationId = [guid]::NewGuid().ToString() try { if (-not $NoProgress) { Write-Progress -Id 1100 -Activity 'EndpointForge computer checkup' -Status 'Reading computer health' -PercentComplete 10 } $health = Get-EFEndpointHealth -MinimumFreeSpacePercent $MinimumFreeSpacePercent ` -MaximumUptimeDays $MaximumUptimeDays -IncludeSoftware:$IncludeSoftware -NoProgress if (-not $NoProgress) { Write-Progress -Id 1100 -Activity 'EndpointForge computer checkup' -Status 'Checking recommended Windows settings' -PercentComplete 60 } $complianceParameters = @{ Baseline = $Baseline NoProgress = $true } if ($PSBoundParameters.ContainsKey('ControlId')) { $complianceParameters.ControlId = $ControlId } $compliance = Get-EFComplianceReport @complianceParameters if (-not $NoProgress) { Write-Progress -Id 1100 -Activity 'EndpointForge computer checkup' -Status 'Explaining what needs attention' -PercentComplete 90 } $findings = [Collections.Generic.List[object]]::new() foreach ($check in @($health.Checks | Where-Object { $_.Status -ne 'Healthy' -and $_.Id -ne 'InventoryCollection' })) { $suggestedAction = if ($check.Status -eq 'Unknown') { 'Review collection details and rerun elevated if the capability requires administrator privileges.' } else { 'Review the health check details and address the reported threshold or protection state.' } $findingTitle = switch -Wildcard ([string]$check.Id) { 'DiskFreeSpace' { 'System drive free space' } 'Uptime' { 'Endpoint uptime' } 'PendingReboot' { 'Pending restart' } 'Firewall*' { ([string]$check.Id).Replace('Firewall', '') + ' firewall profile' } 'DefenderRealTimeProtection' { 'Microsoft Defender real-time protection' } 'BitLockerProtection' { 'BitLocker system-drive protection' } default { [string]$check.Id } } $findings.Add([pscustomobject]@{ Source = 'Health' Id = [string]$check.Id Title = $findingTitle Severity = [string]$check.Severity Status = [string]$check.Status Message = [string]$check.Message SuggestedAction = $suggestedAction RequiresElevation = $false WhyItMatters = switch -Wildcard ([string]$check.Id) { 'DiskFreeSpace' { 'Windows and applications need free disk space to update and work reliably.' } 'Uptime' { 'Regular approved restarts allow completed updates and maintenance to take effect.' } 'PendingReboot' { 'Some updates and configuration changes do not finish until Windows restarts.' } 'Firewall*' { 'The Windows firewall helps block unwanted network connections.' } 'Defender*' { 'Real-time threat protection helps detect harmful files and activity.' } 'BitLocker*' { 'Drive encryption helps protect files if a computer or drive is lost.' } default { 'This check helps describe the computer''s current health and protection.' } } HowChecked = 'EndpointForge read the related Windows status. It did not change the setting.' WhatWouldChange = 'Nothing during this check.' ManualAction = $suggestedAction }) } foreach ($controlResult in @($compliance.Results | Where-Object Status -in @('NonCompliant', 'Error'))) { $requiresElevation = $controlResult.Status -eq 'Error' -and $controlResult.Message -match 'elevat|access.+denied|administrator|privilege' $findings.Add([pscustomobject]@{ Source = 'Compliance' Id = [string]$controlResult.ControlId Title = [string]$controlResult.Title Severity = [string]$controlResult.Severity Status = [string]$controlResult.Status Message = [string]$controlResult.Message SuggestedAction = [string]$controlResult.RecommendedAction RequiresElevation = [bool]$requiresElevation ActualValue = Get-EFPropertyValue -InputObject $controlResult -Name 'ActualValue' DesiredValue = Get-EFPropertyValue -InputObject $controlResult -Name 'DesiredValue' WhyItMatters = [string](Get-EFPropertyValue -InputObject $controlResult -Name 'WhyItMatters' -Default '') HowChecked = [string](Get-EFPropertyValue -InputObject $controlResult -Name 'HowChecked' -Default '') WhatWouldChange = [string](Get-EFPropertyValue -InputObject $controlResult -Name 'WhatWouldChange' -Default '') ManualAction = [string](Get-EFPropertyValue -InputObject $controlResult -Name 'ManualAction' -Default $controlResult.RecommendedAction) SafetyNotes = [string](Get-EFPropertyValue -InputObject $controlResult -Name 'SafetyNotes' -Default '') }) } $criticalComplianceCount = @($compliance.Results | Where-Object { $_.Status -eq 'NonCompliant' -and $_.Severity -eq 'Critical' }).Count $actualIssueCount = @($findings | Where-Object Status -notin @('Unknown', 'Error')).Count $unknownCount = @($findings | Where-Object Status -in @('Unknown', 'Error')).Count $overallStatus = if ($health.Status -eq 'Critical' -or $criticalComplianceCount -gt 0) { 'Critical' } elseif ($actualIssueCount -gt 0 -or $health.Status -eq 'Warning') { 'Warning' } elseif ($unknownCount -gt 0) { 'Incomplete' } else { 'Healthy' } $complianceStatus = if ($compliance.NonCompliantCount -gt 0) { 'NonCompliant' } elseif ($compliance.ErrorCount -gt 0) { 'Incomplete' } else { 'Compliant' } $dataStatus = if ($health.DataStatus -eq 'Failed' -or $compliance.DataStatus -eq 'Failed') { 'Failed' } elseif ($health.DataStatus -eq 'Partial' -or $compliance.DataStatus -eq 'Partial') { 'Partial' } else { 'Complete' } $coveragePercent = [math]::Round(($health.CoveragePercent + $compliance.CoveragePercent) / 2, 1) $score = [math]::Round(($health.Score + $compliance.Score) / 2, 1) $exitCode = if ($dataStatus -eq 'Failed' -or $compliance.ErrorCount -gt 0) { 3 } elseif ($overallStatus -eq 'Critical' -or $compliance.NonCompliantCount -gt 0) { 2 } elseif ($overallStatus -eq 'Warning' -or $dataStatus -eq 'Partial') { 1 } else { 0 } $inventory = $health.Inventory $firewallProfiles = @($inventory.Security.Firewall) $enabledFirewallProfiles = @($firewallProfiles | Where-Object Enabled).Count $defender = $inventory.Security.Defender $bitLocker = $inventory.Security.BitLocker $security = [pscustomobject]@{ Firewall = if ($firewallProfiles.Count -eq 0) { 'Unknown' } else { "$enabledFirewallProfiles/$($firewallProfiles.Count) enabled" } Defender = if ($null -eq $defender) { 'Unknown' } elseif ($defender.RealTimeProtectionEnabled) { 'Enabled' } else { 'Disabled' } BitLocker = if ($null -eq $bitLocker) { 'Unknown' } else { [string]$bitLocker.ProtectionStatus } SecureBoot = if ($null -eq $inventory.Security.SecureBoot) { 'Unknown' } elseif ($inventory.Security.SecureBoot) { 'Enabled' } else { 'Disabled' } Tpm = if ($null -eq $inventory.Security.Tpm) { 'Unknown' } elseif ($inventory.Security.Tpm.Ready) { 'Ready' } else { 'NotReady' } } $sortedFindings = @($findings | Sort-Object ` @{ Expression = { switch ($_.Severity) { 'Critical' { 0 } 'High' { 1 } 'Warning' { 2 } 'Medium' { 3 } 'Low' { 4 } default { 5 } } } }, Source, Id) $nextStep = if ($compliance.ErrorCount -gt 0) { 'Some settings could not be checked. Open PowerShell with Run as Administrator (an elevated session), then run the computer checkup again.' } elseif ($compliance.NonCompliantCount -gt 0) { 'Open the safe fix assistant to review supported fixes. It will show a preview before any change can be approved.' } elseif ($health.Status -ne 'Healthy') { 'Review the items needing attention and follow the plain-language guidance before the next checkup.' } else { 'No action is required.' } $timer.Stop() [pscustomobject]@{ PSTypeName = 'EndpointForge.EndpointSummary' SchemaVersion = '1.0' ModuleVersion = [string](Get-Module EndpointForge).Version ComputerName = $inventory.ComputerName OverallStatus = $overallStatus HealthStatus = $health.Status ComplianceStatus = $complianceStatus ChecklistName = [string](Get-EFPropertyValue -InputObject $compliance -Name 'ChecklistName' -Default ( Get-EFPropertyValue -InputObject $compliance -Name 'BaselineName' -Default '' )) BaselineName = [string](Get-EFPropertyValue -InputObject $compliance -Name 'BaselineName' -Default '') ChecklistVersion = [string](Get-EFPropertyValue -InputObject $compliance -Name 'ChecklistVersion' -Default ( Get-EFPropertyValue -InputObject $compliance -Name 'BaselineVersion' -Default '' )) DataStatus = $dataStatus Score = $score HealthScore = $health.Score ComplianceScore = $compliance.Score CoveragePercent = $coveragePercent IssueCount = $actualIssueCount UnknownCount = $unknownCount IsRebootPending = $health.PendingReboot.IsRebootPending ExitCode = $exitCode OperatingSystem = $inventory.OperatingSystemName OperatingSystemBuild = $inventory.OperatingSystemBuild Model = $inventory.DeviceModel UptimeDays = $inventory.UptimeDays DiskFreePercent = $inventory.SystemDriveFreePercent Security = $security NextStep = $nextStep AutomationNextStep = if ($compliance.NonCompliantCount -gt 0) { 'Get-EFRemediationPlan' } elseif ($compliance.ErrorCount -gt 0) { 'Get-EFEndpointSummary -NoProgress' } else { $null } CorrelationId = $correlationId StartedAtUtc = [DateTime]::UtcNow.Subtract($timer.Elapsed) CompletedAtUtc = [DateTime]::UtcNow DurationMilliseconds = $timer.ElapsedMilliseconds Findings = $sortedFindings Inventory = $inventory Health = $health Compliance = $compliance } } finally { if (-not $NoProgress) { Write-Progress -Id 1100 -Activity 'EndpointForge computer checkup' -Completed } if ($timer.IsRunning) { $timer.Stop() } } } |