Security change on December 1, 2026: TLS 1.2 will become the minimum standard for 365 business Print Agent. Details and system requirements
365 business development
PowerShell Module

Containers module

Module: businessdev.ALbuild.Containers  •  Tier: Free  •  Cmdlets: 32

The Containers module manages the full Business Central Docker container lifecycle without any dependency on BcContainerHelper — artifact discovery and download, container create/start/stop/restart/remove, users, the test toolkit, configuration packages, Traefik reverse-proxy publishing and self-signed certificate trust. Container operations require a Windows host with a running Docker engine.

Cmdlets in this module

CmdletDescription
Enter-BcContainerOpens an interactive PowerShell session inside a Business Central container.
Find-BcArtifactUrlFinds Business Central artifact URLs from the public artifact indexes.
Get-BcArtifactDownloads and caches a Business Central artifact (application + platform packages).
Get-BcArtifactSymbolFolderReturns the symbol (package cache) folders a host AL compile needs from a downloaded BC artifact.
Get-BcArtifactVersionParses the type, version and country out of a Business Central artifact URL.
Get-BcContainerLists Business Central (Docker) containers, optionally filtered by name.
Get-BcContainerAppFileInfoReads the real identity (app id / name / publisher / version) of one or more .app files by asking the build container, for packages the host cannot read itself.
Get-BcContainerAppInfoReturns the apps installed/published in a Business Central container, with versions.
Get-BcContainerWebClientUrlResolves the reachable Web Client URL of a Business Central container.
Get-BcDockerDataRootWhere Docker stores its images and container layers, and whether that place is a good one.
Get-BcImageLists the cached version-specific Business Central images on this host.
Import-BcConfigurationPackageImports a RapidStart (.rapidstart) configuration package into a Business Central container.
Install-BcContainerTestToolkitPublishes and installs the Business Central test toolkit apps into a container.
Invoke-BcContainerCommandRuns a PowerShell script block inside a running Business Central (Windows) container.
Invoke-BcDockerRuns a Docker CLI command for ALbuild (the central Docker entry point).
New-BcContainerCreates a Business Central Docker container from an artifact.
New-BcContainerUserCreates a Business Central user inside a container.
New-BcImageBuilds a version-specific Business Central image with the artifact already installed.
Optimize-BcImageCacheTrims the cached Business Central images to a size budget, least-recently-used first.
Publish-BcContainerToTraefikProduces a Traefik v3 dynamic configuration that routes traffic to a BC container.
Register-BcContainerCertificateTrusts a BC container's self-signed TLS certificate for the current user.
Remove-BcContainerRemoves a Business Central container (and its anonymous volumes).
Remove-BcImageRemoves a cached version-specific Business Central image.
Resolve-BcContainerHostShareReturns the host folder actually bind-mounted to C:\run\my in a container (with a fallback).
Restart-BcContainerRestarts a Business Central container and waits for it to become ready.
Set-BcContainerServerConfigSets Business Central server configuration keys inside a container and restarts the instance.
Set-BcDockerDataRootMoves Docker's data root to another drive, with a full preflight and an automatic rollback.
Start-BcContainerStarts a stopped Business Central container.
Stop-BcContainerStops a running Business Central container.
Test-BcDockerReports whether the Docker CLI is installed and its daemon is reachable.
Unregister-BcContainerCertificateRemoves a BC container's certificate that ALbuild trusted for the current user.
Wait-BcContainerReadyWaits for a Business Central container to report that it is ready for connections.

Enter-BcContainer

Opens an interactive PowerShell session inside a Business Central container.

The equivalent of BcContainerHelper's Enter-BcContainer / Open-BcContainer: a prompt inside the container, for the times when you need to look rather than automate - reading a service tier log, checking what a failed install actually left behind, running Get-NAVAppInfo by hand.

WHY THIS IS NOT Invoke-BcContainerCommand Invoke-BcContainerCommand captures stdout and stderr, which is exactly right for automation and exactly wrong for a session: a captured stream draws no prompt and accepts no keystrokes. This hands the console to 'docker exec -it' and gets out of the way, so the exit code you see is the shell's own.

The in-container host is resolved by Get-BcContainerPowerShellExe, so this lands on the shell that can actually load the BC management cmdlets - 'powershell' up to BC28, 'pwsh' from BC29, where the Windows PowerShell compatibility layer was removed.

Refuses to start without a terminal. 'docker exec -it' on a redirected stdin either fails with "the input device is not a TTY" or waits forever, and a pipeline job that hangs on an interactive prompt is far worse than one that says why it cannot run - so this checks first and points at Invoke-BcContainerCommand instead.

Syntax

PowerShellCode
Enter-BcContainer -Name <String> [-Command <String>] [-WorkingDirectory <String>] [-PowerShellExe <String>] [-SkipPrompt] [-DockerExecutable <String>]

Parameters

ParameterTypeRequiredDescription
-NameStringYesThe container to enter.
-CommandStringNoA command to run before the prompt appears. The session stays open afterwards.
-WorkingDirectoryStringNoWhere the session starts. Default 'C:\run', which is where the generic image keeps its scripts. Default: 'C:\run'.
-PowerShellExeStringNoPin the in-container shell instead of letting Get-BcContainerPowerShellExe choose it. Allowed values: powershell, pwsh.
-SkipPromptswitchNoDo not dot-source the image's C:\Run\prompt.ps1. Use it when that script gets in the way.
-DockerExecutableStringNoThe Docker executable to use. Default 'docker'. Default: 'docker'.

Output

None. The exit code of the in-container shell is left in $LASTEXITCODE.

Examples

Example 1

PowerShellCode
Enter-BcContainer -Name bcserver A prompt inside 'bcserver', in C:\run, with the image's prompt loaded.

Example 2

PowerShellCode
Enter-BcContainer -Name bcserver -Command 'Get-NAVAppInfo -ServerInstance BC' Runs the command, then leaves the session open to keep looking.

Example 3

PowerShellCode
Open-BcContainer bcserver The BcContainerHelper name, kept as an alias.

Find-BcArtifactUrl

Finds Business Central artifact URLs from the public artifact indexes.

