Modules/businessdev.ALbuild.Containers/Public/Remove-BcImage.ps1

function Remove-BcImage {
    <#
    .SYNOPSIS
        Removes a cached version-specific Business Central image.
 
    .DESCRIPTION
        Refuses while any container still references the image. Docker would refuse too, but with a
        message about image ids that says nothing about which build is affected - and the caller here is
        usually an automated cache trim, where a clear refusal is worth more than a forced removal.
 
        The usage marker is deleted with the image so a rebuilt image starts with a fresh timestamp
        rather than inheriting the old one and being evicted first.
 
    .PARAMETER ImageName
        The image tag to remove.
 
    .PARAMETER DockerExecutable
        Docker executable.
 
    .OUTPUTS
        PSCustomObject: ImageName, Removed.
    #>

    [CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'High')]
    [OutputType([PSCustomObject])]
    param(
        [Parameter(Mandatory, ValueFromPipeline)] [ValidateNotNullOrEmpty()] [string] $ImageName,
        [string] $DockerExecutable = 'docker'
    )

    process {
        $ps = Invoke-BcDocker -DockerExecutable $DockerExecutable -Quiet -PassThru -SuccessExitCodes @(0, 1) `
            -Arguments @('ps', '-a', '--filter', "ancestor=$ImageName", '--format', '{{.Names}}')
        $users = @("$($ps.StdOut)" -split "`r?`n" | Where-Object { -not [string]::IsNullOrWhiteSpace($_) })
        if ($users.Count -gt 0) {
            throw "Image '$ImageName' is still used by container(s): $($users -join ', '). Remove those first."
        }

        if (-not $PSCmdlet.ShouldProcess($ImageName, 'Remove cached BC image')) {
            return [PSCustomObject]@{ ImageName = $ImageName; Removed = $false }
        }

        Invoke-BcDocker -DockerExecutable $DockerExecutable -Quiet -Arguments @('rmi', $ImageName) | Out-Null
        $marker = Get-BcImageUsageMarkerPath -ImageName $ImageName
        if (Test-Path -LiteralPath $marker) { Remove-Item -LiteralPath $marker -Force -ErrorAction SilentlyContinue }

        return [PSCustomObject]@{ ImageName = $ImageName; Removed = $true }
    }
}