Modules/businessdev.ALbuild.Environments/Public/New-BcEnvironment.ps1

function New-BcEnvironment {
    <#
    .SYNOPSIS
        Provisions a demo or developer Business Central environment (container) with Traefik routing (licensed).
 
    .DESCRIPTION
        Creates a Business Central container tagged with environment metadata labels (expiry, owner,
        type) for label-based lifecycle management, and produces a Traefik v3 dynamic configuration
        routing to it (Subdomain or PathPrefix). Requires Windows + Docker and a valid ALbuild
        license.
 
    .PARAMETER Name
        Environment / container name.
 
    .PARAMETER Domain
        Base domain for Traefik routing (e.g. businesscentral.example.com).
 
    .PARAMETER Credential
        Container admin credential.
 
    .PARAMETER ArtifactUrl
        The BC artifact URL. If omitted, resolved from -Type/-Country/-Version.
 
    .PARAMETER Type
        Artifact type when resolving: Sandbox (default) or OnPrem.
 
    .PARAMETER Country
        Artifact country. Default 'w1'.
 
    .PARAMETER Version
        Optional artifact version.
 
    .PARAMETER Routing
        Traefik routing mode: Subdomain (default) or PathPrefix.
 
    .PARAMETER EnvironmentType
        Demo (default) or Development.
 
    .PARAMETER ExpiresInDays
        Lifetime in days (used for the expiry label). Default 7.
 
    .PARAMETER OwnerEmail
        Owner email recorded as a label.
 
    .PARAMETER TraefikConfigFolder
        Folder to write the Traefik dynamic configuration to. Default: ./traefik.
 
    .PARAMETER DockerExecutable
        The Docker executable to use (default 'docker').
 
    .OUTPUTS
        PSCustomObject describing the environment (Name, Url, ExpiresAt, Container, TraefikConfig).
    #>

    [CmdletBinding(SupportsShouldProcess)]
    [OutputType([PSCustomObject])]
    param(
        [Parameter(Mandatory)] [ValidateNotNullOrEmpty()] [string] $Name,
        [Parameter(Mandatory)] [ValidateNotNullOrEmpty()] [string] $Domain,
        [Parameter(Mandatory)] [pscredential] $Credential,
        [string] $ArtifactUrl,
        [ValidateSet('Sandbox', 'OnPrem')] [string] $Type = 'Sandbox',
        [string] $Country = 'w1',
        [string] $Version = '',
        [ValidateSet('Subdomain', 'PathPrefix')] [string] $Routing = 'Subdomain',
        [ValidateSet('Demo', 'Development')] [string] $EnvironmentType = 'Demo',
        [int] $ExpiresInDays = 7,
        [string] $OwnerEmail = '',
        [string] $TraefikConfigFolder = (Join-Path (Get-Location) 'traefik'),
        [string] $DockerExecutable = 'docker'
    )

    Assert-ALbuildLicensed -Feature 'Environments'

    if (-not $ArtifactUrl) {
        $ArtifactUrl = Find-BcArtifactUrl -Type $Type -Country $Country -Version $Version -Select Latest
        if (-not $ArtifactUrl) { throw 'Could not resolve an artifact URL.' }
    }

    $expiresAt = (Get-Date).AddDays($ExpiresInDays).ToUniversalTime().ToString('o')
    $url = if ($Routing -eq 'Subdomain') { "https://$Name.$Domain" } else { "https://$Domain/$Name" }
    $labels = @{
        'albuild.environment'     = 'true'
        'albuild.expiresAt'       = $expiresAt
        'albuild.owner'           = $OwnerEmail
        'albuild.environmentType' = $EnvironmentType
        'albuild.publicUrl'       = $url
    }
    $auth = if ($EnvironmentType -eq 'Development') { 'AAD' } else { 'UserPassword' }

    if (-not $PSCmdlet.ShouldProcess($Name, "Provision $EnvironmentType environment")) { return }

    $container = New-BcContainer -Name $Name -ArtifactUrl $ArtifactUrl -Credential $Credential -Auth $auth `
        -Labels $labels -DockerExecutable $DockerExecutable

    $traefikConfig = Publish-BcContainerToTraefik -Name $Name -Domain $Domain -Routing $Routing `
        -OutputPath (Join-Path $TraefikConfigFolder "$Name.json")

    Write-ALbuildLog -Level Success "Provisioned $EnvironmentType environment '$Name' at $url (expires $expiresAt)."

    return [PSCustomObject]@{
        Name          = $Name
        Url           = $url
        ExpiresAt     = $expiresAt
        Type          = $EnvironmentType
        Container     = $container
        TraefikConfig = $traefikConfig
    }
}