Containers/New-Container.ps1
<# .Synopsis Creates a new NAV/BC container .Description Creates a new NAV/BC container .Parameter ContainerName Name of the container .Parameter Version Version of NAV or BC to create .Parameter LicenseFile Path to license file. It can be an Uri and then the license will be downloaded .Parameter Credential Credentials to be used for login to the container. .Parameter Country Country version of the container. .Parameter ArtifactUrl Specifies the Artifact Url .Parameter databaseBackup Defines the BAK or bacpac of a database to use to restore into the container .Parameter sqlServer Specify an external SQL Server, if the database is already there or should be deployed on the SQL Server .Parameter sqlDatabase Specify a database on an external SQL Server .Parameter sqlCredential Specify credentials to connect to the external SQL Server .Parameter memoryLimit Defines the memory limit for the docker container. The default limit is 12GB .Parameter singleTenant Defines, if the database is single tenant .Parameter skipAlwaysPull Always pull latest version of the docker image be default. This overrides the default .Parameter SetupTestUsers Creates test users in the container after it is created .Parameter AddTestTool Add this switch if you do not want to install the test tool .Parameter skipBackup Add this switch if you do not want to use database backups from previous containers .Parameter useHyperVIsolation Add this switch if you want to force Hyper V isolation when creating the container .Parameter enableTaskScheduler Include this switch if you want to do Enable the Task Scheduler .Parameter disableHttps Turns off SSL for access to the environment .Example New-Container -SetupTestUsers #> function New-Container { [CmdletBinding(SupportsShouldProcess, ConfirmImpact="low")] Param( [Parameter(Mandatory = $false)] [string] $ContainerName, [Parameter(Mandatory = $true, ParameterSetName = 'Version')] [string] $Version, [Parameter(Mandatory = $false, ParameterSetName = 'Version')] [string] $CU = "", [Parameter(Mandatory = $false, ParameterSetName = 'Version')] [string] $Country = "", [Parameter(Mandatory = $false)] [string] $LicenseFile, [Parameter(Mandatory = $false)] [pscredential] $Credential, [Parameter(Mandatory = $false)] [Parameter(Mandatory = $true, ParameterSetName = 'Artifact')] [Parameter(Mandatory = $false, ParameterSetName = 'SQLServer')] [string] $ArtifactUrl = "", [Parameter(Mandatory = $false)] [ValidateSet('', 'OnPrem','Sandbox')] [string] $target = "", [Parameter(Mandatory = $false)] [string] $databaseBackup = "", [Parameter(Mandatory = $false)] [Parameter(Mandatory = $true, ParameterSetName = 'SQLServer')] [string] $sqlServer = "", [Parameter(Mandatory = $false)] [Parameter(Mandatory = $false, ParameterSetName = 'SQLServer')] [string] $sqlInstance = "", [Parameter(Mandatory = $false)] [Parameter(Mandatory = $false, ParameterSetName = 'SQLServer')] [string] $sqlDatabase = "", [Parameter(Mandatory = $false)] [Parameter(Mandatory = $true, ParameterSetName = 'SQLServer')] [pscredential] $sqlCredentials = $null, [Parameter(Mandatory = $false)] [Parameter(Mandatory = $false, ParameterSetName = 'SQLServer')] [boolean] $sqlReplaceExternalDBs = $false, [Parameter(Mandatory = $false)] [ValidatePattern("^(\d+)(GB|gb)$")] [string] $memoryLimit = '12g', [switch] $singleTenant, [switch] $skipAlwaysPull, [switch] $SetupTestUsers, [switch] $AddTestTool, [switch] $skipBackup, [switch] $useHyperVIsolation, [switch] $enableTaskScheduler, [switch] $disableHttps, [switch] $forceRebuild ) if ($PSCmdlet.ShouldProcess("Container", "This will create a new ")) { Write-Output @' _____ _ _____ _ | __ \ (_) | __ \ | | | |__) | __ ___ _ __ __ _ _ __ _ _ __ __ _ | |__) |_ _ _ __ __ _ _ __ ___ ___| |_ ___ _ __ ___ | ___/ '__/ _ \ '_ \ / _` | '__| | '_ \ / _` | | ___/ _` | '__/ _` | '_ ` _ \ / _ \ __/ _ \ '__/ __| | | | | | __/ |_) | (_| | | | | | | | (_| | | | | (_| | | | (_| | | | | | | __/ || __/ | \__ \ |_| |_| \___| .__/ \__,_|_| |_|_| |_|\__, | |_| \__,_|_| \__,_|_| |_| |_|\___|\__\___|_| |___/ | | __/ | |_| |___/ '@ $os = (Get-CimInstance Win32_OperatingSystem) $isServerHost = $os.ProductType -eq 3 $useSSL = !$disableHttps.IsPresent if (!$useHyperVIsolation.IsPresent -and !$isServerHost -and $os.BuildNumber -eq 22621 -and $useSSL) { Write-Output "Disabling SSL due to a bug in Windows 11" $useSSL = $false } $settings = Import-Config Set-ProperContext -settings $settings | Out-Null $SourcePath = Get-Location $dockerImageName = "" $ContainerName = Get-NewContainerName -SourcePath $SourcePath -ContainerName $ContainerName if ($null -eq $Credential) { $NewCredential = Get-CredentialFromEnvironmentJson -SourcePath $SourcePath $Credential = $NewCredential } $Password = $Credential.Password $ArtifactUrl = Get-ProperArtifactUrl -Version ([ref]$Version) -Cu $CU -Country ([ref]$country) -ArtifactUrl $ArtifactUrl -target ([ref]$target) -imageName ([ref]$dockerImageName) -SourcePath $SourcePath if ($LicenseFile -eq "") { $LicenseFile = Get-LicenseFile -Publisher (Get-AppKeyValue -SourcePath $SourcePath -KeyName 'Publisher') -Version $Version -Settings $settings } Write-Output "Version: $Version" if ($CU -ne "" -and $null -ne $CU) { Write-Output "Cumulative Update: $CU" } Write-Output "Country: $Country" Write-Output "Artifact Url: $artifactUrl" Write-Output "Image: $dockerImageName" [version]$platform = Get-VersionAppJson -SourcePath $SourcePath -ArtifactUrl $ArtifactUrl if ($platform.Major -lt 15) { $skipBackup = $true } #disable using backup, since this is currently possibly causing issues as well $skipBackup = $true if (!$skipBackup.IsPresent) { if (!(Test-Path "C:\.backups")) { New-Item -Path "C:\.backups" -ItemType Directory | Out-Null } if ($Country -eq "") { $Country = Get-EnvironmentKeyValue -KeyName "locale" -SourcePath $SourcePath } $bakFolder = (Join-Path "C:\.backups" $platform) $bakFolder = (Join-Path $bakFolder $Country) if (Test-Path (Join-Path $bakFolder "*")) { Write-Output "Backups: Yes" } } else { Write-Output "Backups: No" } if ($sqlServer -ne "") { Write-Output "Using SQL Server: $sqlServer" Write-Output " SQL instance: $sqlInstance" Write-Output " Database: $sqlDatabase" } $customLicenseFile = Get-FileFromStorage -fileName $LicenseFile # custom scripts to fix different BcContainerHelper issues $startParameters = @{ accept_eula = $true accept_outdated = $true updateHosts = $true useBestContainerOS = $true doNotExportObjectsToText = $true forceRebuild = $forceRebuild.IsPresent useSSL = $useSSL auth = "UserPassword" containerName = $ContainerName Credential = $Credential artifactUrl = $artifactUrl imageName = $dockerImageName licenseFile = $customLicenseFile memoryLimit = $memoryLimit SQLMemoryLimit = '50%' Timeout = 180 } if ($useSSL -and $Version -eq "2016") { $startParameters.Add("myscripts", @("https://raw.githubusercontent.com/microsoft/nav-docker/master/override/SelfSignedCertificateEx/SetupCertificate.ps1")) } $localBackup = "" if ($databaseBackup -ne "") { $localBackup = Get-FileFromStorage -fileName $databaseBackup if ((Split-Path $localBackup -Leaf).Split('.')[-1].ToLower() -eq 'bak') { $startParameters.Add('bakFile', $localBackup) } } if ($useHyperVIsolation.IsPresent) { $startParameters.Add('isolation', 'HyperV') } if (Get-EnvironmentKeyValue -KeyName "usePremium" -SourcePath $SourcePath) { $startParameters.Add('assignPremiumPlan', $true) } $isStandardTesting = Get-UseStandardTest -MajorVersion $platform.Major -SourcePath $SourcePath if ($AddTestTool.IsPresent) { if ($isStandardTesting) { $startParameters.Add('includeTestToolkit', $true) } } if ($platform.Major -le 14) { $startParameters.Add('shortcuts', 'DesktopFolder') # Turn off symbol loading for now # $startParameters.Add('enableSymbolLoading', $false) } else { $startParameters.Add('shortcuts', 'None') $startParameters.Add('enableSymbolLoading', $false) } if (!$skipAlwaysPull.IsPresent) { $startParameters.Add('alwaysPull', $true) } if ($platform.Major -le 14) { $startParameters.Add('includeCSide', $true) $startParameters.Add('clickonce', $true) } if (!$skipBackup.IsPresent) { $startParameters.Add('bakFolder', $bakFolder) $startParameters.Add('additionalParameters', @("-v C:\.backups:C:\.backups")) } if ($enableTaskScheduler.IsPresent) { $startParameters.Add('enableTaskScheduler', $true) } else { $startParameters.Add('enableTaskScheduler', $false) } if ($singleTenant.IsPresent) { $startParameters.Add('multitenant', $false) } # turn off health check for CPU usage $startParameters.Add('doNotCheckHealth', $true) # DNS fix $startParameters.Add('dns', '8.8.8.8') # Add Sql Server if ($sqlServer -ne "") { $startParameters.Add('databaseServer', $sqlServer) } if ($sqlInstance -ne "") { $startParameters.Add('databaseInstance', $sqlInstance) } if ($sqlDatabase -ne "") { $startParameters.Add('databaseName', $sqlDatabase) $startParameters.Add('replaceExternalDatabases', $sqlReplaceExternalDBs) $startParameters.Add('databasePrefix', "$($ContainerName)-") } if ($null -ne $sqlCredentials) { $startParameters.Add('databaseCredential', $sqlCredentials) } # Containers are now created as multitenant. Turn this off for anything but the newer versions (greater or equal BC15) if ($platform.Major -lt 15) { $startParameters.Add('multitenant', $false) } if ($SetupTestUsers.IsPresent) { $startParameters.Add('finalizeDatabasesScriptBlock', {Setup-BcContainerTestUsers -containerName $ContainerName -password $Password -credential $Credential}) } Write-Output "Container creation parameters:" $startParameters.GetEnumerator() | ForEach-Object { Write-Output (" {0}: {1}" -f $_.Key, $_.Value) } Write-Output @' _____ _ _ _____ _ _ / ____| | | (_) / ____| | | (_) | | _ __ ___ __ _| |_ _ _ __ __ _ | | ___ _ __ | |_ __ _ _ _ __ ___ _ __ | | | '__/ _ \/ _` | __| | '_ \ / _` | | | / _ \| '_ \| __/ _` | | '_ \ / _ \ '__| | |____| | | __/ (_| | |_| | | | | (_| | | |___| (_) | | | | || (_| | | | | | __/ | \_____|_| \___|\__,_|\__|_|_| |_|\__, | \_____\___/|_| |_|\__\__,_|_|_| |_|\___|_| __/ | |___/ '@ Flush-ContainerHelperCache -cache bcartifacts -keepDays 7 New-BcContainer @startParameters if ($localBackup -ne "") { if ((Split-Path $localBackup -Leaf).Split('.')[-1].ToLower() -eq 'bacpac') { $containerPath = Join-Path "C:\Run\My" (Split-Path $localBackup -Leaf) Copy-FileToBcContainer -containerName $ContainerName -localPath $localBackup -containerPath $containerPath Invoke-ScriptInBcContainer -containerName $ContainerName -scriptblock { Param($containerPath, $database) Invoke-SqlCmd ` -Query "EXEC sp_configure 'contained', 1;RECONFIGURE;" ` -ServerInstance "localhost\SQLEXPRESS" Restore-BacpacWithRetry ` -bacpac $containerPath ` -databasename $database ` -maxattempts 1 } -argumentList $containerPath, $ContainerName $tenantId = 'default' if ($singleTenant.IsPresent) { Invoke-ScriptInBcContainer -containerName $ContainerName -scriptblock { Param($database, $serverInstance) Set-NAVServerConfiguration ` -ServerInstance $serverInstance ` -KeyName DatabaseName ` -KeyValue $database Restart-NAVServerInstance ` -ServerInstance $serverInstance Sync-NavTenant ` -ServerInstance $serverInstance ` -Force } -argumentList $ContainerName, ((Get-BcContainerServerConfiguration -ContainerName $ContainerName).ServerInstance) } else { $tenantId = $ContainerName Invoke-ScriptInBCContainer -containerName $containerName -scriptblock { Param($database, $tenantId, $serverInstance) Mount-NavTenant ` -ServerInstance $serverInstance ` -id $tenantId ` -databasename $database ` -databaseserver localhost ` -databaseinstance SQLEXPRESS ` -EnvironmentType Sandbox ` -OverwriteTenantIdInDatabase ` -Force Sync-NavTenant ` -ServerInstance $ServerInstance ` -Tenant $tenantId ` -Force } -argumentList $ContainerName, $tenantId, ((Get-BcContainerServerConfiguration -ContainerName $ContainerName).ServerInstance) } New-BcContainerBcUser ` -containerName $containerName ` -Credential $Credential ` -ChangePasswordAtNextLogOn:$false ` -PermissionSetId SUPER ` -tenant $tenantId } } # Write-Output @' # # _____ _ _ _ _ # |_ _| | | (_) | | (_) # | | _ __ ___ _ __ ___ _ __| |_ _ _ __ __ _ | | _ ___ ___ _ __ ___ ___ # | | | '_ ` _ \| '_ \ / _ \| '__| __| | '_ \ / _` | | | | |/ __/ _ \ '_ \/ __|/ _ \ # _| |_| | | | | | |_) | (_) | | | |_| | | | | (_| | | |____| | (_| __/ | | \__ \ __/ # |_____|_| |_| |_| .__/ \___/|_| \__|_|_| |_|\__, | |______|_|\___\___|_| |_|___/\___| # | | __/ | # |_| |___/ # #'@ # # Import-BcContainerLicense -containerName $ContainerName -licenseFile $customLicenseFile -restart if ($platform.Major -le 11) { Write-Output @' _ _ _ _ _ _ _ _____ | | | | | | | | (_) /\ | | | | |_ _| | | | |_ __ __| | __ _| |_ _ _ __ __ _ / \ __| | __| |______| | _ __ ___ | | | | '_ \ / _` |/ _` | __| | '_ \ / _` | / /\ \ / _` |/ _` |______| | | '_ \/ __| | |__| | |_) | (_| | (_| | |_| | | | | (_| | / ____ \ (_| | (_| | _| |_| | | \__ \ \____/| .__/ \__,_|\__,_|\__|_|_| |_|\__, | /_/ \_\__,_|\__,_| |_____|_| |_|___/ | | __/ | |_| |___/ '@ Invoke-ScriptInBcContainer -containerName $ContainerName -scriptblock { $sharedPath = "C:\navpfiles\" + $args[0] + "0\RoleTailored Client\" $programPath = "C:\Program Files (x86)\Microsoft Dynamics NAV\" + $args[0] + "0\RoleTailored Client\" Write-Output "Copying add-in files to shared files" Copy-Item "C:\Program Files\Microsoft Dynamics NAV\*\Service\Add-Ins\" $sharedPath -recurse -Force Write-Output "Copying add-in files to program files" Copy-Item "C:\Program Files\Microsoft Dynamics NAV\*\Service\Add-Ins\" $programPath -Recurse -Force } -ArgumentList $platform.Major } if ($AddTestTool.IsPresent) { if (!$isStandardTesting) { Write-Output @' _____ _ _______ _ _ |_ _| | | |__ __| | | (_) | | _ __ ___ _ __ ___ _ __| |_ | | ___ ___| |_ _ _ __ __ _ | | | '_ ` _ \| '_ \ / _ \| '__| __| | |/ _ \/ __| __| | '_ \ / _` | _| |_| | | | | | |_) | (_) | | | |_ | | __/\__ \ |_| | | | | (_| | |_____|_| |_| |_| .__/ \___/|_| \__| |_|\___||___/\__|_|_| |_|\__, | | | __/ | |_| |___/ '@ Import-Testing -containerName $ContainerName } } if ($platform.Major -ge 15) { Wait-ForTenantReady -containerName $ContainerName -tenant "default" } } } Export-ModuleMember New-Container |