Public/Get-EFBaseline.ps1

function Get-EFBaseline {
    <#
    .SYNOPSIS
    Loads a built-in or file-based Windows settings checklist.
 
    .DESCRIPTION
    A checklist is a list of Windows settings and their expected values. PowerShell
    commands call it a baseline for compatibility. This command loads and validates the
    JSON file; it does not check 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.
 
    .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
 
    .OUTPUTS
    EndpointForge.Baseline or EndpointForge.BaselineInfo.
 
    .LINK
    New-EFBaseline
 
    .LINK
    Test-EFBaseline
    #>

    [CmdletBinding(DefaultParameterSetName = 'Name')]
    param(
        [Parameter(ParameterSetName = 'Name')]
        [ValidateNotNullOrEmpty()]
        [string]$Name = 'EnterpriseRecommended',

        [Parameter(Mandatory, ParameterSetName = 'Path')]
        [ValidateNotNullOrEmpty()]
        [string]$Path,

        [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 -eq 'Baseline.schema.json') {
                continue
            }
            try {
                $item = Get-Content -LiteralPath $file.FullName -Raw -Encoding UTF8 | ConvertFrom-Json -ErrorAction Stop
                Assert-EFBaseline -Baseline $item
                [pscustomobject]@{
                    PSTypeName   = 'EndpointForge.BaselineInfo'
                    Name         = [string]$item.Name
                    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.")
        }
    }

    try {
        $baseline = Get-Content -LiteralPath $resolvedPath -Raw -Encoding UTF8 | ConvertFrom-Json -ErrorAction Stop
    }
    catch {
        throw [System.IO.InvalidDataException]::new("Baseline '$resolvedPath' is not valid JSON: $($_.Exception.Message)")
    }

    Assert-EFBaseline -Baseline $baseline
    $baseline.PSObject.TypeNames.Insert(0, 'EndpointForge.Baseline')
    $baseline | Add-Member -NotePropertyName SourcePath -NotePropertyValue $resolvedPath -Force
    $baseline | Add-Member -NotePropertyName ControlCount -NotePropertyValue @($baseline.Controls).Count -Force
    $baseline | Add-Member -NotePropertyName RemediableCount -NotePropertyValue @($baseline.Controls | Where-Object Remediable).Count -Force
    return $baseline
}