Public/Get-CIEMCheck.ps1

function Get-CIEMCheck {
    <#
    .SYNOPSIS
        Lists available CIEM security checks.

    .DESCRIPTION
        Dynamically discovers security checks from per-provider directories under the
        configured checksPath (e.g., Checks/Azure/, Checks/Aws/). Each provider directory
        is scanned for *.metadata.json files which are parsed into CIEMCheck objects.

    .PARAMETER CloudProvider
        Filter checks by cloud provider (Azure, AWS).

    .PARAMETER Service
        Filter checks by service name (e.g., Entra, IAM, KeyVault, Storage, iam, s3).

    .PARAMETER Severity
        Filter checks by severity level (critical, high, medium, low).

    .PARAMETER CheckId
        Filter to a specific check by ID.

    .OUTPUTS
        [CIEMCheck[]] Array of CIEMCheck objects.

    .EXAMPLE
        Get-CIEMCheck
        # Returns all checks across all providers

    .EXAMPLE
        Get-CIEMCheck -CloudProvider AWS
        # Returns all AWS checks

    .EXAMPLE
        Get-CIEMCheck -Service Entra -Severity high
        # Returns high-severity Entra checks

    .EXAMPLE
        Get-CIEMCheck -CheckId 'entra_security_defaults_enabled'
        # Returns specific check details
    #>

    [CmdletBinding()]
    [OutputType([CIEMCheck[]])]
    param(
        [Parameter()]
        [ValidateSet('Azure', 'AWS')]
        [string]$CloudProvider,

        [Parameter()]
        [string]$Service,

        [Parameter()]
        [ValidateSet('critical', 'high', 'medium', 'low')]
        [string]$Severity,

        [Parameter()]
        [string]$CheckId
    )

    $ErrorActionPreference = 'Stop'

    $checksRoot = Join-Path $script:ModuleRoot $script:Config.checksPath
    $checks = [System.Collections.Generic.List[CIEMCheck]]::new()

    # Map of directory name → CIEMCloudProvider enum value
    $providerMap = @{
        'Azure' = [CIEMCloudProvider]::Azure
        'Aws'   = [CIEMCloudProvider]::AWS
    }

    if (Test-Path $checksRoot) {
        $providerDirs = @(Get-ChildItem -Path $checksRoot -Directory -ErrorAction SilentlyContinue)

        foreach ($providerDir in $providerDirs) {
            if (-not $providerMap.ContainsKey($providerDir.Name)) {
                Write-Verbose "Skipping unknown provider directory: $($providerDir.Name)"
                continue
            }
            $providerEnum = $providerMap[$providerDir.Name]

            # Scan for *.metadata.json files
            $metadataFiles = @(Get-ChildItem -Path $providerDir.FullName -Filter '*.metadata.json' -Recurse -ErrorAction SilentlyContinue)

            foreach ($metaFile in $metadataFiles) {
                try {
                    $jsonObj = Get-Content $metaFile.FullName -Raw | ConvertFrom-Json
                    $check = [CIEMCheck]::FromJsonObject($jsonObj, $providerEnum)
                    $checks.Add($check)
                }
                catch {
                    Write-Verbose "Failed to parse $($metaFile.FullName): $_"
                }
            }
        }
    }

    # Apply filters
    $result = $checks.ToArray()

    if ($CloudProvider) {
        $result = $result | Where-Object { $_.CloudProvider -eq $CloudProvider }
    }

    if ($Service) {
        $result = $result | Where-Object { $_.Service -eq $Service }
    }

    if ($Severity) {
        $result = $result | Where-Object { $_.Severity -eq $Severity }
    }

    if ($CheckId) {
        $result = $result | Where-Object { $_.Id -eq $CheckId }
    }

    $result
}