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
| Cmdlet | Description |
|---|---|
Enter-BcContainer | Opens an interactive PowerShell session inside a Business Central container. |
Find-BcArtifactUrl | Finds Business Central artifact URLs from the public artifact indexes. |
Get-BcArtifact | Downloads and caches a Business Central artifact (application + platform packages). |
Get-BcArtifactSymbolFolder | Returns the symbol (package cache) folders a host AL compile needs from a downloaded BC artifact. |
Get-BcArtifactVersion | Parses the type, version and country out of a Business Central artifact URL. |
Get-BcContainer | Lists Business Central (Docker) containers, optionally filtered by name. |
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. |
Get-BcContainerAppInfo | Returns the apps installed/published in a Business Central container, with versions. |
Get-BcContainerWebClientUrl | Resolves the reachable Web Client URL of a Business Central container. |
Get-BcDockerDataRoot | Where Docker stores its images and container layers, and whether that place is a good one. |
Get-BcImage | Lists the cached version-specific Business Central images on this host. |
Import-BcConfigurationPackage | Imports a RapidStart (.rapidstart) configuration package into a Business Central container. |
Install-BcContainerTestToolkit | Publishes and installs the Business Central test toolkit apps into a container. |
Invoke-BcContainerCommand | Runs a PowerShell script block inside a running Business Central (Windows) container. |
Invoke-BcDocker | Runs a Docker CLI command for ALbuild (the central Docker entry point). |
New-BcContainer | Creates a Business Central Docker container from an artifact. |
New-BcContainerUser | Creates a Business Central user inside a container. |
New-BcImage | Builds a version-specific Business Central image with the artifact already installed. |
Optimize-BcImageCache | Trims the cached Business Central images to a size budget, least-recently-used first. |
Publish-BcContainerToTraefik | Produces a Traefik v3 dynamic configuration that routes traffic to a BC container. |
Register-BcContainerCertificate | Trusts a BC container's self-signed TLS certificate for the current user. |
Remove-BcContainer | Removes a Business Central container (and its anonymous volumes). |
Remove-BcImage | Removes a cached version-specific Business Central image. |
Resolve-BcContainerHostShare | Returns the host folder actually bind-mounted to C:\run\my in a container (with a fallback). |
Restart-BcContainer | Restarts a Business Central container and waits for it to become ready. |
Set-BcContainerServerConfig | Sets Business Central server configuration keys inside a container and restarts the instance. |
Set-BcDockerDataRoot | Moves Docker's data root to another drive, with a full preflight and an automatic rollback. |
Start-BcContainer | Starts a stopped Business Central container. |
Stop-BcContainer | Stops a running Business Central container. |
Test-BcDocker | Reports whether the Docker CLI is installed and its daemon is reachable. |
Unregister-BcContainerCertificate | Removes a BC container's certificate that ALbuild trusted for the current user. |
Wait-BcContainerReady | Waits 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
Code
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
-Name | String | Yes | The container to enter. |
-Command | String | No | A command to run before the prompt appears. The session stays open afterwards. |
-WorkingDirectory | String | No | Where the session starts. Default 'C:\run', which is where the generic image keeps its scripts. Default: 'C:\run'. |
-PowerShellExe | String | No | Pin the in-container shell instead of letting Get-BcContainerPowerShellExe choose it. Allowed values: powershell, pwsh. |
-SkipPrompt | switch | No | Do not dot-source the image's C:\Run\prompt.ps1. Use it when that script gets in the way. |
-DockerExecutable | String | No | The 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
Code
Example 2
Code
Example 3
Code
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/{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
Code
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
-Type | String | No | OnPrem or Sandbox (default Sandbox). Allowed values: OnPrem, Sandbox. Default: 'Sandbox'. |
-Country | String | No | Localisation (e.g. w1, de, us). Empty queries all countries. |
-Version | String | No | Version or version prefix to match (e.g. '25', '25.1', '25.1.12345.0'). |
-Select | String | No | Selection strategy: Latest (default), First, All, Closest, SecondToLastMajor, Current, NextMinor, NextMajor. Allowed values: Latest, First, All, Closest, SecondToLastMajor, Current, NextMinor, NextMajor. Default: 'Latest'. |
-StorageAccount | String | No | Override the storage account (advanced; default bcartifacts). |
-AcceptInsiderEula | switch | No | Required to query insider artifacts (NextMinor/NextMajor), confirming acceptance of the Business Central Insider EULA (https://go.microsoft.com/fwlink/?linkid=2245051). |
-DoNotCheckPlatform | switch | No | Skip confirming that a matching platform build exists in the index. |
Output
System.String (one or more artifact URLs).
Examples
Example 1
Code
Example 2
Code
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
Code
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
-ArtifactUrl | String | Yes | The artifact URL (see Find-BcArtifactUrl). |
-CacheFolder | String | No | Root cache folder. Defaults to the configured ArtifactCacheFolder. |
-IncludePlatform | Boolean | No | Also download/extract the platform package. Default: $true. Default: $true. |
-Force | switch | No | Re-download even if a cached copy exists. |
Output
PSCustomObject with ApplicationPath, PlatformPath, Version, Country.
Examples
Example 1
Code
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
Code
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
-Artifact | Object | Yes | The artifact object returned by Get-BcArtifact (ApplicationPath / PlatformPath). |
-Force | switch | No | Re-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
Code
Get-BcArtifactVersion
Parses the type, version and country out of a Business Central artifact URL.
Syntax
Code
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
-ArtifactUrl | String | Yes | An artifact URL of the form https://.../{type}/{version}/{country}. |
Output
PSCustomObject with Type, Version ([version]), Country, Url.
Examples
Example 1
Code
Get-BcContainer
Lists Business Central (Docker) containers, optionally filtered by name.
Syntax
Code
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
-Name | String | No | Optional exact container name to filter by. |
-DockerExecutable | String | No | The Docker executable to use (default 'docker'). Default: 'docker'. |
Output
PSCustomObject with Name, Status, Image, Id, Running.
Examples
Example 1
Code
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
Code
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
-ContainerName | String | Yes | The build container to read through (its C:\run\my share is used to hand the files across). |
-Path | String[] | Yes | One or more .app file paths on the host. |
-DockerExecutable | String | No | Default: '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
Code
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
-Name | String | Yes | Container name. |
-ServerInstance | String | No | BC server instance inside the container. Default 'BC'. Default: 'BC'. |
-Tenant | String | No | Tenant to query for tenant-specific (installed) information. Default 'default'. Default: 'default'. |
-DockerExecutable | String | No | The 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
Code
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
-Name | String | Yes | Container name. |
-Protocol | String | No | 'http' or 'https'. Empty = read the 'albuild.protocol' label, else default to 'https'. Allowed values: ``, http, https. |
-ServerInstance | String | No | BC server instance (the Web Client path segment). Default 'BC' (the generic image default). Default: 'BC'. |
-Tenant | String | No | The tenant appended to the URL as '?tenant=<tenant>'. Default 'default' (the single-tenant container tenant). Empty = omit the tenant query. Default: 'default'. |
-DockerExecutable | String | No | The 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
Code
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
-DockerExecutable | String | No | The Docker executable to query. Default 'docker'. Default: 'docker'. |
-ConfigPath | String | No | The 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
Code
Example 2
Code
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
Code
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
-ImageName | String | No | Optional filter on the image tag. |
-DockerExecutable | String | No | Docker 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
Code
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
-Name | String | Yes | Container name. |
-Path | String | Yes | A .rapidstart file, or a folder to search (recursively) for the first .rapidstart file. |
-ServerInstance | String | No | Business Central server instance inside the container. Default 'BC'. Default: 'BC'. |
-DockerExecutable | String | No | The Docker executable to use. Default 'docker'. Default: 'docker'. |
Output
PSCustomObject: Container, File.
Examples
Example 1
Code
Example 2
Code
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
Code
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
-Name | String | Yes | Container name. |
-IncludeTestLibrariesOnly | switch | No | Install only the test framework and libraries, not Microsoft's test-content apps. |
-SymbolExportFolder | String | No | Host 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). |
-SearchRoots | String[] | No | Additional 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'). |
-ServerInstance | String | No | BC server instance inside the container. Default 'BC'. Default: 'BC'. |
-DockerExecutable | String | No | The 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
Code
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
-ContainerName | String | Yes | The target container. |
-ScriptBlock | ScriptBlock | Yes | The PowerShell to run inside the container. |
-Variables | Hashtable | No | Optional hashtable of simple values made available as variables inside the container. |
-StreamOutput | switch | No | |
-PowerShellExe | String | No | Pin 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. |
-DockerExecutable | String | No | The Docker executable to use (default 'docker'). Default: 'docker'. |
Output
System.String (the command's stdout).
Examples
Example 1
Code
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
Code
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
-Arguments | String[] | Yes | The Docker command and its arguments, e.g. @('ps','--all','--format','{{.Names}}'). |
-DockerExecutable | String | No | The 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'. |
-WorkingDirectory | String | No | Working directory for the Docker process. |
-SuccessExitCodes | Int32[] | No | Exit codes treated as success. Default: 0. Default: @(0). |
-RetryCount | Int32 | No | Additional attempts on failure (use for transient operations such as 'pull'). Default 0. Default: 0. |
-RetryDelaySeconds | Int32 | No | Delay between attempts. Default 5. Default: 5. |
-PassThru | switch | No | Return the result object even on failure instead of throwing. |
-Quiet | switch | No | Do not echo Docker stdout through Write-ALbuildLog. |
-StreamOutput | switch | No |
Output
PSCustomObject with ExitCode, StdOut, StdErr, Success, Attempts.
Examples
Example 1
Code
Example 2
Code
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
Code
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
-Name | String | Yes | Container name. |
-ArtifactUrl | String | Yes | The artifact URL (see Find-BcArtifactUrl). Required unless -Type/-Country/-Version are used. |
-Credential | PSCredential | No | Credential for the container's admin user (used with UserPassword auth). |
-Auth | String | No | Authentication model: UserPassword (default), NavUserPassword, Windows or AAD. Allowed values: UserPassword, NavUserPassword, Windows, AAD. Default: 'UserPassword'. |
-ImageName | String | No | The generic image to base the container on. Default: 'mcr.microsoft.com/businesscentral:ltsc2022'. |
-MemoryLimit | String | No | Optional 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". |
-Isolation | String | No | Container isolation: process or hyperv (default: let Docker decide). Allowed values: ``, process, hyperv. |
-LicenseFile | String | No | Optional license file (path or URL) passed to the image. |
-Labels | Hashtable | No | Additional Docker labels (hashtable). |
-PublishPorts | String[] | No | Ports to publish (docker --publish values). |
-Http | switch | No | Serve 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. |
-Transparent | switch | No | Attach 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. |
-Language | String | No | Culture 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). |
-SupportedLanguages | String | No | Optional ';'-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. |
-EnvironmentVariables | Hashtable | No | Additional environment variables (hashtable) merged into the image contract. |
-AdditionalArguments | String[] | No | Extra raw 'docker run' arguments. |
-NoWait | switch | No | Do not wait for the container to become ready. |
-ArtifactCacheFolder | String | No | |
-NoArtifactCache | switch | No | |
-UseImageCache | switch | No | |
-MinFreeDiskGb | Int32 | No | Default: 10. |
-MaxStartAttempts | Int32 | No | Default: 3. |
-DockerExecutable | String | No | The Docker executable to use (default 'docker'). Default: 'docker'. |
Output
PSCustomObject describing the container.
Examples
Example 1
Code
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
Code
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
-Name | String | Yes | Container name. |
-Credential | PSCredential | Yes | The user's credentials. |
-PermissionSetId | String | No | Permission set to assign. Default SUPER. Default: 'SUPER'. |
-ServerInstance | String | No | BC server instance inside the container. Default 'BC'. Default: 'BC'. |
-DockerExecutable | String | No | The 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
Code
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
-ArtifactUrl | String | Yes | The artifact to install into the image. |
-ImageName | String | No | Image tag. Defaults to Get-BcImageName. |
-BaseImage | String | No | The generic image to build on. Default: 'mcr.microsoft.com/businesscentral:ltsc2022'. |
-MemoryLimit | String | No | Memory 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'. |
-Force | switch | No | Rebuild even when the image already exists. |
-MinFreeDiskGb | Int32 | No | Refuse 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. |
-TimeoutSeconds | Int32 | No | Build timeout. Default: 3600. |
-DockerExecutable | String | No | Docker executable. Default: 'docker'. |
Output
PSCustomObject: ImageName, ArtifactUrl, Built, BuildSeconds, SizeBytes.
Examples
Example 1
Code
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
Code
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
-BudgetGb | Int32 | No | Total size to keep. 0 disables the size check (then only -MinFreeDiskGb applies). Default: 400. |
-MinFreeDiskGb | Int32 | No | Keep evicting while free disk is below this. 0 disables the free-space check. Default: 80. |
-Pin | String[] | No | Image names that must never be evicted. |
-DockerExecutable | String | No | Docker 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
Code
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
-Name | String | Yes | Container name (and the subdomain/path segment). |
-Domain | String | Yes | Base domain (e.g. businesscentral.example.com). |
-Routing | String | Yes | Subdomain or PathPrefix. Allowed values: Subdomain, PathPrefix. |
-BackendHost | String | No | Backend host Traefik forwards to. Default: the container name (Docker network DNS). |
-Port | Int32 | No | Backend port. Default 80. Default: 80. |
-Scheme | String | No | Backend scheme (http/https). Default http. Default: 'http'. |
-EntryPoint | String | No | Traefik entry point. Default 'websecure'. Default: 'websecure'. |
-CertResolver | String | No | Traefik certificate resolver. Default 'letsencrypt'. Default: 'letsencrypt'. |
-OutputPath | String | No | Optional path to write the dynamic configuration JSON to. |
Output
Hashtable (the Traefik dynamic configuration).
Examples
Example 1
Code
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
Code
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
-Name | String | Yes | Container name (used for the friendly-name tag and as the default DNS name). |
-DnsName | String | No | Host name the certificate is served on. Defaults to the container name. |
-Port | Int32 | No | HTTPS 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
Code
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
-Name | String | Yes | Container name. |
-DockerExecutable | String | No | The Docker executable to use (default 'docker'). Default: 'docker'. |
Examples
Example 1
Code
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
Code
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
-ImageName | String | Yes | The image tag to remove. |
-DockerExecutable | String | No | Docker 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
Code
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
-Name | String | Yes | Container name. |
-DockerExecutable | String | No | The 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
Code
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
-Name | String | Yes | Container name. |
-NoWait | switch | No | Do not wait for the container to become ready again. |
-DockerExecutable | String | No | The Docker executable to use (default 'docker'). Default: 'docker'. |
Set-BcContainerServerConfig
Sets Business Central server configuration keys inside a container and restarts the instance.
Syntax
Code
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
-Name | String | Yes | Container name. |
-Settings | Hashtable | Yes | Hashtable of configuration key/value pairs (Set-NAVServerConfiguration KeyName/KeyValue). |
-ServerInstance | String | No | BC server instance inside the container. Default 'BC'. Default: 'BC'. |
-NoRestart | switch | No | Apply the settings without restarting the server instance. |
-DockerExecutable | String | No | The Docker executable to use (default 'docker'). Default: 'docker'. |
Examples
Example 1
Code
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
Code
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
-Path | String | Yes | The new data root, e.g. 'G:\Docker'. Created if it does not exist. |
-ServiceName | String | No | The Docker service to restart. Detected automatically ('docker', then 'com.docker.service'). |
-DockerExecutable | String | No | The Docker executable. Default 'docker'. Default: 'docker'. |
-ConfigPath | String | No | The 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'). |
-MinimumFreeGb | Int32 | No | Refuse 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. |
-TimeoutSeconds | Int32 | No | How long to wait for the service to stop, and for the daemon to answer after starting. Default 180. Default: 180. |
-Force | switch | No | Proceed 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
Code
Example 2
Code
Start-BcContainer
Starts a stopped Business Central container.
Syntax
Code
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
-Name | String | Yes | Container name. |
-DockerExecutable | String | No | The Docker executable to use (default 'docker'). Default: 'docker'. |
Stop-BcContainer
Stops a running Business Central container.
Syntax
Code
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
-Name | String | Yes | Container name. |
-DockerExecutable | String | No | The 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
Code
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
-DockerExecutable | String | No | The Docker executable to query. Default 'docker'. Default: 'docker'. |
-Require | switch | No | Throw if Docker is not installed or the daemon is not reachable. |
Output
PSCustomObject with Installed, DaemonRunning, ClientVersion, ServerVersion.
Examples
Example 1
Code
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
Code
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
-Name | String | Yes | Container 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
Code
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
-Name | String | Yes | Container name. |
-TimeoutSeconds | Int32 | No | Maximum time to wait. Default 1200 (20 minutes). Default: 1200. |
-ReadyText | String | No | The log text that signals readiness. Default 'Ready for connections'. Default: 'Ready for connections'. |
-PollIntervalSeconds | Int32 | No | Seconds between polls. Default 5. Default: 5. |
-HeartbeatSeconds | Int32 | No | Emit an "elapsed" heartbeat after this many seconds without new log output. Default 30. Default: 30. |
-NoProgress | switch | No | Suppress streaming the container's startup log lines (the readiness check and heartbeat still apply). |
-DockerExecutable | String | No | The Docker executable to use (default 'docker'). Default: 'docker'. |
Output
System.Boolean ($true when ready; otherwise throws).


