Public/Get-EFEndpointReadiness.ps1
|
function Get-EFEndpointReadiness { <# .SYNOPSIS Explains what EndpointForge can check and safely offer to fix in the current PowerShell window. .DESCRIPTION Performs a strictly read-only preflight. It checks the Windows platform, the selected checklist, administrator access, remote-session context, and whether Windows provides the commands needed by each checklist item. It does not evaluate policy settings and never changes the endpoint. EndpointForge calls its list of expected settings a baseline. In beginner-facing guidance, this command calls it a checklist: the list of Windows settings that the PC will be compared with. Selecting a checklist does not apply it. .PARAMETER Baseline The checklist to inspect. Supply the built-in name, a custom JSON path, or a validated checklist object. The default is the conservative EnterpriseRecommended checklist. .PARAMETER ControlId Limits readiness discovery to specific checklist item identifiers. .EXAMPLE Get-EFEndpointReadiness .EXAMPLE Get-EFEndpointReadiness -Baseline .\Contoso.Workstation.json .OUTPUTS EndpointForge.EndpointReadiness .LINK Get-EFEndpointSummary .LINK Get-EFRemediationPlan #> [CmdletBinding()] param( [Parameter(Position = 0)] [AllowNull()] [object]$Baseline = 'EnterpriseRecommended', [string[]]$ControlId ) $checkedAtUtc = [DateTime]::UtcNow $isWindowsPlatform = [bool](Test-EFWindows) $isAdministrator = $false if ($isWindowsPlatform) { $isAdministrator = [bool](Test-EFAdministrator) } $isRemoteSession = $false try { $senderInfo = Get-Variable -Name PSSenderInfo -ValueOnly -ErrorAction SilentlyContinue $isRemoteSession = $null -ne $senderInfo } catch { $isRemoteSession = $false } $resolvedBaseline = $null $baselineError = $null [object[]]$controls = @() try { $resolvedBaseline = Resolve-EFBaseline -Baseline $Baseline $controls = @($resolvedBaseline.Controls) if ($PSBoundParameters.ContainsKey('ControlId') -and $null -ne $ControlId -and $ControlId.Count -gt 0) { $missingIds = @($ControlId | Where-Object { $_ -notin $controls.Id }) if ($missingIds.Count -gt 0) { throw [System.ArgumentException]::new("The checklist does not contain item(s): $($missingIds -join ', ').") } $controls = @($controls | Where-Object { $_.Id -in @($ControlId) }) } } catch { $baselineError = $_.Exception.Message $resolvedBaseline = $null $controls = @() } $baselineIsValid = $null -ne $resolvedBaseline $checklistName = if ($baselineIsValid) { [string]$resolvedBaseline.Name } else { 'Unavailable' } $checklistVersion = if ($baselineIsValid) { [string]$resolvedBaseline.Version } else { $null } $capabilities = @( foreach ($control in $controls) { Get-EFControlCapability -Control $control -IsWindowsPlatform $isWindowsPlatform -IsAdministrator $isAdministrator } ) $unavailableControlCount = @($capabilities | Where-Object { -not $_.CanCheck }).Count $privilegedCheckCount = @($capabilities | Where-Object AdministratorRecommendedForCheck).Count $automaticFixCount = @($capabilities | Where-Object IsAutomaticFixDeclared).Count $availableAutomaticFixCount = @($capabilities | Where-Object AutomaticFixAvailable).Count $fixNowCount = @($capabilities | Where-Object CanFixNow).Count $assessmentReady = $isWindowsPlatform -and $baselineIsValid $completeCheckLikely = $assessmentReady -and $unavailableControlCount -eq 0 -and ($isAdministrator -or $privilegedCheckCount -eq 0) $fixReady = $assessmentReady -and $isAdministrator -and $availableAutomaticFixCount -gt 0 $limitations = [Collections.Generic.List[string]]::new() if (-not $isWindowsPlatform) { $limitations.Add('Endpoint checks require Windows 10, Windows 11, or a supported Windows Server release.') } if (-not $baselineIsValid) { $limitations.Add("The selected checklist could not be used: $baselineError") } if ($assessmentReady -and -not $isAdministrator -and $privilegedCheckCount -gt 0) { $limitations.Add("Windows may hide details for $privilegedCheckCount checklist item(s) until PowerShell is opened using Run as administrator.") } if ($assessmentReady -and -not $isAdministrator -and $automaticFixCount -gt 0) { $limitations.Add('This standard-user PowerShell window can check settings, but it cannot apply automatic fixes.') } if ($unavailableControlCount -gt 0) { $limitations.Add("Windows features needed by $unavailableControlCount checklist item(s) are unavailable in this session.") } if ($isRemoteSession) { $limitations.Add('This is a remote PowerShell session. Checks and approved fixes affect the remote PC, not the PC in front of you.') } $status = if (-not $assessmentReady) { 'Blocked' } elseif (-not $completeCheckLikely -or ($automaticFixCount -gt 0 -and -not $isAdministrator) -or $availableAutomaticFixCount -lt $automaticFixCount) { 'Limited' } else { 'Ready' } $summary = switch ($status) { 'Blocked' { 'EndpointForge cannot start this checklist until the blocked item is corrected.' } 'Limited' { 'EndpointForge can check this PC now, but some details or automatic fixes may be unavailable.' } default { 'EndpointForge is ready to check this PC. Checking only reads settings and does not change anything.' } } $nextStep = if (-not $isWindowsPlatform) { 'Run EndpointForge on the Windows PC you want to check.' } elseif (-not $baselineIsValid) { 'Choose the built-in recommended checklist or correct the custom checklist file, then run readiness again.' } elseif (-not $isAdministrator -and ($privilegedCheckCount -gt 0 -or $automaticFixCount -gt 0)) { 'You can run a check now. For the most complete result, reopen PowerShell using Run as administrator and check again.' } elseif ($unavailableControlCount -gt 0) { 'Run the check and review unavailable items. They may not apply to this Windows edition or device type.' } else { 'Run Get-EFEndpointSummary, or choose Check this PC from the guided menu.' } $checks = [Collections.Generic.List[object]]::new() $checks.Add([pscustomobject]@{ PSTypeName = 'EndpointForge.ReadinessCheck' Name = 'Windows PC' Status = if ($isWindowsPlatform) { 'Ready' } else { 'Blocked' } PlainLanguage = if ($isWindowsPlatform) { 'This PowerShell window is running on Windows.' } else { 'EndpointForge endpoint checks must run on Windows.' } NextStep = if ($isWindowsPlatform) { 'No action is needed.' } else { 'Open PowerShell on the Windows PC you want to check.' } }) $checks.Add([pscustomobject]@{ PSTypeName = 'EndpointForge.ReadinessCheck' Name = 'Checklist' Status = if ($baselineIsValid) { 'Ready' } else { 'Blocked' } PlainLanguage = if ($baselineIsValid) { "'$checklistName' is valid and contains $($controls.Count) setting check(s). A checklist is the list of expected Windows settings; selecting it does not apply changes." } else { "The selected checklist could not be read or validated: $baselineError" } NextStep = if ($baselineIsValid) { 'No action is needed.' } else { 'Choose a valid built-in checklist or custom JSON checklist file.' } }) $checks.Add([pscustomobject]@{ PSTypeName = 'EndpointForge.ReadinessCheck' Name = 'PowerShell access' Status = if ($isAdministrator) { 'Ready' } elseif ($assessmentReady) { 'Warning' } else { 'Blocked' } PlainLanguage = if ($isAdministrator) { 'PowerShell is running as Administrator. Complete checks and guarded fixes can be offered when Windows supports them.' } else { 'PowerShell is running as a standard user. Normal checks work, but Windows may hide protected details and EndpointForge will not apply fixes.' } NextStep = if ($isAdministrator) { 'No action is needed.' } else { 'Check now, or use Run as administrator if you need complete protected details or later approve a fix.' } }) $checks.Add([pscustomobject]@{ PSTypeName = 'EndpointForge.ReadinessCheck' Name = 'Windows features' Status = if (-not $assessmentReady) { 'Blocked' } elseif ($unavailableControlCount -gt 0) { 'Warning' } else { 'Ready' } PlainLanguage = if (-not $assessmentReady) { 'Windows feature discovery will begin after the platform and checklist are ready.' } elseif ($unavailableControlCount -gt 0) { "$unavailableControlCount checklist item(s) need a Windows feature that is unavailable in this session. EndpointForge will report those items instead of guessing." } else { 'The Windows commands needed by every selected checklist item are available.' } NextStep = if ($unavailableControlCount -gt 0) { 'Review ControlCapabilities for the exact unavailable feature.' } else { 'No action is needed.' } }) $checks.Add([pscustomobject]@{ PSTypeName = 'EndpointForge.ReadinessCheck' Name = 'Target PC' Status = if ($isRemoteSession) { 'Warning' } else { 'Ready' } PlainLanguage = if ($isRemoteSession) { 'This PowerShell window is connected to another PC. Every check and approved fix affects that remote PC.' } else { 'This PowerShell window is checking the local PC.' } NextStep = if ($isRemoteSession) { 'Confirm the remote computer name before approving any future change.' } else { 'No action is needed.' } }) [pscustomobject]@{ PSTypeName = 'EndpointForge.EndpointReadiness' ComputerName = if ([string]::IsNullOrWhiteSpace($env:COMPUTERNAME)) { [Environment]::MachineName } else { $env:COMPUTERNAME } CheckedAtUtc = $checkedAtUtc Status = $status AssessmentReady = $assessmentReady CompleteCheckLikely = $completeCheckLikely FixReady = $fixReady IsWindows = $isWindowsPlatform IsAdministrator = $isAdministrator IsRemoteSession = $isRemoteSession ChecklistName = $checklistName ChecklistVersion = $checklistVersion ChecklistDefinition = 'A checklist (called a baseline in automation) is the list of expected Windows settings that the PC is compared with. Selecting or checking it does not apply changes.' ControlCount = $controls.Count AvailableControlCount = $capabilities.Count - $unavailableControlCount UnavailableControlCount = $unavailableControlCount PrivilegedCheckCount = $privilegedCheckCount AutomaticFixCount = $automaticFixCount AvailableAutomaticFixCount = $availableAutomaticFixCount FixNowCount = $fixNowCount Summary = $summary NextStep = $nextStep Limitations = @($limitations) Checks = @($checks) ControlCapabilities = @($capabilities) } } |