I don’t write blog posts about every single version of the NavContainerHelper, but I wanted to call out a few things in this version.

.app instead of .fob

Both NavContainerHelper and the ARM templates ( has been using .fob files for setting up Business Central. Importing a .fob file, which contains code to setup test users and invoking this through Invoke-NavContainerCodeunit.

As many of you have discovered, Business Central CU4 and CU5 (and spring release) all have a bug, where Invoke-NavCodeunit does not work if you are using NavUserPassword authentication. This basically had the effect that all partners setting up test or demo environments through the ARM templates, started to run into problems.

This basically left me with 3 options:

  1. Stating that these versions could not be used with Docker and/or ARM templates in conjunction with AAD authentication or Test Users.
  2. Creating an ugly workaround for these versions.
  3. Accelerate the transformation of these .fob files to extensions and create a solution which will work in the future when we go to AL only.

I decided to go for #3 – and that is included in this version of NavContainerHelper.

The function Setup-NavContainerTestUsers is now downloading, publishing and installing an app. This app will expose an Api, which is invoked from PowerShell and after doings its job, the app is uninstalled and unpublished, leaving no trace.

The source for this app is here:

The other app is used for setting up the Azure Ad. This app is used in the ARM templates and the source can be found here:

Functions for invoking APIs

The new version has two new functions for communicating with APIs:

  • Get-NavContainerApiCompanyId will return the Company Id to be used when invoking APIs
  • Invoke-NavContainerApi will invoke an API.

The best way to describe the functions is to display how Setup-NavContainerTestUsers works in the new version:

$appfile = Join-Path $env:TEMP ""
Download-File -sourceUrl "" -destinationFile $appfile
Publish-NavContainerApp -containerName $containerName -appFile $appFile -skipVerification -install -sync

$companyId = Get-NavContainerApiCompanyId -containerName $containerName -tenant $tenant -credential $credential

$parameters = @{ 
  "name" = "CreateTestUsers"
  "value" = ([System.Runtime.InteropServices.Marshal]::PtrToStringAuto([System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($Password)))
Invoke-NavContainerApi -containerName $containerName -tenant $tenant -credential $credential -APIPublisher "Microsoft" -APIGroup "Setup" -APIVersion "beta" -CompanyId $companyId -Method "POST" -Query "testUsers" -body $parameters | Out-Null

UnPublish-NavContainerApp -containerName $containerName -appName CreateTestUsers -unInstall

Yes, I could have used Invoke-RestMethod directly, but then I would have to handle authentication and other things in all locations.

Invoke-NavContainerApi actually uses the IP address of the container to do the communication, and thus does not rely on updatehosts or other things being in place. It also disables SSL verification temporarily if the container uses SSL.

AL files

Another “new” feature is, that if you spin up your Business Central spring release container using -includeCSide and do not use -doNotExportObjectsToText, then you will now get three folders with source code:

  • Original-<version>-<country> which is the classic CSide representation of objects
  • Original-<version>-<country>-newsyntax which is the CSide representation of objects in new format.
  • Original-<version>-<country>-al which is all objects in the newsyntax folder converted to AL and basically your baseline for AL objects.

If you copy the content of the AL folder to another folder and initialize a git repository on those files, then you can import your objects, reexport everything as AL and copy them on top of the baseline.

This will make git disover the changes in your objects.

Try to run this:

$imageName = ""
$myalfolder = "c:\temp\myal"
$containerName = "temp"
$credential = New-Object pscredential 'admin', (ConvertTo-SecureString -String 'P@ssword1' -AsPlainText -Force)

New-NavContainer -accept_eula -containerName $containerName -imageName $imageName -includeCSide -licensefile C:\temp\license.flf -auth NavUserPassword -Credential $credential -updateHosts
$version = Get-NavContainerNavVersion -containerOrImageName $containerName
$baseAppFolder = "C:\ProgramData\NavContainerHelper\Extensions\Original-$version-al"
if (Test-Path $myalfolder) {
  remove-item -Path (Join-Path $myalfolder "*") -Recurse -Force
else {
  New-Item $myalfolder -ItemType Directory
Set-Location $myalfolder
& git init
Copy-Item -Path (Join-Path $baseAppFolder "*") -Destination $myalfolder
& git add .
& git commit --message "baseapp"

Now open $myalfolder in VSCode and you will see all your files:


You should also see that the source control branch indicates no changes.

Now you import your C/AL object modifications (or just modify a few objects) and then run this script (Remember that everything must be compiled in C/Side):

$ModifiedFolder = Convert-ModifiedObjectsToAl -containerName $containerName -sqlCredential $credential -doNotUseDeltas
Copy-Item -Path (Join-Path $ModifiedFolder "*") -Destination $myalfolder

As you can see this script just re-exports everything as AL and copies it on top of your baseline. Git will compare and discover what you actually changed:


This is by all means not perfect, but it is a starting point in finding your AL changes and starting to look at them and seeing whether it is right…


Freddy Kristiansen
Technical Evangelist


15 thoughts on “NavContainerHelper

  1. I’am using your scripts for automated build on tfs/azure devops which uses invoke-navcontainercodeunit for test result export. Do you have an updated version of that using invoke-navcontainerapi?


    • I implemented the changes in from the HelloWorld Repo and now i get this error:

      CommunicationError : Error while copying content to a stream.
      ClientSession in Error
      at AwaitState, C:\ProgramData\NavContainerHelper\Extensions\lep-ext-dev\PsTestTool\ClientContext.ps1: line 98
      at InvokeInteraction, C:\ProgramData\NavContainerHelper\Extensions\lep-ext-dev\PsTestTool\ClientContext.ps1: line 111
      at InvokeInteractionAndCatchForm, C:\ProgramData\NavContainerHelper\Extensions\lep-ext-dev\PsTestTool\ClientContext.ps1: line 120
      at OpenForm, C:\ProgramData\NavContainerHelper\Extensions\lep-ext-dev\PsTestTool\ClientContext.ps1: line 135
      at Run-Tests, C:\ProgramData\NavContainerHelper\Extensions\lep-ext-dev\PsTestTool\PsTestFunctions.ps1: line 132
      at , : line 33
      ClientSession in Error
      In C:\Program Files\WindowsPowerShell\Modules\navcontainerhelper\\ContainerHandling\Invoke-ScriptInNavContainer.ps1:31 Zeichen:13
      + Invoke-Command -Session $session -ScriptBlock $scriptbloc …
      + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      + CategoryInfo : OperationStopped: (ClientSession in Error:String) [], RuntimeException
      + FullyQualifiedErrorId : ClientSession in Error

      Should we continue the discussion on github navcontainerhelper?


      • You probably need to remove the -e webclient=N (which causes the container to be created without a webclient). Run-Tests uses the Client Services endpoint to connect and emulate a client for running the tests


      • Well i did that. In Fact i’am currently testing this locally not in the build agent.
        For this i’am using a script “Local-Test” which basicly runs:
        – compile-app.ps1
        – publish-app.ps1
        – run-tests.ps1

        there i’am using the sandbox container for execution which obviously has the webclient enabled.


      • Ok, not sure what the reason is, use this all the time myself. Basically run-tests uses the client endpoint hosted with the web client to run.
        Please open an issue here: and include the output from the container generation and the error from run-tests as well. I do not monitor blog post comments as closely as github issues – and on blog post comments, I am the only person who can answer. On github issues – other people can chime in as well (and it is easier to get an overview)


  2. Pingback: Calling SOAP Services from PowerShell - Dynamics 365 Business Central Community

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s