Public/Health/Add-KrHealthProbe.ps1

<#
    .SYNOPSIS
        Registers a script-based health probe with the active Kestrun server.
    .DESCRIPTION
        Wraps the Kestrun host AddProbe overload that accepts script content. You can provide inline
        PowerShell via the -ScriptBlock parameter set, inline code tied to an explicit language, or
        the path to a script file. Optional arguments, imports, references, and tag metadata can be
        supplied to influence probe execution and filtering.
    .PARAMETER Server
        The Kestrun host instance to configure. If omitted, the current server context is resolved automatically.
    .PARAMETER Name
        Unique name for the probe.
    .PARAMETER Tags
        Optional set of tags used to include or exclude the probe when requests filter by tag.
    .PARAMETER ScriptBlock
        Inline PowerShell that returns a ProbeResult (or equivalent contract). This is the default parameter set.
    .PARAMETER Code
        Inline code interpreted in the language supplied via -Language.
    .PARAMETER Language
        Script language for inline code or script files. When registering a script block the language defaults to PowerShell.
    .PARAMETER CodePath
        Path to a script file. The file is read once at registration time.
    .PARAMETER Arguments
        Hashtable of values exposed to the probe at execution time.
    .PARAMETER ExtraImports
        Additional language-specific imports (namespaces) supplied to Roslyn-based probes.
    .PARAMETER ExtraRefs
        Additional assemblies referenced by Roslyn-based probes.
    .PARAMETER PassThru
        Emits the configured server instance so the call can be chained.
    .EXAMPLE
        Add-KrHealthProbe -Name SelfCheck -Tags 'core' -ScriptBlock {
            return [Kestrun.Health.ProbeResult]::new([Kestrun.Health.ProbeStatus]::Healthy, 'Service ready')
        }
        Registers a PowerShell health probe named SelfCheck tagged with 'core'.
    .EXAMPLE
        Add-KrHealthProbe -Name Database -Language CSharp -Code @"
            return await ProbeAsync();
        "@
        Registers an inline C# health probe.
    .EXAMPLE
        Add-KrHealthProbe -Name Cache -CodePath './Scripts/CacheProbe.cs' -Language CSharp -ExtraImports 'System.Net'
        Registers a C# health probe from a script file and adds an extra namespace import.
#>

function Add-KrHealthProbe {
    [KestrunRuntimeApi('Definition')]
    [CmdletBinding(DefaultParameterSetName = 'ScriptBlock')]
    [OutputType([Kestrun.Hosting.KestrunHost])]
    param(
        [Parameter(ValueFromPipeline = $true)]
        [Kestrun.Hosting.KestrunHost]$Server,

        [Parameter(Mandatory = $true)]
        [string]$Name,

        [string[]]$Tags,

        [Parameter(Mandatory = $true, Position = 0, ParameterSetName = 'ScriptBlock')]
        [scriptblock]$ScriptBlock,

        [Parameter(Mandatory = $true, ParameterSetName = 'Code')]
        [string]$Code,

        [Parameter(Mandatory = $true, ParameterSetName = 'Code')]
        [Parameter(ParameterSetName = 'File')]
        [Kestrun.Scripting.ScriptLanguage]$Language,

        [Parameter(Mandatory = $true, ParameterSetName = 'File')]
        [string]$CodePath,

        [hashtable]$Arguments,

        [string[]]$ExtraImports,

        [System.Reflection.Assembly[]]$ExtraRefs,

        [switch]$PassThru
    )
    begin {
        $Server = Resolve-KestrunServer -Server $Server
        if ($null -eq $Server) {
            throw 'Server is not initialized. Call New-KrServer first or pipe an existing host instance.'
        }
    }
    process {
        $codeToRegister = $null
        [Kestrun.Scripting.ScriptLanguage]$effectiveLanguage = [Kestrun.Scripting.ScriptLanguage]::PowerShell

        switch ($PSCmdlet.ParameterSetName) {
            'ScriptBlock' {
                $codeToRegister = $ScriptBlock.ToString()
                $effectiveLanguage = [Kestrun.Scripting.ScriptLanguage]::PowerShell
            }
            'Code' {
                $codeToRegister = $Code
                $effectiveLanguage = $Language
            }
            'File' {
                if (-not (Test-Path -LiteralPath $CodePath)) {
                    throw "The specified code path '$CodePath' does not exist. Ensure the file exists and the path is correct."
                }
                $codeToRegister = Get-Content -LiteralPath $CodePath -Raw
                if ($PSBoundParameters.ContainsKey('Language')) {
                    $effectiveLanguage = $Language
                } else {
                    $extension = [System.IO.Path]::GetExtension($CodePath).ToLowerInvariant()
                    $effectiveLanguage = switch ($extension) {
                        '.ps1' { [Kestrun.Scripting.ScriptLanguage]::PowerShell }
                        '.cs' { [Kestrun.Scripting.ScriptLanguage]::CSharp }
                        '.vb' { [Kestrun.Scripting.ScriptLanguage]::VBNet }
                        default {
                            throw "Cannot infer script language from extension '$extension'. Specify -Language explicitly."
                        }
                    }
                }
            }
            default {
                throw "Unsupported parameter set '$($PSCmdlet.ParameterSetName)'."
            }
        }

        if ([string]::IsNullOrWhiteSpace($codeToRegister)) {
            throw 'Probe code cannot be empty.'
        }

        $normalizedTags = $null
        if ($PSBoundParameters.ContainsKey('Tags')) {
            $normalizedTags = @($Tags | Where-Object { -not [string]::IsNullOrWhiteSpace($_) } | ForEach-Object { $_.Trim() })
            if ($normalizedTags.Count -eq 0) {
                $normalizedTags = $null
            }
        }

        $argDictionary = $null
        if ($PSBoundParameters.ContainsKey('Arguments') -and $Arguments) {
            $argDictionary = [System.Collections.Generic.Dictionary[string, object]]::new()
            foreach ($key in $Arguments.Keys) {
                $argDictionary[$key] = $Arguments[$key]
            }
        }

        $imports = $null
        if ($PSBoundParameters.ContainsKey('ExtraImports')) {
            $imports = @($ExtraImports | Where-Object { -not [string]::IsNullOrWhiteSpace($_) } | ForEach-Object { $_.Trim() })
            if ($imports.Count -eq 0) {
                $imports = $null
            }
        }

        try {
            $hostResult = $Server.AddProbe($Name, $normalizedTags, $codeToRegister, $effectiveLanguage, $argDictionary, $imports, $ExtraRefs)
            Write-KrLog -Level Information -Message "Health probe '{0}' registered." -Values $Name
            if ($PassThru.IsPresent) {
                return $hostResult
            }
        } catch {
            Write-KrLog -Level Error -Message "Failed to register health probe '{0}'." -Values $Name -ErrorRecord $_
            throw
        }
    }
}