Queries the Business Central artifact storage indexes (https://bcartifacts-exdbf9fwegejdqak.b02.azurefd.net/&#123;type}/indexes) and returns matching artifact URLs of the form https://.../{type}/{version}/{country}. This is the cross-platform basis for creating containers and for resolving the platform/application baseline.

Syntax

PowerShellCode
Find-BcArtifactUrl [-Type <String>] [-Country <String>] [-Version <String>] [-Select <String>] [-StorageAccount <String>] [-AcceptInsiderEula] [-DoNotCheckPlatform]

Parameters

ParameterTypeRequiredDescription
-TypeStringNoOnPrem or Sandbox (default Sandbox). Allowed values: OnPrem, Sandbox. Default: 'Sandbox'.
-CountryStringNoLocalisation (e.g. w1, de, us). Empty queries all countries.
-VersionStringNoVersion or version prefix to match (e.g. '25', '25.1', '25.1.12345.0').
-SelectStringNoSelection strategy: Latest (default), First, All, Closest, SecondToLastMajor, Current, NextMinor, NextMajor. Allowed values: Latest, First, All, Closest, SecondToLastMajor, Current, NextMinor, NextMajor. Default: 'Latest'.
-StorageAccountStringNoOverride the storage account (advanced; default bcartifacts).
-AcceptInsiderEulaswitchNoRequired to query insider artifacts (NextMinor/NextMajor), confirming acceptance of the Business Central Insider EULA (https://go.microsoft.com/fwlink/?linkid=2245051).
-DoNotCheckPlatformswitchNoSkip confirming that a matching platform build exists in the index.

Output

System.String (one or more artifact URLs).

Examples

Example 1

PowerShellCode
Find-BcArtifactUrl -Type Sandbox -Country w1 -Select Latest

Example 2

PowerShellCode
Find-BcArtifactUrl -Type OnPrem -Country de -Version 25.1

Get-BcArtifact

Downloads and caches a Business Central artifact (application + platform packages).

Downloads the application package for the given artifact URL and, unless suppressed, the matching platform package (the same URL with the country replaced by 'platform'). Each package is a ZIP; it is extracted into the artifact cache and reused on subsequent calls.

Syntax

PowerShellCode
Get-BcArtifact -ArtifactUrl <String> [-CacheFolder <String>] [-IncludePlatform <Boolean>] [-Force]

Parameters

ParameterTypeRequiredDescription
-ArtifactUrlStringYesThe artifact URL (see Find-BcArtifactUrl).
-CacheFolderStringNoRoot cache folder. Defaults to the configured ArtifactCacheFolder.
-IncludePlatformBooleanNoAlso download/extract the platform package. Default: $true. Default: $true.
-ForceswitchNoRe-download even if a cached copy exists.

Output

PSCustomObject with ApplicationPath, PlatformPath, Version, Country.

Examples

Example 1

PowerShellCode
Get-BcArtifact -ArtifactUrl (Find-BcArtifactUrl -Country w1 -Select Latest)

Get-BcArtifactSymbolFolder

Returns the symbol (package cache) folders a host AL compile needs from a downloaded BC artifact.

Collects every folder of a Get-BcArtifact result that provides compiled first-party symbols for a host (AL Tool) compile, in one place instead of each caller re-deriving the layout:

  • '<application>/Extensions' - first-party app symbols shipped with the country artifact.
  • '<application>/Applications.<COUNTRY>' - the compiled country apps INCLUDING the test toolkit (Tests-TestLibraries, Library Assert, Test Runner, ...). Localized artifacts only.
  • the platform folder holding 'System.app' - the AL system/runtime symbols.

The W1 artifact ships no 'Applications.W1' folder - its compiled test toolkit lives scattered through the PLATFORM artifact instead ('Applications/TestFramework/**', 'Applications/BaseApp/Test', 'Applications/System Application/Test', ...). Without it, compiling a test app against W1 fails with AL1022 ('Tests-TestLibraries ... could not be found'). So when the country artifact has no 'Applications.*' folder, the platform's apps are staged once into '.albuild-toolkit-symbols' beside the platform artifact and that folder is returned too (keyed to the artifact version, so it is reused across builds). Staging is serialised on the artifact cache lock and published by an atomic rename, so a concurrent build never sees a half-copied symbol folder:

  • W1 sandbox (an 'Extensions' folder IS present): only the test toolkit is missing - stage just those apps (paths matching 'TestFramework', a 'Test' segment, or a 'Test Library' name).
  • On-premises (NO 'Extensions' and NO 'Applications.<country>'): the platform 'Applications' tree is the only source of first-party symbols, so stage them ALL (the business apps Application / Base Application / Business Foundation under '<App>/Source', plus the toolkit), or the host compile fails with AL1022 for 'Microsoft Application' / 'Base Application'.

Syntax

PowerShellCode
Get-BcArtifactSymbolFolder -Artifact <Object> [-Force]

Parameters

ParameterTypeRequiredDescription
-ArtifactObjectYesThe artifact object returned by Get-BcArtifact (ApplicationPath / PlatformPath).
-ForceswitchNoRe-stage the W1 toolkit symbols even when the staging folder already exists.

Output

System.String[] - existing folders, ready for the compiler's package cache path.

Examples

Example 1

PowerShellCode
$artifact = Get-BcArtifact -ArtifactUrl $url $symbols = Get-BcArtifactSymbolFolder -Artifact $artifact Invoke-BcCompiler -ProjectFolder .\app -PackageCachePath (@('.alpackages') + $symbols)

Get-BcArtifactVersion

Parses the type, version and country out of a Business Central artifact URL.

Syntax

PowerShellCode
Get-BcArtifactVersion -ArtifactUrl <String>

Parameters

ParameterTypeRequiredDescription
-ArtifactUrlStringYesAn artifact URL of the form https://.../{type}/{version}/{country}.

Output

PSCustomObject with Type, Version ([version]), Country, Url.

Examples

Example 1

PowerShellCode
Get-BcArtifactVersion 'https://bcartifacts-exdbf9fwegejdqak.b02.azurefd.net/sandbox/25.1.12345.0/w1'

Get-BcContainer

Lists Business Central (Docker) containers, optionally filtered by name.

Syntax

PowerShellCode
Get-BcContainer [-Name <String>] [-DockerExecutable <String>]

Parameters

ParameterTypeRequiredDescription
-NameStringNoOptional exact container name to filter by.
-DockerExecutableStringNoThe Docker executable to use (default 'docker'). Default: 'docker'.

Output

PSCustomObject with Name, Status, Image, Id, Running.

Examples

Example 1

PowerShellCode
Get-BcContainer Get-BcContainer -Name bld

Get-BcContainerAppFileInfo

Reads the real identity (app id / name / publisher / version) of one or more .app files by asking the build container, for packages the host cannot read itself.

A committed encrypted BC runtime package has no host-readable ZIP payload, so its app id can not be extracted on the agent (Expand-BcAppFile throws, and the id is not recoverable from the file header). The container, however, decrypts the manifest: 'Get-NAVAppInfo -Path' returns the real identity. This copies the .app file(s) into the container's C:\run\my share and reads them there, so a locally-served runtime dependency can be pinned by its ACTUAL app id (matching the consuming app.json 'dependencies') instead of relying on a '{Publisher}{Name}{Version}.app' file-name convention.

Syntax

PowerShellCode
Get-BcContainerAppFileInfo -ContainerName <String> -Path <String[]> [-DockerExecutable <String>]

Parameters

ParameterTypeRequiredDescription
-ContainerNameStringYesThe build container to read through (its C:\run\my share is used to hand the files across).
-PathString[]YesOne or more .app file paths on the host.
-DockerExecutableStringNoDefault: 'docker'.

Output

For each readable file, a PSCustomObject with Id, Name, Publisher, Version and File (the original host path). Files the container cannot read are omitted.


Get-BcContainerAppInfo

Returns the apps installed/published in a Business Central container, with versions.

Runs Get-NAVAppInfo inside the container and returns the result as objects. The version information (including Microsoft first-party apps such as System Application and Base Application) is what the dependency resolver uses as the pinned baseline for a build.

Syntax

PowerShellCode
Get-BcContainerAppInfo -Name <String> [-ServerInstance <String>] [-Tenant <String>] [-DockerExecutable <String>]

Parameters

ParameterTypeRequiredDescription
-NameStringYesContainer name.
-ServerInstanceStringNoBC server instance inside the container. Default 'BC'. Default: 'BC'.
-TenantStringNoTenant to query for tenant-specific (installed) information. Default 'default'. Default: 'default'.
-DockerExecutableStringNoThe Docker executable to use (default 'docker'). Default: 'docker'.

Output

PSCustomObject with Name, Publisher, Version, AppId, IsInstalled.


Get-BcContainerWebClientUrl

Resolves the reachable Web Client URL of a Business Central container.

Returns the URL an external browser (e.g. the OpenClaw Playwright agent on another host) can use to open the container's Web Client, together with the protocol, IP and port. The URL is built IP-based (not DNS/name-based) so it resolves from any host on the LAN - a container on a transparent Docker network has its own DHCP LAN IP, and even a default (NAT) container's IP is stable on the Docker host.

The container IP is read via 'docker inspect' (the same pattern as Publish-BcContainerApp). The protocol is taken from -Protocol if given (the caller created the container and knows it), otherwise from the 'albuild.protocol' label stamped by New-BcContainer, defaulting to https (the BC generic image's default). Default Web Client ports (80 http / 443 https) are omitted from the URL.

Syntax

PowerShellCode
Get-BcContainerWebClientUrl -Name <String> [-Protocol <String>] [-ServerInstance <String>] [-Tenant <String>] [-DockerExecutable <String>]

Parameters

ParameterTypeRequiredDescription
-NameStringYesContainer name.
-ProtocolStringNo'http' or 'https'. Empty = read the 'albuild.protocol' label, else default to 'https'. Allowed values: ``, http, https.
-ServerInstanceStringNoBC server instance (the Web Client path segment). Default 'BC' (the generic image default). Default: 'BC'.
-TenantStringNoThe tenant appended to the URL as '?tenant=<tenant>'. Default 'default' (the single-tenant container tenant). Empty = omit the tenant query. Default: 'default'.
-DockerExecutableStringNoThe Docker executable to use (default 'docker'). Default: 'docker'.

Output

PSCustomObject with Url, Protocol, Ip, Port - or $null when no container IP could be resolved (e.g. the container is not running yet).


Get-BcDockerDataRoot

Where Docker stores its images and container layers, and whether that place is a good one.

On a build server this one directory decides how much can be cached and how many containers can run. A BC container copies the service tier, the web client and the apps into its writable layer and restores the demo database there - many GB each - so a Docker root on the system drive is the usual reason a container dies with a cryptic "Failed to start service" after a long wait.

This reports the current root, what daemon.json actually says (which is not the same question - an absent setting means the built-in default), the service that owns it, the volume's properties, and how much would have to be pulled again after a move. Read-only: it changes nothing.

Use Set-BcDockerDataRoot to move it.

Syntax

PowerShellCode
Get-BcDockerDataRoot [-DockerExecutable <String>] [-ConfigPath <String>]

Parameters

ParameterTypeRequiredDescription
-DockerExecutableStringNoThe Docker executable to query. Default 'docker'. Default: 'docker'.
-ConfigPathStringNoThe daemon configuration file. Defaults to the standard Windows location. Default: (Join-Path $env:ProgramData 'Docker\config\daemon.json').

Output

PSCustomObject with Path, ConfiguredPath, IsDefault, ConfigPath, ServiceName, ServiceStatus, IsDockerDesktop, Drive, FileSystem, DriveType, FreeGb, TotalGb, DeduplicationEnabled, ContainerCount, ImageCount, Warnings.

Examples

Example 1

PowerShellCode
Get-BcDockerDataRoot | Format-List

Example 2

PowerShellCode
(Get-BcDockerDataRoot).Warnings Just the reasons this host's Docker root is a poor place to keep an image cache.

Get-BcImage

Lists the cached version-specific Business Central images on this host.

Reports the images New-BcImage built, identified by the 'albuild.image=bc' label rather than by a name pattern, so an image is never mistaken for one of ours because its tag happened to match.

LastUsedUtc comes from a marker file per image under the ALbuild base folder. Docker records when an image was created but not when it was last used, and creation time is a poor proxy for a cache like this one: an image is built once and then reused for months, so evicting by age would throw out precisely the versions that are being asked for most. A file per image - rather than one shared index - means concurrent workers never need to coordinate a read-modify-write.

Syntax

PowerShellCode
Get-BcImage [-ImageName <String>] [-DockerExecutable <String>]

Parameters

ParameterTypeRequiredDescription
-ImageNameStringNoOptional filter on the image tag.
-DockerExecutableStringNoDocker executable. Default: 'docker'.

Output

PSCustomObject[]: ImageName, ArtifactUrl, SizeBytes, CreatedUtc, LastUsedUtc, InUse.


Import-BcConfigurationPackage

Imports a RapidStart (.rapidstart) configuration package into a Business Central container.

Copies a RapidStart configuration package from the host into the container and imports it with Import-NAVConfigurationPackageFile. The package source is a .rapidstart file or a folder that contains one (e.g. the output of Get-BcUniversalPackage). Requires Windows + a running Docker engine. This is the native replacement for the V1 DownloadConfigPackageUniversalFeed import.

Syntax

PowerShellCode
Import-BcConfigurationPackage -Name <String> -Path <String> [-ServerInstance <String>] [-DockerExecutable <String>]

Parameters

ParameterTypeRequiredDescription
-NameStringYesContainer name.
-PathStringYesA .rapidstart file, or a folder to search (recursively) for the first .rapidstart file.
-ServerInstanceStringNoBusiness Central server instance inside the container. Default 'BC'. Default: 'BC'.
-DockerExecutableStringNoThe Docker executable to use. Default 'docker'. Default: 'docker'.

Output

PSCustomObject: Container, File.

Examples

Example 1

PowerShellCode
Import-BcConfigurationPackage -Name bld -Path '.\config\Setup.rapidstart'

Example 2

PowerShellCode
$pkg = Get-BcUniversalPackage -Organization org -Feed D365BC -Name cfg -OutputFolder $tmp Import-BcConfigurationPackage -Name bld -Path $pkg.OutputFolder

Install-BcContainerTestToolkit

Publishes and installs the Business Central test toolkit apps into a container.

Discovers the Microsoft test toolkit/framework app packages that ship with the artifact and publishes, synchronises and installs them, in dependency order and idempotently. With -IncludeTestLibrariesOnly only the framework and library apps are installed (not Microsoft's test-content apps).

Apps are taken from the compiled, country-specific copies that the container produced at setup (the versioned Microsoft_*_<version>.app files under C:\Applications.<country>, e.g. C:\Applications.DE), then C:\Extensions, falling back to the source apps under C:\Applications only for anything without a compiled copy. Publishing a compiled app does not recompile it, so localized containers such as 'de' work - recompiling the source Tests-TestLibraries against a German base app fails on its VAT objects. This mirrors BcContainerHelper's GetTestToolkitApps, which globs c:\applications.* for the versioned package and only uses the source app when no compiled copy exists.

Syntax

PowerShellCode
Install-BcContainerTestToolkit -Name <String> [-IncludeTestLibrariesOnly] [-SymbolExportFolder <String>] [-SearchRoots <String[]>] [-ServerInstance <String>] [-DockerExecutable <String>]

Parameters

ParameterTypeRequiredDescription
-NameStringYesContainer name.
-IncludeTestLibrariesOnlyswitchNoInstall only the test framework and libraries, not Microsoft's test-content apps.
-SymbolExportFolderStringNoHost folder to copy the installed toolkit .app files into, so a host (AL Tool) compile can resolve test-toolkit symbols that the artifact does not ship on the host. This is required for test apps on country 'w1', whose 'System Application Test Library' and 'Tests-TestLibraries' exist only inside the container. The apps are bridged out through the container's C:\run\my host mount ('docker cp' is not supported against a running hyperv-isolated container).
-SearchRootsString[]NoAdditional container folders to search, in preference order, after the auto-discovered compiled country folders (C:\Applications.*). Default 'C:\Extensions' then 'C:\Applications'. Default: @('C:\Extensions', 'C:\Applications').
-ServerInstanceStringNoBC server instance inside the container. Default 'BC'. Default: 'BC'.
-DockerExecutableStringNoThe Docker executable to use (default 'docker'). Default: 'docker'.

Invoke-BcContainerCommand

Runs a PowerShell script block inside a running Business Central (Windows) container.

Executes the script block inside the container via 'docker exec ... powershell -EncodedCommand', returning the captured stdout. Simple variables can be passed with -Variables (marshalled as JSON across the process boundary). This is the single seam through which higher-level container cmdlets run Business Central management cmdlets.

Syntax

PowerShellCode
Invoke-BcContainerCommand -ContainerName <String> -ScriptBlock <ScriptBlock> [-Variables <Hashtable>] [-StreamOutput] [-PowerShellExe <String>] [-DockerExecutable <String>]

Parameters

ParameterTypeRequiredDescription
-ContainerNameStringYesThe target container.
-ScriptBlockScriptBlockYesThe PowerShell to run inside the container.
-VariablesHashtableNoOptional hashtable of simple values made available as variables inside the container.
-StreamOutputswitchNo
-PowerShellExeStringNoPin the in-container PowerShell host instead of letting Get-BcContainerPowerShellExe choose it. The automatic choice follows the BC management cmdlets (Windows PowerShell through BC28, pwsh from BC29, where only the .NET 8 modules remain). Pin 'powershell' for a script that needs .NET Framework instead - the AL test runner does: it loads the .NET Framework client assemblies from C:\Test Assemblies and relies on ServicePointManager for the loopback certificate bypass, which is obsolete/ineffective under .NET. Such a script must not need the management cmdlets. Allowed values: powershell, pwsh.
-DockerExecutableStringNoThe Docker executable to use (default 'docker'). Default: 'docker'.

Output

System.String (the command's stdout).

Examples

Example 1

PowerShellCode
Invoke-BcContainerCommand -ContainerName bld -ScriptBlock { Get-NavServerInstance }

Invoke-BcDocker

Runs a Docker CLI command for ALbuild (the central Docker entry point).

Every Docker interaction in ALbuild goes through this function so behaviour is consistent: the Docker CLI is located (and a clear error raised if it is missing), the command is run via Invoke-ALbuildProcess (reliable output capture, optional retry/back-off), registry authentication failures on 'pull' are turned into actionable errors, and output is logged through Write-ALbuildLog. This is ALbuild's equivalent of BcContainerHelper's DockerDo, written from scratch on top of the shared process helper.

Syntax

PowerShellCode
Invoke-BcDocker -Arguments <String[]> [-DockerExecutable <String>] [-WorkingDirectory <String>] [-SuccessExitCodes <Int32[]>] [-RetryCount <Int32>] [-RetryDelaySeconds <Int32>] [-PassThru] [-Quiet] [-StreamOutput]

Parameters

ParameterTypeRequiredDescription
-ArgumentsString[]YesThe Docker command and its arguments, e.g. @('ps','--all','--format','{{.Names}}').
-DockerExecutableStringNoThe Docker executable to use. Default 'docker'. Allows full paths or alternatives (e.g. 'docker.exe', 'podman') and makes the function testable against a stand-in. Default: 'docker'.
-WorkingDirectoryStringNoWorking directory for the Docker process.
-SuccessExitCodesInt32[]NoExit codes treated as success. Default: 0. Default: @(0).
-RetryCountInt32NoAdditional attempts on failure (use for transient operations such as 'pull'). Default 0. Default: 0.
-RetryDelaySecondsInt32NoDelay between attempts. Default 5. Default: 5.
-PassThruswitchNoReturn the result object even on failure instead of throwing.
-QuietswitchNoDo not echo Docker stdout through Write-ALbuildLog.
-StreamOutputswitchNo

Output

PSCustomObject with ExitCode, StdOut, StdErr, Success, Attempts.

Examples

Example 1

PowerShellCode
Invoke-BcDocker -Arguments @('version','--format','{{.Server.Version}}')

Example 2

PowerShellCode
Invoke-BcDocker -Arguments @('pull', $imageName) -RetryCount 5 -RetryDelaySeconds 15

New-BcContainer

Creates a Business Central Docker container from an artifact.

Pulls the Business Central generic image (if needed) and runs a container configured for the given artifact URL using the generic image's environment contract (accept_eula, artifactUrl, Auth, username, password, licenseFile). Requires a Windows host with a running Docker engine; on other platforms it fails with a clear message. After starting, it waits for the container to report ready unless -NoWait is specified.

Syntax

PowerShellCode
New-BcContainer -Name <String> -ArtifactUrl <String> [-Credential <PSCredential>] [-Auth <String>] [-ImageName <String>] [-MemoryLimit <String>] [-Isolation <String>] [-LicenseFile <String>] [-Labels <Hashtable>] [-PublishPorts <String[]>] [-Http] [-Transparent] [-Language <String>] [-SupportedLanguages <String>] [-EnvironmentVariables <Hashtable>] [-AdditionalArguments <String[]>] [-NoWait] [-ArtifactCacheFolder <String>] [-NoArtifactCache] [-UseImageCache] [-MinFreeDiskGb <Int32>] [-MaxStartAttempts <Int32>] [-DockerExecutable <String>]

Parameters

ParameterTypeRequiredDescription
-NameStringYesContainer name.
-ArtifactUrlStringYesThe artifact URL (see Find-BcArtifactUrl). Required unless -Type/-Country/-Version are used.
-CredentialPSCredentialNoCredential for the container's admin user (used with UserPassword auth).
-AuthStringNoAuthentication model: UserPassword (default), NavUserPassword, Windows or AAD. Allowed values: UserPassword, NavUserPassword, Windows, AAD. Default: 'UserPassword'.
-ImageNameStringNoThe generic image to base the container on. Default: 'mcr.microsoft.com/businesscentral:ltsc2022'.
-MemoryLimitStringNoOptional memory limit (e.g. '8G'). Defaults to '8G' when not specified: Business Central's start script requires at least 3 GB, and under hyperv isolation (the Docker Desktop default on Windows client hosts) this value sizes the container VM, so leaving it unset makes the container exit immediately with "At least 3Gb memory needs to be available to the Container".
-IsolationStringNoContainer isolation: process or hyperv (default: let Docker decide). Allowed values: ``, process, hyperv.
-LicenseFileStringNoOptional license file (path or URL) passed to the image.
-LabelsHashtableNoAdditional Docker labels (hashtable).
-PublishPortsString[]NoPorts to publish (docker --publish values).
-HttpswitchNoServe the Web Client / Web Services over plain HTTP instead of the generic image's default self-signed HTTPS (sets the image env 'useSSL=N'). NavUserPassword works over HTTP. Intended for Sandbox/Dev containers on a trusted LAN only - credentials travel in clear text over HTTP.
-TransparentswitchNoAttach the container to a transparent Docker network so it gets its own LAN IP via DHCP and is reachable from other hosts on the LAN (no port publishing / firewall rule needed). The transparent network is created if the host does not already have one (see Initialize-BcTransparentNetwork). Dev-only; on a Hyper-V VM host the vNIC needs MACAddressSpoofing enabled.
-LanguageStringNoCulture name (e.g. 'de-DE') to set as the container's default UI language (DefaultLanguage) after it is ready. Empty (default) leaves the image default (en-US). The language module must be installed on the instance (use a matching country artifact, e.g. country 'de' for de-DE) - a missing language throws. Setting this restarts the service tier (the key is not dynamically updatable). Ignored with -NoWait (the instance is not ready to configure).
-SupportedLanguagesStringNoOptional ';'-separated culture list to pin (SupportedLanguages). Default when -Language is set = the language alone, which forces the UI language even when the browser requests another installed language. Must include -Language. Only applies together with -Language.
-EnvironmentVariablesHashtableNoAdditional environment variables (hashtable) merged into the image contract.
-AdditionalArgumentsString[]NoExtra raw 'docker run' arguments.
-NoWaitswitchNoDo not wait for the container to become ready.
-ArtifactCacheFolderStringNo
-NoArtifactCacheswitchNo
-UseImageCacheswitchNo
-MinFreeDiskGbInt32NoDefault: 10.
-MaxStartAttemptsInt32NoDefault: 3.
-DockerExecutableStringNoThe Docker executable to use (default 'docker'). Default: 'docker'.

Output

PSCustomObject describing the container.

Examples

Example 1

PowerShellCode
$cred = Get-Credential New-BcContainer -Name bld -ArtifactUrl (Find-BcArtifactUrl -Country w1 -Select Latest) -Credential $cred

New-BcContainerUser

Creates a Business Central user inside a container.

Runs the Business Central server management cmdlets inside the container to create a user and assign a permission set (SUPER by default). The password crosses the process boundary in clear text to the local container only (acceptable for a development/build container).

Syntax

PowerShellCode
New-BcContainerUser -Name <String> -Credential <PSCredential> [-PermissionSetId <String>] [-ServerInstance <String>] [-DockerExecutable <String>]

Parameters

ParameterTypeRequiredDescription
-NameStringYesContainer name.
-CredentialPSCredentialYesThe user's credentials.
-PermissionSetIdStringNoPermission set to assign. Default SUPER. Default: 'SUPER'.
-ServerInstanceStringNoBC server instance inside the container. Default 'BC'. Default: 'BC'.
-DockerExecutableStringNoThe Docker executable to use (default 'docker'). Default: 'docker'.

New-BcImage

Builds a version-specific Business Central image with the artifact already installed.

A container started from the generic image installs the Business Central artifact into its writable layer on every start. Measured on build 27197 that install is the dominant cost of a runtime-package run - 178 s on BC18 rising to 468 s on BC27, against ~80 s of actual work per product. Baking the install into an image layer moves it out of the per-container path: the install is paid once per platform version and every later container only starts the service tier.

The build uses the generic image's own install-only entry point, 'start.ps1 -installOnly', which performs the installation and stops short of creating the instance, generating certificates and starting the service tier. That split matters: 'docker commit' of a fully started container would bake in instance state, self-signed certificates and the container hostname, all of which must be produced fresh at run time.

WHY IT IS WORTH BUILDING AT ALL The image only pays for itself on a repeat visit to the same platform version - building it costs an install, same as starting a container once. It wins because platform versions are revisited constantly: every product release walks the whole matrix again, and the weekly sweep revisits the newest versions for every product. It is therefore a cache with a budget, trimmed by Optimize-BcImageCache, not something to build for all ~200 versions.

Concurrency: two workers asking for the same image must not both build it. The build is serialised on the same global lock used for the artifact cache, and the presence check is repeated under that lock.

Note the BUILD downloads the artifact itself. 'docker build' on Windows cannot bind-mount, so the host's artifact cache is not visible to the build container - unlike a normal container start, which mounts it at C:\dl. That is a one-off cost per platform version, and it is why the image is built once and then reused rather than rebuilt.

Syntax

PowerShellCode
New-BcImage -ArtifactUrl <String> [-ImageName <String>] [-BaseImage <String>] [-MemoryLimit <String>] [-Force] [-MinFreeDiskGb <Int32>] [-TimeoutSeconds <Int32>] [-DockerExecutable <String>]

Parameters

ParameterTypeRequiredDescription
-ArtifactUrlStringYesThe artifact to install into the image.
-ImageNameStringNoImage tag. Defaults to Get-BcImageName.
-BaseImageStringNoThe generic image to build on. Default: 'mcr.microsoft.com/businesscentral:ltsc2022'.
-MemoryLimitStringNoMemory for the BUILD container. Not cosmetic: 'docker build' gives a Windows build container 1 GB by default and Business Central's start script refuses to install below 3 GB, so without this the build fails with "At least 3Gb memory needs to be available to the Container". Default: '8G'.
-ForceswitchNoRebuild even when the image already exists.
-MinFreeDiskGbInt32NoRefuse to build below this much free disk. An image build that fills the drive mid-layer leaves a large dangling layer behind and makes the next build worse. Default: 60.
-TimeoutSecondsInt32NoBuild timeout. Default: 3600.
-DockerExecutableStringNoDocker executable. Default: 'docker'.

Output

PSCustomObject: ImageName, ArtifactUrl, Built, BuildSeconds, SizeBytes.

Examples

Example 1

PowerShellCode
New-BcImage -ArtifactUrl (Find-BcArtifactUrl -Type OnPrem -Country de -Version '26.3' -Select Closest)

Optimize-BcImageCache

Trims the cached Business Central images to a size budget, least-recently-used first.

The version-specific image cache is the only thing that removes the per-container install cost, and it is also the largest thing on the agent's disk. It therefore needs a retention policy of its own rather than being swept up by the generic cache prune - Clear-ALbuildCache deliberately excludes 'albuild.image' images, because it runs under disk pressure and would delete the cache at exactly the moment it is most valuable.

Eviction is by least-recent USE, not by age. An image is built once and reused for months, so evicting the oldest would discard the platform versions being asked for most.

Two things are never evicted:

  • an image a container still references - removing it would break a running build;
  • an image in -Pin, which the caller is about to use. A run that pins the versions in its plan cannot have the cache pulled out from under it by its own trimming step.

Note the budget is measured against each image's total reported size, which includes the layers shared with the generic base. That over-counts: the base is stored once for all of them. Being conservative here is intentional - overshooting the disk is far more expensive than keeping one image fewer.

Syntax

PowerShellCode
Optimize-BcImageCache [-BudgetGb <Int32>] [-MinFreeDiskGb <Int32>] [-Pin <String[]>] [-DockerExecutable <String>]

Parameters

ParameterTypeRequiredDescription
-BudgetGbInt32NoTotal size to keep. 0 disables the size check (then only -MinFreeDiskGb applies). Default: 400.
-MinFreeDiskGbInt32NoKeep evicting while free disk is below this. 0 disables the free-space check. Default: 80.
-PinString[]NoImage names that must never be evicted.
-DockerExecutableStringNoDocker executable. Default: 'docker'.

Output

PSCustomObject: Removed[], KeptCount, FreedBytes.


Publish-BcContainerToTraefik

Produces a Traefik v3 dynamic configuration that routes traffic to a BC container.

Generates a Traefik v3 file-provider dynamic configuration for the container in one of two routing modes - Subdomain (<name>.<domain>) or PathPrefix (<domain>/<name>, with a strip-prefix middleware). The configuration object is returned and, when -OutputPath is given, written as JSON for Traefik's file provider to pick up (no container recreation required).

Syntax

PowerShellCode
Publish-BcContainerToTraefik -Name <String> -Domain <String> -Routing <String> [-BackendHost <String>] [-Port <Int32>] [-Scheme <String>] [-EntryPoint <String>] [-CertResolver <String>] [-OutputPath <String>]

Parameters

ParameterTypeRequiredDescription
-NameStringYesContainer name (and the subdomain/path segment).
-DomainStringYesBase domain (e.g. businesscentral.example.com).
-RoutingStringYesSubdomain or PathPrefix. Allowed values: Subdomain, PathPrefix.
-BackendHostStringNoBackend host Traefik forwards to. Default: the container name (Docker network DNS).
-PortInt32NoBackend port. Default 80. Default: 80.
-SchemeStringNoBackend scheme (http/https). Default http. Default: 'http'.
-EntryPointStringNoTraefik entry point. Default 'websecure'. Default: 'websecure'.
-CertResolverStringNoTraefik certificate resolver. Default 'letsencrypt'. Default: 'letsencrypt'.
-OutputPathStringNoOptional path to write the dynamic configuration JSON to.

Output

Hashtable (the Traefik dynamic configuration).

Examples

Example 1

PowerShellCode
Publish-BcContainerToTraefik -Name bld -Domain bc.example.com -Routing Subdomain -OutputPath /etc/traefik/dynamic/bld.json

Register-BcContainerCertificate

Trusts a BC container's self-signed TLS certificate for the current user.

Reads the certificate the container presents on https://<DnsName> and adds it to the current user's Trusted Root store (Cert:\CurrentUser\Root) so the web client opens without a browser security warning. This requires no administrator rights and is honoured by Edge and Chrome (which use the Windows certificate store).

The certificate is stamped with a friendly name so it can be removed again when the container is removed (see Unregister-BcContainerCertificate, called by Remove-BcContainer). Re-running is idempotent - an already-trusted certificate (same thumbprint) is not added twice.

Syntax

PowerShellCode
Register-BcContainerCertificate -Name <String> [-DnsName <String>] [-Port <Int32>]

Parameters

ParameterTypeRequiredDescription
-NameStringYesContainer name (used for the friendly-name tag and as the default DNS name).
-DnsNameStringNoHost name the certificate is served on. Defaults to the container name.
-PortInt32NoHTTPS port (default 443). Default: 443.

Output

[string] The certificate thumbprint, or $null when no certificate could be read.


Remove-BcContainer

Removes a Business Central container (and its anonymous volumes).

Syntax

PowerShellCode
Remove-BcContainer -Name <String> [-DockerExecutable <String>]

Parameters

ParameterTypeRequiredDescription
-NameStringYesContainer name.
-DockerExecutableStringNoThe Docker executable to use (default 'docker'). Default: 'docker'.

Examples

Example 1

PowerShellCode
Remove-BcContainer -Name bld No ConfirmImpact='High': ALbuild runs primarily non-interactively (pipelines, the MCP, the VS Code extension), where a High-impact confirmation prompt has no host UI and ShouldProcess throws a NullReferenceException. -WhatIf still works and callers can opt into -Confirm; destructive intent is gated by the consumers (e.g. the MCP's approval flow), not by an auto-prompt here.

Remove-BcImage

Removes a cached version-specific Business Central image.

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.

Syntax

PowerShellCode
Remove-BcImage -ImageName <String> [-DockerExecutable <String>]

Parameters

ParameterTypeRequiredDescription
-ImageNameStringYesThe image tag to remove.
-DockerExecutableStringNoDocker executable. Default: 'docker'.

Output

PSCustomObject: ImageName, Removed.


Resolve-BcContainerHostShare

Returns the host folder actually bind-mounted to C:\run\my in a container (with a fallback).

Files are exchanged with a Business Central container through the host folder bind-mounted to C:\run\my (Copy-BcFileToContainer writes there; Invoke-BcContainerCommand stages large command scripts there). Get-BcContainerHostShare returns the DETERMINISTIC folder that ALbuild's own New-BcContainer mounts - which is correct only for a container this module created in the current job, because the convention is rooted under the job-scoped AGENT_TEMPDIRECTORY. For a container created elsewhere - a BcContainerHelper container, or a long-lived container targeted by a release / on-prem deployment - that path does NOT match the real mount, so staged files are written to a folder the container cannot see (the deploy then fails with "the argument 'C:\run\my...ps1' to the -File parameter does not exist").

This resolves the REAL host path by inspecting the container's mounts (authoritative regardless of who created it) and returning the Source of the C:\run\my bind mount. If the container cannot be inspected - Docker missing, or the container does not exist yet (e.g. called at creation time) - it falls back to the deterministic Get-BcContainerHostShare convention.

Syntax

PowerShellCode
Resolve-BcContainerHostShare -Name <String> [-DockerExecutable <String>]

Parameters

ParameterTypeRequiredDescription
-NameStringYesContainer name.
-DockerExecutableStringNoThe Docker executable to use (default 'docker'). Default: 'docker'.

Output

System.String - the host folder path bind-mounted to C:\run\my.


Restart-BcContainer

Restarts a Business Central container and waits for it to become ready.

Syntax

PowerShellCode
Restart-BcContainer -Name <String> [-NoWait] [-DockerExecutable <String>]

Parameters

ParameterTypeRequiredDescription
-NameStringYesContainer name.
-NoWaitswitchNoDo not wait for the container to become ready again.
-DockerExecutableStringNoThe Docker executable to use (default 'docker'). Default: 'docker'.

Set-BcContainerServerConfig

Sets Business Central server configuration keys inside a container and restarts the instance.

Syntax

PowerShellCode
Set-BcContainerServerConfig -Name <String> -Settings <Hashtable> [-ServerInstance <String>] [-NoRestart] [-DockerExecutable <String>]

Parameters

ParameterTypeRequiredDescription
-NameStringYesContainer name.
-SettingsHashtableYesHashtable of configuration key/value pairs (Set-NAVServerConfiguration KeyName/KeyValue).
-ServerInstanceStringNoBC server instance inside the container. Default 'BC'. Default: 'BC'.
-NoRestartswitchNoApply the settings without restarting the server instance.
-DockerExecutableStringNoThe Docker executable to use (default 'docker'). Default: 'docker'.

Examples

Example 1

PowerShellCode
Set-BcContainerServerConfig -Name bld -Settings @{ ExtendedSecurityTokenLifetime = 24 }

Set-BcDockerDataRoot

Moves Docker's data root to another drive, with a full preflight and an automatic rollback.

On a build server the Docker root decides how much can be cached and how many containers fit. A BC container copies the service tier, the web client and the apps into its writable layer and restores the demo database there, and a version image costs about 6.4 GB - so a Docker root on the system drive is what caps a build host long before its CPU or RAM do.

WHAT THIS DOES, AND WHAT IT DELIBERATELY DOES NOT It sets 'data-root' in daemon.json and restarts the service. It does NOT copy the existing layer store, and that is the single most important thing about it. Windows layers ('windowsfilter') are built from hard links and NTFS metadata; copying them is unreliable and produces images that cannot be removed later. So the new root starts EMPTY: images are pulled again on demand.

The consequence is worth stating plainly, because it is also the safety property. Nothing is deleted. The old root stays exactly as it was, which means:

  • every image and container is still on disk, just not visible to the daemon any more;
  • rollback is complete - putting daemon.json back restores the previous state entirely;
  • the old directory can be deleted later, deliberately, once the new root has proven out.

HOW IT FAILS Every check runs before anything is touched, and each one names what to do about it. After that the operation is journalled step by step, and any failure - a service that will not start, a daemon that comes up on the wrong root - triggers a rollback that restores daemon.json byte for byte and restarts the service. The result object says whether it rolled back, and the original failure is preserved rather than replaced by whatever the rollback ran into.

Syntax

PowerShellCode
Set-BcDockerDataRoot -Path <String> [-ServiceName <String>] [-DockerExecutable <String>] [-ConfigPath <String>] [-MinimumFreeGb <Int32>] [-TimeoutSeconds <Int32>] [-Force]

Parameters

ParameterTypeRequiredDescription
-PathStringYesThe new data root, e.g. 'G:\Docker'. Created if it does not exist.
-ServiceNameStringNoThe Docker service to restart. Detected automatically ('docker', then 'com.docker.service').
-DockerExecutableStringNoThe Docker executable. Default 'docker'. Default: 'docker'.
-ConfigPathStringNoThe daemon configuration file. Defaults to the standard Windows location. Other keys in it are preserved - on many hosts 'hosts' is set and the daemon will not start without it. Default: (Join-Path $env:ProgramData 'Docker\config\daemon.json').
-MinimumFreeGbInt32NoRefuse a target with less free space than this. Default 100, which is roughly one BC container plus a small image cache. Use -Force to proceed anyway. Default: 100.
-TimeoutSecondsInt32NoHow long to wait for the service to stop, and for the daemon to answer after starting. Default 180. Default: 180.
-ForceswitchNoProceed despite conditions that are survivable but usually mistakes: running containers, a non-empty target, too little free space, Docker Desktop, or deduplication on the target volume. It does not skip the checks - they still report - and it never suppresses the rollback.

Output

PSCustomObject with Moved, RolledBack, PreviousPath, Path, ServiceName, RetainedDataAt, ImagesToPullAgain, Warnings.

Examples

Example 1

PowerShellCode
Set-BcDockerDataRoot -Path 'G:\Docker' -WhatIf Runs the whole preflight and prints what would change, touching nothing.

Example 2

PowerShellCode
Set-BcDockerDataRoot -Path 'G:\Docker' Prompts (the impact is High), then moves and verifies.

Start-BcContainer

Starts a stopped Business Central container.

Syntax

PowerShellCode
Start-BcContainer -Name <String> [-DockerExecutable <String>]

Parameters

ParameterTypeRequiredDescription
-NameStringYesContainer name.
-DockerExecutableStringNoThe Docker executable to use (default 'docker'). Default: 'docker'.

Stop-BcContainer

Stops a running Business Central container.

Syntax

PowerShellCode
Stop-BcContainer -Name <String> [-DockerExecutable <String>]

Parameters

ParameterTypeRequiredDescription
-NameStringYesContainer name.
-DockerExecutableStringNoThe Docker executable to use (default 'docker'). Default: 'docker'.

Test-BcDocker

Reports whether the Docker CLI is installed and its daemon is reachable.

Returns an object describing Docker availability. Unlike Test-BcPlatform (which only checks for the CLI on PATH), this actually queries the Docker daemon for its version, so it can distinguish "Docker installed but not running" from "Docker ready".

Syntax

PowerShellCode
Test-BcDocker [-DockerExecutable <String>] [-Require]

Parameters

ParameterTypeRequiredDescription
-DockerExecutableStringNoThe Docker executable to query. Default 'docker'. Default: 'docker'.
-RequireswitchNoThrow if Docker is not installed or the daemon is not reachable.

Output

PSCustomObject with Installed, DaemonRunning, ClientVersion, ServerVersion.

Examples

Example 1

PowerShellCode
if ((Test-BcDocker).DaemonRunning) { ... }

Unregister-BcContainerCertificate

Removes a BC container's certificate that ALbuild trusted for the current user.

Removes any certificate from the current user's Trusted Root store (Cert:\CurrentUser\Root) that ALbuild stamped for this container (matched by friendly name). Safe to call when nothing was trusted - it is a no-op. Called automatically by Remove-BcContainer.

Syntax

PowerShellCode
Unregister-BcContainerCertificate -Name <String>

Parameters

ParameterTypeRequiredDescription
-NameStringYesContainer name whose trusted certificate(s) should be removed.

Output

[int] The number of certificates removed.


Wait-BcContainerReady

Waits for a Business Central container to report that it is ready for connections.

Polls the container log for the ready marker emitted by the generic image, failing fast if the container exits before becoming ready or if the timeout elapses. While waiting it streams the container's new start-script log lines to the console (and a periodic heartbeat when the log is quiet) so a long initialisation never looks hung.

Syntax

PowerShellCode
Wait-BcContainerReady -Name <String> [-TimeoutSeconds <Int32>] [-ReadyText <String>] [-PollIntervalSeconds <Int32>] [-HeartbeatSeconds <Int32>] [-NoProgress] [-DockerExecutable <String>]

Parameters

ParameterTypeRequiredDescription
-NameStringYesContainer name.
-TimeoutSecondsInt32NoMaximum time to wait. Default 1200 (20 minutes). Default: 1200.
-ReadyTextStringNoThe log text that signals readiness. Default 'Ready for connections'. Default: 'Ready for connections'.
-PollIntervalSecondsInt32NoSeconds between polls. Default 5. Default: 5.
-HeartbeatSecondsInt32NoEmit an "elapsed" heartbeat after this many seconds without new log output. Default 30. Default: 30.
-NoProgressswitchNoSuppress streaming the container's startup log lines (the readiness check and heartbeat still apply).
-DockerExecutableStringNoThe Docker executable to use (default 'docker'). Default: 'docker'.

Output

System.Boolean ($true when ready; otherwise throws).


Last modified on