By Steve Endow
I have an ERP joke for you...
Find a consultant who supports an on premises ERP application for dozens or hundreds of customers.
Ask them which of the 7 different VPN clients on their laptop is their favorite.
(rim shot)
![]() |
| Just say no |
Steve Endow is a Microsoft MVP who works with Microsoft Dynamics 365 Business Central, Azure, .NET, SQL Server, and Power Platform
Dynamics 365 BC Resources List:
steveendow.link/bcresources
OR: bit.ly/bcresources
By Steve Endow
After seeing a few very cool Business Central features the other day, I was so impressed and in such a good mood that I might have posted a slightly overly enthusiastic tweet.
![]() |
| Can't a guy be in a really good mood? |
Does Business Central do my dishes? My laundry? Paint my house?
Sadly, it does not. Yet. 😉
But it does do lots of awesome things and it has some amazing features and benefits. And after posting my happy tweet, I think a few people are wondering why I think Business Central is so amazing.
So now I feel obligated to explain why I think it's amazing, and in the process, share my enthusiasm for the new ERP platform that I'm learning about.
By Steve Endow
UPDATE: If you're interested in a convenient way to run the BcContainerHelper PowerShell commands, check out Krzysztof's Azure Data Studio Notebook with sample BcContainerHelper commands. Jupyter Notebooks are a great way to include documentation and commands in a single convenient format.
On August 11, 2020, Freddy Kristiansen announced that he had released BcContainerHelper.
You can read his blog post here:
https://freddysblog.com/2020/08/11/bccontainerhelper/
You will definitely want to read the entire blog post carefully, and perhaps read it a few times, as he shares quite a few important details about the new BcContainerHelper.
![]() |
| Same Great Container Helper, But Updated and Upgraded! |
I made a video showing how I updated from NavContainerHelper to BcContainerHelper. The process went flawlessly.
Here are the PowerShell Docker commands that I used to perform my update.
![]() |
| No soup for you! |
![]() |
| Email notification when an update occurs |
#v2.0 - June 22, 2021
#
$server = $env:COMPUTERNAME
#Define date values
$simpleDate = Get-Date -Format "M/d/yy"
$dateTime = Get-Date -Format "M/d/yy HH:mm"
$fileDateTime = Get-Date -Format "yyyy-MM-dd HHmm"
#Define the module name
$moduleName = 'BcContainerHelper'
$body = ""
$message = ""
$updated = $false
#Specify file location for activity transcript log file
$transcriptFile = "D:\BCPowerShell\Logs\" + $fileDateTime + " " + $server + " " + $moduleName + " Update Log.txt"
#Start recording transcript
Start-Transcript -Path $transcriptFile
#Record the start time
$StartTime = $(get-date)
#Define email configuration
$emailFrom = "myemail@gmail.com"
$emailTo = "myemail@gmail.com"
$smtpServer = "smtp.gmail.com"
$port = "587"
#Email password file created using: Read-Host -AsSecureString | ConvertFrom-SecureString | Out-File -FilePath D:\BCPowerShell\Gmail.securestring
$passwordFile = "D:\BCPowerShell\Gmail.securestring"
$securePassword = ConvertTo-SecureString (Get-Content -Path $passwordFile)
$smtpCred = New-Object -TypeName PSCredential ($emailFrom, $securePassword)
$subject = $server + ": " + $simpleDate + " " + $moduleName + " Update Log";
$started = "Start time: " + $StartTime
$body += $started + "`n`n"
Try
{
#Get currently installed version
$currentVersion = (Get-InstalledModule $moduleName -ErrorAction SilentlyContinue).Version.ToString()
}
Catch
{
$currentVersion = "(not installed)"
}
$oldVersion = $currentVersion
#Get the latest version available
$latestVersion = (Find-Module $moduleName).Version.ToString()
#If we don't have the latest version installed
If ($currentVersion -ne $latestVersion)
{
$message = "Current version: " + $currentVersion + "`nLatest version: " + $latestVersion;
$message += "`n`nUpdating to version " + $latestVersion;
#Remove existing version(s)
Uninstall-Module $moduleName -Force -AllVersions -ErrorAction SilentlyContinue
#Install latest version
Install-Module $moduleName -Force
$updated = $true;
#Verify version number
$newVersion = (Get-InstalledModule $moduleName).Version.ToString()
$message += "`nUpdate complete";
$message += "`nCurrent version is now " + $newVersion;
$body += "`n" + $message;
Write-Output $message
}
Else
{
#If we are on the latest version, log that info
$message = "You are on the latest version of " + $moduleName + ": " + $newVersion;
Write-Output $message
}
#Record end time
$EndTime = $(get-date)
$output = "`nEnd time: " + $EndTime
$body += "`n" + $output
Write-Output $output
#Calculate elapsed time
$elapsedTime = $EndTime - $StartTime
$totalTime = "{0:HH:mm:ss}" -f ([datetime]$elapsedTime.Ticks)
$output = "Elapsed time: " + $totalTime
$body += "`n" + $output
Write-Output $output
$body += "`n`nFull log file is attached"
#Finish the transcript recording
#The Transcript must be stopped before trying to send the email,
#otherwise the log file will be locked, causing the email to fail
Stop-Transcript
if ($updated)
{
#Send the email
Send-MailMessage -From $emailFrom -To $emailTo `
-Subject $subject `
-Body $body `
-Attachments $transcriptFile `
-SmtpServer $smtpServer `
-Credential $smtpCred `
-Port $port `
-UseSsl
}
![]() |
| Just tell me how it went... |
![]() |
| Ya gotta measure things |
$StartTime = $(get-date)
Try {
$output = "Started: " + $StartTime
Write-Output $output
$containerName = 'bc1'
$password = 'P@ssw0rd'
$securePassword = ConvertTo-SecureString -String $password -AsPlainText -Force
$credential = New-Object pscredential 'admin', $securePassword
$auth = 'UserPassword'
$artifactUrl = Get-BcArtifactUrl -type 'Sandbox' -version '' -country 'us' -select 'Latest'
New-BcContainer `
-accept_eula `
-containerName $containerName `
-credential $credential `
-auth $auth `
-artifactUrl $artifactUrl `
-imageName 'myimage1' `
-dns '8.8.8.8' `
-updateHosts
}
Catch {
Write-Error "Um, something didn't go well:"
Write-Error $_
}
Finally {
$EndTime = $(get-date)
$output = "End time: " + $EndTime
Write-Output $output
$elapsedTime = $(get-date) - $StartTime
$totalTime = "{0:HH:mm:ss}" -f ([datetime]$elapsedTime.Ticks)
$output = "Elapsed time: " + $totalTime
Write-Output $output
}
![]() |
| Building a new named image vs. using an existing named image |
$MyModuleName = 'NavContainerHelper'
Uninstall-Module $MyModuleName -Force -AllVersions
Install-Module $MyModuleName -Force
![]() |
| The Script |
![]() |
| Windows Task Scheduler |
![]() |
| Task - General Info |
![]() |
| Nightly update |
![]() |
| PowerShell isn't too bad |
Open Powershell / Powershell ISE on HOST machine using Run As Administrator
NOTE: When referring to a Container ID or Image ID, you can use the first
few characters of the ID if they are unique--you do not have to always
use the full ID.
Check NavContainerHelper Version
Get-InstalledModule NavContainerHelper
Fresh Install of NavContainerHelper
Install-module navcontainerhelper
Import-Module navcontainerhelper
Install Latest NavContainerHelper
If you KNOW you don't have multiple versions installed:
Update-Module NavContainerHelper -Force
If you MIGHT have multiple versions installed:
$MyModuleName = <modulename>
Uninstall-Module $MyModuleName -allversions
Install-Module $MyModuleName
NOTE: I do not recommend using the -Force option with Install-Module.
It can bypass valuable warnings that you want to know about.
Alternate method to Remove Old Versions of NavContainerHelper
$ModuleName = 'navcontainerhelper';
$Latest = Get-InstalledModule $ModuleName;
Get-InstalledModule $ModuleName -AllVersions | ? {$_.Version -ne $Latest.Version} | Uninstall-Module -WhatIf
Container Management Commands
Compact Container listing:
docker ps --format "table {{.Names}}\t{{.ID}}\t{{.CreatedAt}}\t{{.Status}}"
Full listing:
docker ps
docker ps -a
docker start <id>
docker stop <id>
docker container inspect
Remove Container
Recommended method:
Remove-BCContainer <containername>
Manual Docker method:
docker stop <id>
docker rm <id>
Manually clean up hosts file
Manually remove desktop icons
Manually remove extensions from C:\ProgramData\NavContainerHelper\Extensions\
Stop all running containers:
docker stop $(docker ps -aq)
Images
docker images
docker images -a
Remove Image
docker rmi <id>
docker rmi <repository>:<tag>
Remove all images:
docker rmi $(docker images -aq)
Clean up old images
Remove orphaned images with "< none >" identifiers:
docker images -q -f dangling=true | % { docker rmi $_ }
Remove orphaned images:
docker image prune -f
Remove orphaned AND UNUSED images:
WARNING: Be careful with this: It will remove generic OS images used by NavContainerHelper!
docker image prune -a -f
Get Artifact Info for an existing BC Container:
Get-BcContainerArtifactUrl containername
Get-NavContainerArtifactUrl containername
Diagnostics
Get-BcContainerEventLog
Create New BC Container
New-BcContainerWizard
https://blog.baudson.de/blog/stop-and-remove-all-docker-containers-and-images
$containerName = 'sandbox1'
$password = 'P@ssword'
$securePassword = ConvertTo-SecureString -String $password -AsPlainText -Force
$credential = New-Object pscredential 'admin', $securePassword
$auth = 'UserPassword'
$artifactUrl = Get-BcArtifactUrl -type 'Sandbox' -version '' -country 'us' -select 'Latest'
$licenseFile = 'c:\zdisks\business central\2020-06bcv16license.flf'
New-BcContainer `
-accept_eula `
-containerName $containerName `
-credential $credential `
-auth $auth `
-artifactUrl $artifactUrl `
-updateHosts `
-assignPremiumPlan `
-licenseFile $licenseFile `
-dns '192.168.25.21' `
-imageName 'mybc16'
Setup-BcContainerTestUsers -containerName $containerName -Password $credential.Password -credential $credential
![]() |
| Sad Trombone |
![]() |
| The last few digits are the important ones |
![]() |
| I'm talkin' to you! |
![]() |
| Install-Module -Force Warning |
#Containers
docker ps
docker ps -a
docker start <id>
docker stop <id>
docker rm <id>
#Stop all running containers:
docker stop $(docker ps -aq)
#Images
docker images
docker images -a
docker rmi <id>
docker rmi <repository>:<tag>
#Check NavContainerHelper version
Get-InstalledModule
#Install Latest NavContainerHelper
$MyModuleName = <modulename>
Uninstall-Module $MyModuleName -allversions
Install-Module $MyModuleName -Force
![]() |
| Can I just ask for directions? |
by Steve Endow Playwright is a browser automation tool that can log into Business Central, navigate pages, enter data, click buttons, and sa...