Public/Get-EFBaseline.ps1
|
function Get-EFBaseline { <# .SYNOPSIS Loads a built-in or file-based Windows computer checklist. .DESCRIPTION A checklist is a list of things expected to be true, such as Windows settings, storage, applications, jobs, files, certificates, recent events, local Windows management information, local network placement, or an approved network service. PowerShell commands call it a baseline for compatibility. This command only loads and validates the JSON file. It does not read a target, perform a network-active check, check a setting, or change a computer. ListAvailable shows the checklists included with the module. .PARAMETER Name The built-in checklist name. EnterpriseRecommended is the default. .PARAMETER Path The path to a custom checklist JSON file. Review custom files before use because they choose which applications, jobs, local paths, event logs, certificates, management namespaces, accounts, update services, hosts, ports, and web addresses later checks can inspect or contact. .PARAMETER ExpectedSha256 The approved SHA-256 hash for a custom checklist file. When supplied, EndpointForge reads the file once and verifies that exact byte sequence before parsing it. Hash- verified files and custom files loaded from an elevated session cannot pass through links or reparse points. .PARAMETER ListAvailable Lists information about every checklist included with the installed module. .EXAMPLE Get-EFBaseline -Name EnterpriseRecommended .EXAMPLE Get-EFBaseline -Path .\contoso-baseline.json .EXAMPLE Get-EFBaseline -ListAvailable .EXAMPLE Get-EFBaseline -Path .\checklists\Contoso.EverydayChecks.json Loads and validates an everyday-checklist file without running any of its checks. .EXAMPLE Get-EFBaseline -Path .\Contoso.json -ExpectedSha256 $approvedHash Loads the custom checklist only when its bytes match the approved SHA-256 hash. .OUTPUTS EndpointForge.Baseline or EndpointForge.BaselineInfo. .LINK New-EFBaseline .LINK Test-EFBaseline #> [CmdletBinding(DefaultParameterSetName = 'Name')] [OutputType('EndpointForge.Baseline', 'EndpointForge.BaselineInfo')] param( [Parameter(ParameterSetName = 'Name')] [ValidateNotNullOrEmpty()] [string]$Name = 'EnterpriseRecommended', [Parameter(Mandatory, ParameterSetName = 'Path')] [ValidateNotNullOrEmpty()] [string]$Path, [Parameter(ParameterSetName = 'Path')] [ValidatePattern('^[A-Fa-f0-9]{64}$')] [string]$ExpectedSha256, [Parameter(Mandatory, ParameterSetName = 'List')] [switch]$ListAvailable ) if ($ListAvailable) { foreach ($file in Get-ChildItem -LiteralPath (Join-Path $script:ModuleRoot 'Data') -Filter '*.json' -File) { if ($file.Name -in @('Baseline.schema.json', 'PublicContract.v1.json')) { continue } try { $fileContent = Read-EFBaselineFile -Path $file.FullName $item = $fileContent.Text | ConvertFrom-Json -ErrorAction Stop Assert-EFBaseline -Baseline $item [pscustomobject]@{ PSTypeName = 'EndpointForge.BaselineInfo' Name = [string]$item.Name FormatVersion = [string](Get-EFPropertyValue -InputObject $item -Name 'FormatVersion' -Default '1.0') Version = [string]$item.Version Description = [string]$item.Description ControlCount = @($item.Controls).Count Path = $file.FullName } } catch { Write-Warning "Skipping invalid built-in baseline '$($file.Name)': $($_.Exception.Message)" } } return } if ($PSCmdlet.ParameterSetName -eq 'Name') { if ($Name -notmatch '^[A-Za-z0-9._-]+$') { throw [System.ArgumentException]::new("Baseline name '$Name' contains invalid characters.") } $resolvedPath = Join-Path (Join-Path $script:ModuleRoot 'Data') "$Name.json" if (-not (Test-Path -LiteralPath $resolvedPath -PathType Leaf)) { throw [System.IO.FileNotFoundException]::new("Built-in baseline '$Name' was not found.") } } else { $resolvedPath = $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($Path) if (-not (Test-Path -LiteralPath $resolvedPath -PathType Leaf)) { throw [System.IO.FileNotFoundException]::new("Baseline file '$resolvedPath' was not found.") } } $requireDirectPath = $PSCmdlet.ParameterSetName -eq 'Path' -and ( $PSBoundParameters.ContainsKey('ExpectedSha256') -or (Test-EFAdministrator) ) $readArguments = @{ Path = $resolvedPath RequireDirectPath = $requireDirectPath } if ($PSBoundParameters.ContainsKey('ExpectedSha256')) { $readArguments.ExpectedSha256 = $ExpectedSha256 } $fileContent = Read-EFBaselineFile @readArguments try { $baseline = $fileContent.Text | ConvertFrom-Json -ErrorAction Stop } catch { throw [System.IO.InvalidDataException]::new("Baseline '$resolvedPath' is not valid JSON: $($_.Exception.Message)") } Assert-EFBaseline -Baseline $baseline if (-not (Test-EFPropertyPresent -InputObject $baseline -Name 'FormatVersion')) { $baseline | Add-Member -NotePropertyName FormatVersion -NotePropertyValue '1.0' } $baseline.PSObject.TypeNames.Insert(0, 'EndpointForge.Baseline') $baseline | Add-Member -NotePropertyName SourcePath -NotePropertyValue $resolvedPath -Force $baseline | Add-Member -NotePropertyName SourceSha256 -NotePropertyValue $fileContent.Sha256 -Force $integrityVerified = $PSCmdlet.ParameterSetName -eq 'Name' -or $PSBoundParameters.ContainsKey('ExpectedSha256') $integrityMethod = if ($PSCmdlet.ParameterSetName -eq 'Name') { 'InstalledModulePackage' } elseif ($PSBoundParameters.ContainsKey('ExpectedSha256')) { 'ExpectedSha256' } else { 'UnverifiedCustomFile' } $baseline | Add-Member -NotePropertyName IntegrityVerified -NotePropertyValue $integrityVerified -Force $baseline | Add-Member -NotePropertyName IntegrityMethod -NotePropertyValue $integrityMethod -Force $baseline | Add-Member -NotePropertyName ControlCount -NotePropertyValue @($baseline.Controls).Count -Force $baseline | Add-Member -NotePropertyName RemediableCount -NotePropertyValue @($baseline.Controls | Where-Object Remediable).Count -Force if ($integrityVerified) { Register-EFBaselineIntegrityApproval -Baseline $baseline -Method $integrityMethod } return $baseline } |