Feeds module
Module: businessdev.ALbuild.Feeds • Tier: Free / Licensed • Cmdlets: 14
The Feeds module is home to ALbuild's headline capability: a real transitive dependency resolver across NuGet v3 feeds, Azure DevOps Universal Packages, GitHub Releases and Microsoft's public feeds. It also creates and publishes NuGet packages and promotes them to Azure DevOps feed views. See the Dependency resolver deep dive.
Licensing
This module spans both free and licensed tiers. Dependency resolution and packaging are free of license; see Licensing & tiers for the features that require a license.
Cmdlets in this module
| Cmdlet | Description |
|---|---|
ConvertFrom-BcRemoteUrl | Derives the Azure DevOps organization and project from a git remote URL. |
Find-BcPackage | Finds the available versions of an AL app across feeds. |
Get-BcDependencyReconciliation | Reconciles an app's manifest dependencies against what a container already has and what the configured feeds can provide. |
Get-BcFeed | Returns the registered feed providers. |
Get-BcPackageVersion | The published versions of one or more package ids on a feed. |
Get-BcUniversalPackage | Downloads a named package from an Azure DevOps Universal feed into a folder. |
Invoke-BcPackagePromotion | Promotes a published NuGet package version to a view on an Azure DevOps Artifacts feed. |
New-BcNuGetPackage | Creates a NuGet package (.nupkg) that contains a Business Central .app. |
Publish-BcPackage | Pushes a NuGet package (.nupkg) to a NuGet v3 feed. |
Register-BcFeed | Registers a NuGet package feed for dependency resolution. |
Resolve-BcDependencies | Resolves an AL project's dependencies across feeds and writes them to .alpackages. |
Resolve-BcDependencyCeiling | Picks the BC version that dependency resolution should cap against, from the available sources. |
Resolve-BcExternalDependency | |
Select-BcArtifactForDependencies | Picks the newest Business Central artifact whose build every project's dependencies still resolve against - stepping back through minor versions when an ISV has not yet shipped packages for the latest BC (dependency-aware selection with downgrade-on-conflict). |
ConvertFrom-BcRemoteUrl
Derives the Azure DevOps organization and project from a git remote URL.
The org/project a project-scoped Universal feed needs used to be parsed with a single regex that
only matched the HTTPS remote format (dev.azure.com/{org}/{project}/_git/...). Azure Pipelines
checks out exactly that way, so the pipeline worked; an SSH-based checkout (our agents / any SSH
clone) uses the SSH v3 form (git@ssh.dev.azure.com
This function recognizes every common Azure DevOps remote format so org/project resolve the same regardless of how the repo was cloned:
- HTTPS https://[user@]dev.azure.com/{org}/{project}/_git/{repo}
- Legacy HTTPS https://{org}.visualstudio.com/{project}/_git/{repo}
- SSH v3 [user@]ssh.dev.azure.com
/{org}/{project}/{repo} - SSH host-alias <alias>
/{org}/{project}/{repo} (a ~/.ssh/config Host alias)
Returns empty strings for both when nothing is recognized (e.g. a non-Azure-DevOps remote), so the caller can fall back to org-scoped behaviour without a hard failure.
Syntax
Code
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
-RemoteUrl | String | No | The output of git remote get-url origin (or any git remote URL). |
Output
PSCustomObject with Organization (a full https://dev.azure.com/{org}/ URL, or '') and Project (the URL-decoded project name, or ''). The project name is URL-encoded in every remote format (e.g. 'Dynamics%20365%20...') and is decoded here.
Find-BcPackage
Finds the available versions of an AL app across feeds.
Syntax
Code
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
-AppId | String | Yes | The AL app id (GUID). |
-Name | String | No | The app name (used for the package id scheme). |
-Publisher | String | No | The app publisher (used for the package id scheme). |
-Feeds | Object[] | No | Feed providers. Defaults to the registered feeds (Get-BcFeed). |
Output
PSCustomObject with Feed, PackageId, Version.
Examples
Example 1
Code
Get-BcDependencyReconciliation
Reconciles an app's manifest dependencies against what a container already has and what the configured feeds can provide.
Read-only (installs nothing). For each dependency (from app.json 'dependencies'), reports whether it is already satisfied by an app installed in the container, otherwise whether a configured feed can provide a compatible version, otherwise that it is missing. Microsoft first-party apps ship with the artifact, so they normally show up as satisfied by the container.
Feeds are taken from -Feeds, else the currently registered feeds (Get-BcFeed) -- register them first with Register-BcFeed / Register-BcFeed -FromProjectConfig.
Syntax
Code
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
-ContainerName | String | Yes | The container to reconcile against. |
-Dependencies | Object[] | Yes | The app.json 'dependencies' entries: objects with id (GUID), optional name/publisher, and version (the minimum required version). |
-Feeds | Object[] | No | Feed definitions to search (default: all currently registered feeds). |
Output
PSCustomObject: containerName, feedsSearched, summary { total, satisfied, availableFromFeed, missing }, satisfied[], availableFromFeed[], missing[].
Get-BcFeed
Returns the registered feed providers.
Syntax
Code
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
-Name | String | No | Optional name to return a single feed. |
Output
The registered feed provider object(s).
Examples
Example 1
Code
Get-BcPackageVersion
The published versions of one or more package ids on a feed.
A plain listing, for the times when the question is "what is already on the feed" rather than "resolve a dependency". The runtime factory asks it to decide what it still has to build: idempotency keyed on blob storage alone lets blob and feed drift apart, because the checkpoint uploads to blob first and pushes to the feed second, and a failed push is warned about rather than fatal.
THE EMPTY-RESULT TRAP The provider's version lookup swallows every error and returns nothing, so "this package has no versions" and "the feed could not be asked" look identical from the outside. Reading the second as the first would tell the factory that nothing is published and send it off to rebuild the whole matrix - hundreds of containers.
So the feed is proven reachable and authorised FIRST, on its own, and a failure there throws. After that an empty version list genuinely means the package is absent, and callers can trust it. A caller that would rather degrade than rebuild should catch the exception and fall back.
Syntax
Code
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
-Feed | Object | Yes | A feed from Register-BcFeed or Get-BcFeed. |
-PackageId | String[] | Yes | One or more package ids. Ids are matched case-insensitively by the feed, as NuGet requires. |
Output
PSCustomObject[] with PackageId and Versions (string[], empty when the package is absent).
Examples
Example 1
Code
Example 2
Code
Get-BcUniversalPackage
Downloads a named package from an Azure DevOps Universal feed into a folder.
Azure DevOps Universal feeds address packages by name and version (unlike NuGet symbol feeds, which the dependency resolver queries by app id). This cmdlet downloads such a named package - e.g. shared symbol bundles or a configuration package - into -OutputFolder. It is the native replacement for the V1 DownloadArtifactsUniversalFeed / DownloadDependenciesUniversalFeed / DownloadConfigPackageUniversalFeed tasks.
Download uses the Azure CLI 'az artifacts universal download' (the supported Universal Packages client). The Azure CLI with the azure-devops extension must be available; the call is routed through Invoke-ALbuildProcess so it is captured and testable. Authenticate either by a prior 'az login' or by passing -AccessToken (a PAT), which is exported as AZURE_DEVOPS_EXT_PAT for the download only.
Syntax
Code
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
-Organization | String | Yes | The Azure DevOps organization - a full URL (https://dev.azure.com/org) or a bare org name. |
-Feed | String | Yes | The feed name. |
-Name | String | Yes | The Universal package name. |
-Version | String | No | The package version, or '' for the latest. Default ''. Default: '*'. |
-OutputFolder | String | Yes | The folder to download the package contents into (created if missing). |
-Project | String | No | Project name for a project-scoped feed. Omit for an organization-scoped feed. |
-AccessToken | String | No | A personal access token used for authentication (exported as AZURE_DEVOPS_EXT_PAT). |
-AzExecutable | String | No | The Azure CLI executable. Default 'az'. Default: 'az'. |
Output
PSCustomObject: Name, Version, OutputFolder, Files.
Examples
Example 1
Code
Invoke-BcPackagePromotion
Promotes a published NuGet package version to a view on an Azure DevOps Artifacts feed.
Azure DevOps Artifacts feeds expose 'views' (e.g. @Prerelease, @Release). Promoting a package version to a view lets partners consume it from a view-scoped feed URL (.../_packaging/<feed>@Prerelease/nuget/v3/index.json), which is how ALbuild distributes prerelease (dev) and release (master) app packages from one feed.
The view assignment is a one-shot PATCH against the Azure DevOps Packaging REST API (it is not part of the NuGet protocol). The feed's v3 index URL is parsed to derive the organisation, optional project and feed name. Promotion is OPT-IN: when -View is not supplied the cmdlet is a no-op and returns $true, so callers can pass the parameter through unconditionally.
Syntax
Code
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
-Url | String | Yes | The feed's NuGet v3 service index URL (.../nuget/v3/index.json) on an Azure DevOps Artifacts host (pkgs.dev.azure.com or *.pkgs.visualstudio.com). |
-View | String | No | Target view name, e.g. 'Prerelease' or 'Release' (any custom view name is accepted). When empty or omitted, no promotion is performed. |
-ApiKey | String | Yes | The Azure DevOps PAT used for the REST call (a Packaging read/write token, the same one used to publish). |
-PackagePath | String | No | Path to the .nupkg. The package id and version are read from its .nuspec. Mutually exclusive with -PackageId/-Version. |
-PackageId | String | Yes | Explicit package id. Use with -Version instead of -PackagePath. |
-Version | String | Yes | Explicit package version. Use with -PackageId instead of -PackagePath. |
Output
System.Boolean ($true on success or when there is nothing to promote).
Examples
Example 1
Code
New-BcNuGetPackage
Creates a NuGet package (.nupkg) that contains a Business Central .app.
Reads the .app manifest, derives the package id from the id scheme (or uses -PackageId), and produces a valid OPC NuGet package (with [Content_Types].xml and relationships) containing the .app and a generated .nuspec. Application/platform dependency ranges and extra dependencies can be declared (used by, for example, runtime packages).
Syntax
Code
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
-AppFile | String | Yes | Path to the .app (or .runtime.app) file. |
-PackageId | String | No | Explicit package id. If omitted, derived from -IdScheme and the app identity. |
-IdScheme | String | No | Package id template when -PackageId is not supplied. Default '{publisher}.{name}.{id}'. Default: '{publisher}.{name}.{id}'. |
-Version | String | No | Package version. Default: the app version. |
-Authors | String | No | Package authors. Default: the app publisher. |
-Description | String | No | Package description. Default: the app name. |
-Dependency | Object[] | No | Additional NuGet dependencies as @{ id = ...; version = ... } hashtables. |
-OutputFolder | String | No | Output folder for the .nupkg. Default: the app file's folder. |
Output
System.String - the path to the created .nupkg.
Examples
Example 1
Code
Publish-BcPackage
Pushes a NuGet package (.nupkg) to a NuGet v3 feed.
Resolves the feed's PackagePublish service from its service index and uploads the package using a multipart PUT (the NuGet v3 push protocol). An existing package version is reported as a conflict rather than failing the build (unless -FailOnConflict is set).
Syntax
Code
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
-PackagePath | String | Yes | Path to the .nupkg to push. |
-Url | String | Yes | The feed's NuGet v3 service index URL (.../index.json). |
-ApiKey | String | Yes | The API key (nuget.org) or PAT (Azure DevOps/GitHub) for publishing. |
-FailOnConflict | switch | No | Throw if the package version already exists. Default: warn and continue. |
-View | String | No | Optional Azure DevOps Artifacts view (e.g. 'Prerelease' or 'Release') to promote the package to after a successful push. When omitted, only the push is performed. Promotion still runs when the version already existed (a non-failing conflict), since promoting an existing version is valid. Ignored for non-Azure-DevOps feeds (Invoke-BcPackagePromotion throws if misused there). |
Output
System.Boolean ($true on success or conflict-when-not-failing).
Examples
Example 1
Code
Example 2
Code
Register-BcFeed
Registers a NuGet package feed for dependency resolution.
Creates a NuGet v3 feed provider and stores it in the session's feed registry. Registered feeds are used by Resolve-BcDependencies (unless feeds are passed explicitly). Use -IncludeMicrosoftDefaults to also register Microsoft's public BC feeds (MSSymbols, AppSourceSymbols, MSApps).
Syntax
Code
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
-Name | String | Yes | A unique name for the feed. |
-Url | String | Yes | The NuGet v3 service index URL (.../index.json). |
-Token | String | No | Optional access token (PAT) for authenticated feeds. |
-IdScheme | String | No | Package id template. Default '{publisher}.{name}.{id}'. Default: '{publisher}.{name}.{id}'. |
-Kind | String | No | Package kind: symbols (default), apps or runtime. Allowed values: symbols, apps, runtime. Default: 'symbols'. |
-CacheFolder | String | No | Package cache folder. Defaults to the configured PackageCacheFolder. |
-IncludeMicrosoftDefaults | switch | Yes | Also register Microsoft's public BC feeds. |
-FromProjectConfig | String | Yes | Register every feed declared in a project's albuild.json (the 'feeds' array). The value is the app/project folder; the workspace-root config is merged in when -WorkspaceRoot is given. Each entry is a URL string or an object { url, name?, kind?, idScheme?, token?, tokenEnv? }; only 'url' is required. This lets developers declare feeds once in albuild.json instead of repeating Register-BcFeed calls in every pipeline. |
-WorkspaceRoot | String | No | Workspace root holding the shared albuild.json, merged under the app-folder config. |
Output
The registered provider object(s).
Examples
Example 1
Code
Example 2
Code
Resolve-BcDependencies
Resolves an AL project's dependencies across feeds and writes them to .alpackages.
Reads the project's app.json, resolves a mutually-compatible, transitively-complete set of dependency packages from the given (or registered) feeds - respecting the target build's platform/application versions and any apps already installed in the build (pinned, e.g. Microsoft first-party apps) - then downloads them in dependency order and writes a dependencies.lock.json for reproducible builds.
Syntax
Code
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
-ProjectFolder | String | Yes | The AL project folder (contains app.json). |
-Feeds | Object[] | No | Feed provider objects. When omitted, uses the feeds registered with Register-BcFeed plus any feeds declared in the project's albuild.json ('feeds' array) - so a pipeline can simply call Resolve-BcDependencies without repeating Register-BcFeed. |
-WorkspaceRoot | String | No | Workspace root holding the shared albuild.json (merged under the project-folder config) when auto-loading feeds from configuration. Ignored when -Feeds is supplied. |
-InstalledApps | Object[] | No | Apps already present in the target build (objects with AppId/Id and Version), pinned as a baseline. Typically Get-BcContainerAppInfo output. |
-TargetApplication | String | No | Target application version. Defaults to app.json 'application'. |
-TargetPlatform | String | No | Target platform version. Defaults to app.json 'platform'. |
-Select | String | No | Latest (default; the newest version compatible with the target build) or LowestCompatible (the oldest version that still satisfies every constraint, for maximally reproducible builds). Allowed values: LowestCompatible, Latest. Default: 'Latest'. |
-OutputFolder | String | No | Where to place resolved .app files. Default: <ProjectFolder>/.alpackages. |
-LockFilePath | String | No | Where to write the lock file. Default: <ProjectFolder>/dependencies.lock.json. |
-SkipDownload | switch | No | Resolve and write the lock file without downloading packages. |
Output
PSCustomObject with Resolved, OutputFolder, LockFile, Packages.
Examples
Example 1
Code
Resolve-BcDependencyCeiling
Picks the BC version that dependency resolution should cap against, from the available sources.
Pure helper (no I/O, unit-testable) for the Resolve Dependencies task. The dependency version ceiling is the BC version being built against - NOT app.json 'application'/'platform', which are the app's minimum supported versions (using those as the ceiling makes the resolver reject real dependency apps built for the current BC and fall back to symbol-only AppSource packages).
Precedence, highest first:
- TargetVersionInput - an explicit pipeline value. Defaults (in the task) to $(bcArtifactVersion) from Get BC Artifact, so a CONTAINER-LESS build still honours the BC version it targets; can also be an author override. An unexpanded '$(...)' macro or an empty value is ignored (a container-less run leaves the default macro unexpanded).
- InstalledApp - the platform app installed in the build container (exact build BC version); preserves the original container-based behaviour.
- ConfigBcVersion - the 'bcVersion' pinned in albuild.json. Returns an empty Version (Source 'none') when nothing is available, so the caller resolves the newest version each app.json is compatible with.
Syntax
Code
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
-TargetVersionInput | String | No | The task's 'targetVersion' input value (may be empty or an unexpanded '$(...)' macro). |
-InstalledApp | Object[] | No | The apps installed in the build container (objects with Name/Version), or empty for none. |
-ConfigBcVersion | String | No | The 'bcVersion' from albuild.json, or empty. |
Output
PSCustomObject: Version (string, '' when none) and Source (string).
Resolve-BcExternalDependency
Syntax
Code
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
-UniversalPackages | Object[] | No | |
-LocalPackage | String[] | No | |
-UrlPackage | Object[] | No | |
-OutputFolder | String | Yes | |
-Organization | String | No | |
-Project | String | No | |
-AccessToken | String | No | |
-RequireUniversalPackages | switch | No | |
-BaseFolder | String | No | Default: (Get-Location).Path. |
-ContainerName | String | No | |
-DockerExecutable | String | No | Default: 'docker'. |
Select-BcArtifactForDependencies
Picks the newest Business Central artifact whose build every project's dependencies still resolve against - stepping back through minor versions when an ISV has not yet shipped packages for the latest BC (dependency-aware selection with downgrade-on-conflict).
For 'Select = Latest' pipelines only. Enumerates the latest artifact and up to -MaxStepsBack earlier minor versions (crossing a major boundary to the previous major's latest minor when a minor reaches x.0), and - newest first - dry-runs Resolve-BcDependencies (-SkipDownload) for every project against that build. The first version where all projects resolve is chosen. If it is older than the latest, 'Downgraded' is set and 'ConflictReason' explains why the latest was skipped (the caller emits the pipeline warning). Throws if nothing within the window resolves. Because it uses an explicit target build and a synthetic Microsoft baseline, no container is needed - the choice is made before the (single) container is created.
A specific -Version pins the choice: enumeration/downgrade only runs when no explicit version is given.
Syntax
Code
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
-ProjectFolder | String[] | Yes | The AL project folder(s) to resolve. Every one must resolve for a version to be chosen. |
-Type | String | No | Artifact type (Sandbox or OnPrem). Default 'Sandbox'. Default: 'Sandbox'. |
-Country | String | No | Artifact country/localisation. |
-Version | String | No | Explicit version/prefix. When given, that version is returned as-is (no downgrade search). |
-MaxStepsBack | Int32 | No | Maximum number of minor versions to step back from the latest. Default 5. Default: 5. |
-Feeds | Object[] | No | Feed provider objects for the resolver (as Resolve-BcDependencies -Feeds). When omitted the resolver auto-loads the project/registered feeds. |
-InstalledApps | Object[] | No | Baseline apps pinned in every dry-run - the already-staged external dependencies (url/local/universal) so the resolver treats them as satisfied instead of fetching from a feed. |
Output
PSCustomObject: ArtifactUrl, Version, LatestVersion, Downgraded, StepsBack, ConflictReason.


