Public/New-UpgradeInitializationScript.ps1
# https://patorjk.com/software/taag/#p=display&h=1&f=Big&t=GetVariables enum UpgradeMode { LS_14_174_18 = 1 LS_14_18_TablesRenamingInV18 = 2 LS_14_18_TablesRenamingInV14 = 3 } function New-UpgradeInitializationScript { param ( [string] $ConfigFile, [switch] $IncludeCustomizationAppPlaceholders ) $loadFromConfigFile = $ConfigFile $includeCustomizationAppPlaceholders = $IncludeCustomizationAppPlaceholders $upgradeMode = [UpgradeMode]::LS_14_18_TablesRenamingInV14 if ($upgradeMode -eq [UpgradeMode]::LS_14_174_18) { throw "Upgrading from LS 14.2 -> LS 17.4 -> LS 18 is not supported." } $loadingFromConfigFile = $loadFromConfigFile -ne "" $minimumToLSVersion = "21.0" $country = "w1" Clear-Host $pshost = Get-Host $pswindow = $pshost.UI.RawUI $minWidth = 150 if (($pswindow.BufferSize) -and ($pswindow.WindowSize) -and ($pswindow.WindowSize.Width -lt $minWidth)) { $buffersize = $pswindow.BufferSize $buffersize.width = $minWidth try { $pswindow.buffersize = $buffersize } catch {} $newsize = $pswindow.windowsize $newsize.width = $minWidth try { $pswindow.windowsize = $newsize } catch {} } $errorActionPreference = "Stop" $script:wizardStep = 0 $script:acceptDefaults = $false $Step = @{ "GetVariables" = 0 "SqlServer" = 5 "Database" = 10 "FromLSVersion" = 15 "FromBCVersion" = 20 "FromBCVersion2" = 22 "FromServerInstanceName" = 25 "FromBCServerPath" = 27 "FromBCClientPath" = 28 "ToLSVersion" = 30 "ToBCVersion" = 35 "ToBCVersion2" = 37 "ToServerInstanceName" = 40 "ToBCServerPath" = 45 "CustomExtensions" = 50 "AddCustomExtensions" = 52 "AddCustomExtensionsManually" = 54 "AddCustomExtensionsFromFile" = 56 "AddCustomExtensionsFromFile2" = 58 "RemoveCustomExtension" = 60 "Multitenancy" = 65 "Localization" = 70 "Final" = 100 } $script:prevSteps = New-Object System.Collections.Stack $script:prevSteps.Push(1) if ($loadingFromConfigFile) { Write-Host "Loading configuration from $loadFromConfigFile." -ForegroundColor Green if (!(Test-Path -Path $loadFromConfigFile)) { Write-Host "Config file not found: $($loadFromConfigFile)" -ForegroundColor Red return } Get-UpgradeInitializationScriptConfig -configFile $loadFromConfigFile # Test "From Version" Write-Host "Testing FromBC Version config" -ForegroundColor Green if (!(Test-Version -Version $upgradeInitializationScriptConfig.FromBc.Version)) { return } Write-Host "FromBC Version config ($($upgradeInitializationScriptConfig.FromBc.Version)) is valid." # Test "To Version" Write-Host "Testing ToBC Version config" -ForegroundColor Green if (!(Test-Version -Version $upgradeInitializationScriptConfig.ToBc.Version)) { return } Write-Host "ToBC Version config ($($upgradeInitializationScriptConfig.ToBc.Version)) is valid." $script:wizardStep = $Step.Final } $customExtensions = @{} while ($script:wizardStep -le 100) { $script:thisStep = $script:wizardStep $script:wizardStep++ switch ($script:thisStep) { $Step.SqlServer { $sqlServerInstance = "" $sqlServer = Enter-Value ` -title @' _____ ____ _ _____ / ____|/ __ \| | / ____| | (___ | | | | | | (___ ___ _ ____ _____ _ __ \___ \| | | | | \___ \ / _ | '__\ \ / / _ | '__| ____) | |__| | |____ ____) | __| | \ V | __| | |_____/ \___\_|______| |_____/ \___|_| \_/ \___|_| '@ ` -description "Enter the name of the SQL Server (and the SQL Server Instance, when applicable).`n`nExample: localhost or localhost\MSSQLSERVER, where localhost would be the SQL Server and MSSQLSERVER would be the instance." ` -question "SQL Server name:" ` -default "localhost" ` -previousStep $splittedSqlServer = $sqlServer.Split('\') if ($splittedSqlServer.Count -eq 2) { $sqlServer = $splittedSqlServer[0] $sqlServerInstance = $splittedSqlServer[1] } elseif ($splittedSqlServer.Count -gt 2) { Write-Host -ForegroundColor Red "Invalid SQL Server." } if ($script:wizardStep -eq $script:thisStep + 1) { $script:prevSteps.Push($script:thisStep) } } $Step.Database { $databaseName = Enter-Value ` -title @' _____ _ _ | __ \ | | | | | | | | __ _| |_ __ _| |__ __ _ ___ ___ | | | |/ _` | __/ _` | '_ \ / _` / __|/ _ \ | |__| | (_| | |_ (_| | |_) | (_| \__ \ __/ |_____/ \__,_|\__\__,_|_.__/ \__,_|___/\___| '@ ` -description "Enter the name of the database that's going to be upgraded." ` -question "Database Name:" ` -previousStep if ($script:wizardStep -eq $script:thisStep + 1) { $script:prevSteps.Push($script:thisStep) } } $Step.FromLSVersion { $lsVersions = @() Get-LSCentralAppInfo | ForEach-Object { $lsVersions += $_.version } $default = "14.2" $fromLsVersion = Enter-Value ` -title @' ______ _ _____ __ __ _ | ____| | | / ____|\ \ / / (_) | |__ _ __ ___ _ __ ___ | | | (___ \ \ / /___ _ __ ___ _ ___ _ __ | __|| '__|/ _ \ | '_ ` _ \ | | \___ \ \ \/ // _ \| '__|/ __|| | / _ \ | '_ \ | | | | | (_) || | | | | || |____ ____) | \ /| __/| | \__ \| || (_) || | | | |_| |_| \___/ |_| |_| |_||______||_____/ \/ \___||_| |___/|_| \___/ |_| |_| '@ ` -description "What version of LS Central are you upgrading from?" ` -options $lsVersions ` -question "From LS Version:" ` -default $default ` -previousStep if ($script:wizardStep -eq $script:thisStep + 1) { $script:prevSteps.Push($script:thisStep) } $fromMajorLSVersion = [int]($fromLsVersion.Split('.')[0]) } $Step.FromBCVersion { $predef = Select-Value ` -title @' ______ ____ _____ __ __ _ | ____| | _ \ / ____|\ \ / / (_) | |__ _ __ ___ _ __ ___ | |_) || | \ \ / /___ _ __ ___ _ ___ _ __ | __|| '__|/ _ \ | '_ ` _ \ | _ < | | \ \/ // _ \| '__|/ __|| | / _ \ | '_ \ | | | | | (_) || | | | | || |_) || |____ \ /| __/| | \__ \| || (_) || | | | |_| |_| \___/ |_| |_| |_||____/ \_____| \/ \___||_| |___/|_| \___/ |_| |_| '@ ` -description "What version of Business Central are you upgrading from?" ` -options ([ordered]@{ "SpecificOnPrem" = "Specific Business Central OnPrem build (requires version number)" }) ` -question "From BC Version" ` -default "SpecificOnPrem" ` -writeAnswer ` -previousStep if ($script:wizardStep -eq $script:thisStep + 1) { $script:prevSteps.Push($script:thisStep) } } $Step.FromBCVersion2 { $fullVersionNo = $false $type = $predef.Substring(8) $ok = $false do { $fromVersion = Enter-Value ` -description "Specify version number.`nIf you specify a full version number (like 15.4.41023.41345), you will get the closest version.`nIf multiple versions matches the entered value, you will be asked to select" ` -question "Enter version number (format major[.minor[.build[.release]]])" ` -doNotClearHost ` -writeAnswer ` -previousStep if ($fromVersion -eq "back") { $ok = $true } else { if ($fromVersion.indexOf('.') -eq -1) { $verno = 0 $ok = [int32]::TryParse($fromVersion, [ref]$verno) if (!$ok) { Write-Host -ForegroundColor Red "Illegal version number" } } else { $verno = [Version]"0.0.0.0" $ok = [Version]::TryParse($fromVersion, [ref]$verno) if (!$ok) { Write-Host -ForegroundColor Red "Illegal version number" } $fullVersionNo = $verno.Revision -ne -1 } if ($ok) { if ($fullVersionNo) { $artifactUrl = Get-BCArtifactUrl -type $type -version $fromVersion -country 'w1' -select 'Closest' if ($artifactUrl) { $foundVersion = $artifactUrl.split('/')[4] if ($foundVersion -ne $fromVersion) { Write-Host -ForegroundColor Yellow "The specific version doesn't exist, closest version is $foundVersion" } } } else { $fromVersions = @() Get-BCArtifactUrl -type $type -version $fromVersion -country 'w1' -select All | ForEach-Object { $fromVersions += $_.Split('/')[4] } if ($fromVersions.Count -eq 0) { Write-Host -ForegroundColor Red "Unable to find a version matching the specified version" $ok = $false } elseif ($fromVersions.Count -gt 1) { $fromVersion = Enter-Value ` -options $fromVersions ` -question "Select specific version" ` -doNotClearHost ` -writeAnswer ` -previousStep if ($fromVersion -eq "back") { $ok = $true } else { $fullVersionNo = $true } } } } if ($ok) { $fromMajorVersion = [int]($fromVersion.Split('.')[0]) if ($fromMajorLSVersion -ne $fromMajorVersion) { Write-Host -ForegroundColor Red "BC and LS major versions are not the same. Business Central version must be V$($fromMajorLSVersion)." $ok = $false } } } } while (!$ok) if ($script:wizardStep -eq $script:thisStep + 1) { $script:prevSteps.Push($script:thisStep) } if ($fromVersion -ne "back") { $fromMajorVersion = [int]($fromVersion.Split('.')[0]) } } $Step.FromServerInstanceName { $fromServerInstanceName = Enter-Value ` -title @' ______ _____ _____ _ _ _ | ____| / ____| |_ _| | | | \ | | | |__ _ __ ___ _ __ ___ | (___ ___ _ __ __ __ ___ _ __ | | _ __ ___ | |_ __ _ _ __ ___ ___ | \| | __ _ _ __ ___ ___ | __|| '__|/ _ \ | '_ ` _ \ \___ \ / _ \| '__|\ \ / // _ \| '__|| | | '_ \ / __|| __|/ _` || '_ \ / __|/ _ \| . ` | / _` || '_ ` _ \ / _ \ | | | | | (_) || | | | | | ____) || __/| | \ V /| __/| | _| |_ | | | |\__ \| |_| (_| || | | || (__| __/| |\ || (_| || | | | | || __/ |_| |_| \___/ |_| |_| |_||_____/ \___||_| \_/ \___||_| |_____||_| |_||___/ \__|\__,_||_| |_| \___|\___||_| \_| \__,_||_| |_| |_| \___| '@ ` -description "Enter the name of the NAV/BC server instance name for the original NAV/BC version." ` -question "Original NAV/BC version Service Instance Name:" ` -previousStep if ($script:wizardStep -eq $script:thisStep + 1) { $script:prevSteps.Push($script:thisStep) } } $Step.FromBCServerPath { $default = "C:\Program Files\Microsoft Dynamics 365 Business Central\$($fromMajorVersion)0" $fromBCServerPath = Enter-Value ` -title @' ______ ____ _____ _____ _____ _ _ | ____| | _ \ / ____| / ____| | __ \ | | | | | |__ _ __ ___ _ __ ___ | |_) || | | (___ ___ _ __ __ __ ___ _ __ | |__) |__ _ | |_ | |__ | __|| '__|/ _ \ | '_ ` _ \ | _ < | | \___ \ / _ \| '__|\ \ / // _ \| '__|| ___// _` || __|| '_ \ | | | | | (_) || | | | | || |_) || |____ ____) || __/| | \ V /| __/| | | | | (_| || |_ | | | | |_| |_| \___/ |_| |_| |_||____/ \_____||_____/ \___||_| \_/ \___||_| |_| \__,_| \__||_| |_| '@ ` -description "Enter the path for the NAV/BC service version you're upgrading from. Example: $default" ` -question "From BC Server Path:" ` -default $default ` -previousStep if ($script:wizardStep -eq $script:thisStep + 1) { $script:prevSteps.Push($script:thisStep) } # Skips the FromBCClientPath step if the major version is greater than v14. if ($fromMajorVersion -ne "14") { $script:wizardStep = $Step.FromBCClientPath + 1 } } $Step.FromBCClientPath { $default = "C:\Program Files (x86)\Microsoft Dynamics 365 Business Central\$($fromMajorVersion)0" $fromBCClientPath = Enter-Value ` -title @' ______ ____ _____ _____ _ _ _ _____ _ _ | ____| | _ \ / ____|/ ____|| |(_) | | | __ \ | | | | | |__ _ __ ___ _ __ ___ | |_) || | | | | | _ ___ _ __ | |_ | |__) |__ _ | |_ | |__ | __|| '__|/ _ \ | '_ ` _ \ | _ < | | | | | || | / _ \| '_ \ | __|| ___// _` || __|| '_ \ | | | | | (_) || | | | | || |_) || |____| |____ | || || __/| | | || |_ | | | (_| || |_ | | | | |_| |_| \___/ |_| |_| |_||____/ \_____|\_____||_||_| \___||_| |_| \__||_| \__,_| \__||_| |_| '@ ` -description "Enter the path for the BC roletailored client version you're upgrading from. Example: $default" ` -question "From BC Roletailored Client Path:" ` -default $default ` -previousStep if ($script:wizardStep -eq $script:thisStep + 1) { $script:prevSteps.Push($script:thisStep) } } $Step.ToLSVersion { $lsVersions = @() Get-LSCentralAppInfo -version $minimumToLSVersion -versionFilterType 'ge' | ForEach-Object { $lsVersions += $_.version } $default = Get-DefaultDestinationVersion $toLsVersion = Enter-Value ` -title @' _______ _ _____ __ __ _ |__ __| | | / ____|\ \ / / (_) | | ___ | | | (___ \ \ / /___ _ __ ___ _ ___ _ __ | | / _ \ | | \___ \ \ \/ // _ \| '__|/ __|| | / _ \ | '_ \ | || (_) || |____ ____) | \ /| __/| | \__ \| || (_) || | | | |_| \___/ |______||_____/ \/ \___||_| |___/|_| \___/ |_| |_| '@ ` -description "What version of LS Central are you upgrading to?" ` -options $lsVersions ` -question "To LS Version:" ` -default $default ` -previousStep if ($script:wizardStep -eq $script:thisStep + 1) { $script:prevSteps.Push($script:thisStep) } $toMajorLSVersion = [int]($toLsVersion.Split('.')[0]) } $Step.ToBCVersion { $predef = Select-Value ` -title @' _______ ____ _____ __ __ _ |__ __| | _ \ / ____|\ \ / / (_) | | ___ | |_) || | \ \ / /___ _ __ ___ _ ___ _ __ | | / _ \ | _ < | | \ \/ // _ \| '__|/ __|| | / _ \ | '_ \ | || (_) || |_) || |____ \ /| __/| | \__ \| || (_) || | | | |_| \___/ |____/ \_____| \/ \___||_| |___/|_| \___/ |_| |_| '@ ` -description "What version of Business Central are you upgrading to?" ` -options ([ordered]@{ "SpecificOnPrem" = "Specific Business Central OnPrem build (requires version number)" }) ` -question "To BC Version:" ` -default "SpecificOnPrem" ` -writeAnswer ` -previousStep if ($script:wizardStep -eq $script:thisStep + 1) { $script:prevSteps.Push($script:thisStep) } } $Step.ToBCVersion2 { $fullVersionNo = $false $type = $predef.Substring(8) $ok = $false do { $toVersion = Enter-Value ` -description "Specify version number.`nIf you specify a full version number (like 15.4.41023.41345), you will get the closest version.`nIf multiple versions matches the entered value, you will be asked to select" ` -question "Enter version number (format major[.minor[.build[.release]]])" ` -doNotClearHost ` -writeAnswer ` -previousStep if ($toVersion -eq "back") { $ok = $true } else { if ($toVersion.indexOf('.') -eq -1) { $verno = 0 $ok = [int32]::TryParse($toVersion, [ref]$verno) if (!$ok) { Write-Host -ForegroundColor Red "Illegal version number" } } else { $verno = [Version]"0.0.0.0" $ok = [Version]::TryParse($toVersion, [ref]$verno) if (!$ok) { Write-Host -ForegroundColor Red "Illegal version number" } $fullVersionNo = $verno.Revision -ne -1 } if ($ok) { if ($fullVersionNo) { $artifactUrl = Get-BCArtifactUrl -type $type -version $toVersion -country 'w1' -select 'Closest' if ($artifactUrl) { $foundVersion = $artifactUrl.split('/')[4] if ($foundVersion -ne $toVersion) { Write-Host -ForegroundColor Yellow "The specific version doesn't exist, closest version is $foundVersion" } } } else { $toVersions = @() Get-BCArtifactUrl -type $type -version $toVersion -country 'w1' -select All | ForEach-Object { $toVersions += $_.Split('/')[4] } if ($toVersions.Count -eq 0) { Write-Host -ForegroundColor Red "Unable to find a version matching the specified version" $ok = $false } elseif ($toVersions.Count -gt 1) { $toVersion = Enter-Value ` -options $toVersions ` -question "Select specific version" ` -doNotClearHost ` -writeAnswer ` -previousStep if ($toVersion -eq "back") { $ok = $true } else { $fullVersionNo = $true } } } } if ($ok) { $toMajorVersion = [int]($toVersion.Split('.')[0]) if ($toMajorLSVersion -ne $toMajorVersion) { Write-Host -ForegroundColor Red "BC and LS major versions are not the same. Business Central version must be V$($toMajorLSVersion)." $ok = $false } } } } while (!$ok) if ($script:wizardStep -eq $script:thisStep + 1) { $script:prevSteps.Push($script:thisStep) } if ($toVersion -ne "back") { $toMajorVersion = [int]($toVersion.Split('.')[0]) } } $Step.ToServerInstanceName { $toServerInstanceName = Enter-Value ` -title @' _______ _____ _____ _ _ _ |__ __| / ____| |_ _| | | | \ | | | | ___ | (___ ___ _ __ __ __ ___ _ __ | | _ __ ___ | |_ __ _ _ __ ___ ___ | \| | __ _ _ __ ___ ___ | | / _ \ \___ \ / _ \| '__|\ \ / // _ \| '__|| | | '_ \ / __|| __|/ _` || '_ \ / __|/ _ \| . ` | / _` || '_ ` _ \ / _ \ | || (_) |____) || __/| | \ V /| __/| | _| |_ | | | |\__ \| |_| (_| || | | || (__| __/| |\ || (_| || | | | | || __/ |_| \___/|_____/ \___||_| \_/ \___||_| |_____||_| |_||___/ \__|\__,_||_| |_| \___|\___||_| \_| \__,_||_| |_| |_| \___| '@ ` -description "Enter the name of the BC server instance name for the new BC version" ` -question "New BC version Service Instance Name:" ` -previousStep if ($script:wizardStep -eq $script:thisStep + 1) { $script:prevSteps.Push($script:thisStep) } } $Step.ToBCServerPath { $default = "C:\Program Files\Microsoft Dynamics 365 Business Central\$($toMajorVersion)0" $toBCServerPath = Enter-Value ` -title @' _______ ____ _____ _____ _____ _ _ |__ __| | _ \ / ____| / ____| | __ \ | | | | | | ___ | |_) || | | (___ ___ _ __ __ __ ___ _ __ | |__) |__ _ | |_ | |__ | | / _ \ | _ < | | \___ \ / _ \| '__|\ \ / // _ \| '__|| ___// _` || __|| '_ \ | || (_) || |_) || |____ ____) || __/| | \ V /| __/| | | | | (_| || |_ | | | | |_| \___/ |____/ \_____||_____/ \___||_| \_/ \___||_| |_| \__,_| \__||_| |_| '@ ` -description "Enter the path for the NAV/BC service version you're upgrading to. Example: $default" ` -question "To BC Server Path:" ` -default $default ` -previousStep if ($script:wizardStep -eq $script:thisStep + 1) { $script:prevSteps.Push($script:thisStep) } } $Step.CustomExtensions { $CustomExtensionsDetailed = "" $customExtensions.GetEnumerator() | ForEach-Object { $CustomExtensionsDetailed += "$($_.key): " $CustomExtensionsDetailed += "$($_.value | ConvertTo-Json -Compress) `n" } $description = "If you have customization extensions then you can automatically add those to the migration script.`n`nCustom extensions:`n`n$($CustomExtensionsDetailed)" $predef = Select-Value ` -title @' _____ _ ______ _ _ / ____| | | | ____| | | (_) | | _ _ ___ | |_ ___ _ __ ___ | |__ __ __| |_ ___ _ __ ___ _ ___ _ __ ___ | | | | | |/ __|| __|/ _ \ | '_ ` _ \ | __| \ \/ /| __|/ _ \| '_ \ / __|| | / _ \ | '_ \ / __| | |____| |_| |\__ \| |_| (_) || | | | | || |____ > < | |_| __/| | | |\__ \| || (_) || | | |\__ \ \_____|\__,_||___/ \__|\___/ |_| |_| |_||______|/_/\_\ \__|\___||_| |_||___/|_| \___/ |_| |_||___/ '@ ` -description $description ` -options ([ordered]@{ "add" = "Add custom extension" "remove" = "Remove custom extension" "continue" = "Continue to next step." }) ` -question "Do you want to add or remove custom extensions to the script?" ` -default "continue" ` -writeAnswer ` -previousStep if ($script:wizardStep -eq $script:thisStep + 1) { $script:prevSteps.Push($script:thisStep) } switch ($predef) { "remove" { $script:wizardStep = $Step.RemoveCustomExtension } # Go to the remove custom extensions menu. "continue" { $script:wizardStep = $Step.Multitenancy } # Skips the next steps if not adding custom extensions. Default {} } } $Step.AddCustomExtensions { $predef = Select-Value ` -description "Choose if you want to enter the extension information (app id, name, publisher and version) manually or read it from the app.json file." ` -options ([ordered]@{ "readfromfile" = "Read from app.json file." "manually" = "Enter manually." }) ` -question "How do you want to enter the custom extensions information?" ` -default "readfromfile" ` -writeAnswer ` -doNotClearHost ` -previousStep if ($script:wizardStep -eq $script:thisStep + 1) { $script:prevSteps.Push($script:thisStep) } # Skips the next step if not adding custom extensions. if ($predef -eq "readfromfile") { $script:wizardStep = $Step.AddCustomExtensionsFromFile } } $Step.AddCustomExtensionsManually { $ok = $false do { $appId = Enter-Value ` -description "Specify the app id for the custom extension." ` -question "Enter the app id for the custom extension:" ` -doNotClearHost ` -writeAnswer ` -previousStep if ($appId -eq "back") { $ok = $true } else { $appIdGuid = [System.Guid]::empty $ok = [System.Guid]::TryParse($appId, [ref]$appIdGuid) if (!$ok) { Write-Host -ForegroundColor Red "Illegal app id for the custom extension" } if ($ok) { $appName = Enter-Value ` -description "Specify the custom extension name." ` -question "Enter the custom extension name:" ` -doNotClearHost ` -writeAnswer ` -previousStep } if ($ok) { $appPublisherName = Enter-Value ` -description "Specify the custom extension publisher name." ` -question "Enter the custom extension publisher name:" ` -doNotClearHost ` -writeAnswer ` -previousStep } if ($ok) { $appVersion = Enter-Value ` -description "Specify the final version for the custom extension." ` -question "Enter the final version for the custom extension:" ` -doNotClearHost ` -writeAnswer ` -previousStep if ($appVersion.indexOf('.') -eq -1) { $verno = 0 $ok = [int32]::TryParse($appVersion, [ref]$verno) if (!$ok) { Write-Host -ForegroundColor Red "Illegal version number" } } else { $verno = [Version]"0.0.0.0" $ok = [Version]::TryParse($appVersion, [ref]$verno) if (!$ok) { Write-Host -ForegroundColor Red "Illegal version number" } $fullVersionNo = $verno.Revision -ne -1 } } } } while (!$ok) if ($script:wizardStep -eq $script:thisStep + 1) { $script:prevSteps.Push($script:thisStep) } if ($appId -ne "back") { $customExtension = [ordered]@{ "Id" = $appId "Name" = $appName "Publisher" = $appPublisherName "Version" = $appVersion } $offset = $customExtensions.Count $customExtensions.add($([char]($offset+97)), $customExtension) # Go to the custom extensions main step. $script:wizardStep = $Step.CustomExtensions } } $Step.AddCustomExtensionsFromFile { $ok = $false do { $appJsonPath = Enter-Value ` -description "Specify the path for the custom extension app.json file.`nExample: C:\CustomExtensionProject\app.json." ` -question "Enter the path for the custom extension app.json file:" ` -doNotClearHost ` -writeAnswer ` -previousStep if ($appJsonPath -eq "back") { $ok = $true } else { $appJsonPath = $appJsonPath.Trim('"') $ok = Test-Path -Path $appJsonPath if (!$ok) { Write-Host -ForegroundColor Red "App.json file not found" } if ($ok) { try { $appJson = Get-Content $appJsonPath | ConvertFrom-Json $appId = $appJson.id $appName = $appJson.name $appPublisherName = $appJson.publisher $appVersion = $appJson.version } catch { $ok = $false throw "Error reading configuration file $loadFromConfigFile, cannot execute function." } } } } while (!$ok) if ($script:wizardStep -eq $script:thisStep + 1) { $script:prevSteps.Push($script:thisStep) } if ($appJsonPath -ne "back") { $customExtension = [ordered]@{ "Id" = $appId "Name" = $appName "Publisher" = $appPublisherName "Version" = $appVersion } $offset = $customExtensions.Count $customExtensions.add($([char]($offset+97)), $customExtension) # Go to the custom extensions main step. $script:wizardStep = $Step.CustomExtensions } } $Step.RemoveCustomExtension { $customExtensionsOptions = @{} $customExtensions.GetEnumerator() | ForEach-Object { $key = $_.key $value = $_.value | ConvertTo-Json -Compress $customExtensionsOptions.add($key, $value) } $predef = Select-Value ` -description "Choose the custom extension you want to remove." ` -options ($customExtensionsOptions) ` -question "What custom extension do you want to remove?" ` -writeAnswer ` -doNotClearHost ` -previousStep $customExtensions.remove($predef) if ($script:wizardStep -eq $script:thisStep + 1) { $script:prevSteps.Push($script:thisStep) } # Go to the custom extensions main step. $script:wizardStep = $Step.CustomExtensions } $Step.Multitenancy { $predef = Select-Value ` -title @' __ __ _ _ _ _ | \/ | | || | (_)| | | \ / | _ _ | || |_ _ | |_ ___ _ __ __ _ _ __ ___ _ _ | |\/| || | | || || __|| || __|/ _ \| '_ \ / _` || '_ \ / __|| | | | | | | || |_| || || |_ | || |_| __/| | | || (_| || | | || (__ | |_| | |_| |_| \__,_||_| \__||_| \__|\___||_| |_| \__,_||_| |_| \___| \__, | __/ | |___/ '@ ` -description "Indicate if you're setting up a single or multitenant environment." ` -options ([ordered]@{ "yes" = "Yes, it's a multi tenant environment." "no" = "No, it's a single tenant environment." }) ` -question "Are you setting up a multitenancy environment?" ` -default "no" ` -writeAnswer ` -previousStep if ($script:wizardStep -eq $script:thisStep + 1) { $script:prevSteps.Push($script:thisStep) } $multitenancy = $false if ($predef -eq "yes") { $multitenancy = $true } } $Step.Localization { $default = "w1" $localization = Enter-Value ` -title @' _ _ _ _ _ | | | |(_) | | (_) | | ___ ___ __ _ | | _ ____ __ _ | |_ _ ___ _ __ | | / _ \ / __|/ _` || || ||_ // _` || __|| | / _ \ | '_ \ | |____| (_) || (__| (_| || || | / /| (_| || |_ | || (_) || | | | |______|\___/ \___|\__,_||_||_|/___|\__,_| \__||_| \___/ |_| |_| '@ ` -description "Indicate if you are using any localization.`n`nEnter the country code with 2 digits like: is, fi, es, us, etc.`nMore Info: https://docs.microsoft.com/en-us/dynamics365/business-central/dev-itpro/compliance/apptest-countries-and-translations`n`nBase, System and Application files for this localization will be used." ` -question "What localization are you using?" ` -default $default ` -writeAnswer ` -previousStep if ($script:wizardStep -eq $script:thisStep + 1) { $script:prevSteps.Push($script:thisStep) } } # ______ _ _ # | ____(_) | | # | |__ _ _ __ __ _| | # | __| | | '_ \ / _` | | # | | | | | | | (_| | | # |_| |_|_| |_|\__,_|_| # $step.Final { $script:acceptDefaults = $false if (!$loadingFromConfigFile) { if (!((Get-Variable -scope Script upgradeInitializationScriptConfig -ErrorAction SilentlyContinue) -and $upgradeInitializationScriptConfig)) { $customExtensionsConfig = @() $customExtensions.GetEnumerator() | ForEach-Object { $customExtensionsConfig = $customExtensionsConfig + $_.Value } Set-Variable -scope Script -Name upgradeInitializationScriptConfig -Value @{ "Environment" = @{ "Multitenant" = $multitenancy "Localization" = $localization } "SQL" = @{ "Server" = "$sqlServer" "Instance" = "$sqlServerInstance" "Database" = "$databaseName" } "FromBC" = @{ "ServerInstance" = "$fromServerInstanceName" "Version" = "$fromVersion" "LSVersion" = "$fromLSVersion" "ServerPath" = "$fromBCServerPath" "ClientPath" = "$fromBCClientPath" } "ToBC" = @{ "ServerInstance" = "$toServerInstanceName" "Version" = "$toVersion" "LSVersion" = "$toLsVersion" "ServerPath" = "$toBCServerPath" } "CustomExtensions" = $customExtensionsConfig } } } $title = ` @" _____ _ _ _ _____ _ _ | __ \ | | | || | / ____| (_) | | | |__) |___ __ __ ___ _ __ ___ | |__ ___ | || | | (___ ___ _ __ _ _ __ | |_ ___ | ___// _ \\ \ /\ / // _ \| '__|/ __|| '_ \ / _ \| || | \___ \ / __|| '__|| || '_ \ | __|/ __| | | | (_) |\ V V /| __/| | \__ \| | | || __/| || | ____) || (__ | | | || |_) || |_ \__ \ |_| \___/ \_/\_/ \___||_| |___/|_| |_| \___||_||_| |_____/ \___||_| |_|| .__/ \__||___/ | | |_| "@ Write-Host -ForegroundColor Yellow $title $preparationScript = Get-PreparationScript $preparationScriptPath = Join-Path (Get-Location) "Preparation-Script.ps1" $preparationScript | Out-File $preparationScriptPath Write-Host "Preparation Powershell script file exported to $preparationScriptPath" $migrationScript = Get-MigrationScript $migrationScriptPath = Join-Path (Get-Location) "Migration-Script.ps1" $migrationScript | Out-File $migrationScriptPath Write-Host "Migration Powershell script file exported to $migrationScriptPath" if ($loadingFromConfigFile -eq $false) { $exportConfigPath = Join-Path (Get-Location) "config.json" $upgradeInitializationScriptConfig | ConvertTo-Json | Set-Content $exportConfigPath Write-Host "Config file exported to $exportConfigPath" } } } } } function Select-Value { Param( [Parameter(Mandatory = $false)] [string] $title, [Parameter(Mandatory = $false)] [string] $description, [Parameter(Mandatory = $true)] $options, [Parameter(Mandatory = $false)] [string] $default = "", [Parameter(Mandatory = $true)] [string] $question, [switch] $doNotClearHost = ($host.name -ne "ConsoleHost"), [switch] $writeAnswer = ($host.name -ne "ConsoleHost"), [switch] $previousStep ) if (!$doNotClearHost) { Clear-Host } if ($title) { Write-Host -ForegroundColor Yellow $title Write-Host } if ($description) { Write-Host $description Write-Host } $offset = 0 $defaultChr = -1 $keys = @() $values = @() $options.GetEnumerator() | ForEach-Object { Write-Host -ForegroundColor Yellow "$([char]($offset+97)) " -NoNewline $keys += @($_.Key) $values += @($_.Value) if ($_.Key -eq $default) { Write-Host -ForegroundColor Yellow $_.Value $defaultAnswer = $offset } else { Write-Host $_.Value } $offset++ } Write-Host if ($script:thisStep -lt 100) { if (($default) -and !$script:acceptDefaults) { Write-Host -ForegroundColor Yellow "!" -NoNewline Write-Host " accept default answers for the remaining questions" } if ($previousStep) { Write-Host -ForegroundColor Yellow "x" -NoNewline Write-Host " start over" Write-Host -ForegroundColor Yellow "z" -NoNewline Write-Host " go back" } if (($default) -or ($previousStep)) { Write-Host } } $answer = -1 do { Write-Host "$question " -NoNewline if ($defaultAnswer -ge 0) { Write-Host "(default $([char]($defaultAnswer + 97))) " -NoNewline } if ($script:acceptDefaults -and $defaultAnswer -ge 0) { $selection = "" } else { $selection = (Read-Host).ToLowerInvariant() } if ($selection -eq "!" -and ($default)) { $selection = "" $script:acceptDefaults = $true Write-Host $defaultAnswer } if ($previousStep) { if ($selection -eq "x") { if ($writeAnswer) { Write-Host Write-Host -ForegroundColor Green "Start over selected" Write-Host } $script:acceptDefaults = $false $script:wizardStep = 0 $script:prevSteps = New-Object System.Collections.Stack $script:prevSteps.Push(1) return "Back" } if ($selection -eq "z") { if ($writeAnswer) { Write-Host Write-Host -ForegroundColor Green "Back selected" Write-Host } $script:acceptDefaults = $false $script:wizardStep = $script:prevSteps.Pop() return "Back" } } if ($selection -eq "") { if ($defaultAnswer -ge 0) { $answer = $defaultAnswer } else { Write-Host -ForegroundColor Red "No default value exists. " -NoNewline } } else { if (($selection.Length -ne 1) -or (([int][char]($selection)) -lt 97 -or ([int][char]($selection)) -ge (97 + $offset))) { Write-Host -ForegroundColor Red "Illegal answer. " -NoNewline } else { $answer = ([int][char]($selection)) - 97 } } if ($answer -eq -1) { if ($offset -eq 2) { Write-Host -ForegroundColor Red "Please answer one letter, a or b" } else { Write-Host -ForegroundColor Red "Please answer one letter, from a to $([char]($offset+97-1))" } } } while ($answer -eq -1) if ($writeAnswer) { Write-Host Write-Host -ForegroundColor Green "$($values[$answer]) selected" Write-Host } $keys[$answer] } function Enter-Value { Param( [Parameter(Mandatory = $false)] [string] $title, [Parameter(Mandatory = $false)] [string] $description, [Parameter(Mandatory = $false)] $options, [Parameter(Mandatory = $false)] [string] $default = "", [Parameter(Mandatory = $true)] [string] $question, [switch] $doNotClearHost = ($host.name -ne "ConsoleHost"), [switch] $writeAnswer = ($host.name -ne "ConsoleHost"), [switch] $doNotConvertToLower, [switch] $previousStep ) if (!$doNotClearHost) { Clear-Host } if ($title) { Write-Host -ForegroundColor Yellow $title Write-Host } if ($description) { Write-Host $description Write-Host } if ($script:thisStep -lt 100) { if (($default) -and !$script:acceptDefaults) { Write-Host -ForegroundColor Yellow "!" -NoNewline Write-Host " accept default answers for the remaining questions" } if ($previousStep) { Write-Host "Enter " -NoNewline Write-Host -ForegroundColor Yellow "x" -NoNewline Write-Host " to start over" Write-Host "Enter " -NoNewline Write-Host -ForegroundColor Yellow "z" -NoNewline Write-Host " to go back" } if (($default) -or ($previousStep)) { Write-Host } } $answer = "" do { Write-Host "$question " -NoNewline if ($options) { Write-Host "($([string]::Join(', ', $options))) " -NoNewline } if ($default) { Write-Host "(default $default) " -NoNewline } if ($script:acceptDefaults -and ($default)) { $selection = "" Write-Host $default } elseif ($doNotConvertToLower) { $selection = Read-Host } else { $selection = (Read-Host).ToLowerInvariant() } if ($selection -eq "!" -and ($default)) { $selection = "" $script:acceptDefaults = $true } if ($selection -eq "") { if ($default) { $answer = $default } else { Write-Host -ForegroundColor Red "No default value exists. " } } elseif ($selection -eq "x" -and $previousStep) { if ($writeAnswer) { Write-Host Write-Host -ForegroundColor Green "Exit selected" Write-Host } $script:acceptDefaults = $false $script:wizardStep = 0 $script:prevSteps = New-Object System.Collections.Stack $script:prevSteps.Push(1) return "back" } elseif ($selection -eq "z" -and $previousStep) { if ($writeAnswer) { Write-Host Write-Host -ForegroundColor Green "Back selected" Write-Host } $script:acceptDefaults = $false $script:wizardStep = $script:prevSteps.Pop() return "back" } else { if ($options) { $answer = $options | Where-Object { $_ -like "$selection*" } if (-not ($answer)) { Write-Host -ForegroundColor Red "Illegal answer. Please answer one of the options." } elseif ($answer -is [Array]) { Write-Host -ForegroundColor Red "Multiple options match the answer. Please answer one of the options that matched the previous selection." $options = $answer $answer = $null } } else { $answer = $selection } } } while (-not ($answer)) if ($writeAnswer) { Write-Host Write-Host -ForegroundColor Green "$answer selected" Write-Host } $answer } function Get-PreparationScript { $fromLSVersion = $upgradeInitializationScriptConfig.FromBC.LSVersion $fromLSMajorVersion = [int]($fromLSVersion.Split('.')[0]) $script = @() switch ($fromLSMajorVersion) { "14" { $script = Get-PreparationScript_FromLS14 break } default { $script = Get-PreparationScript_FromLS15OrLater break } } return $script } function Get-PreparationScript_FromLS14 { $fromServerInstanceName = $upgradeInitializationScriptConfig.FromBC.ServerInstance $fromLSVersion = $upgradeInitializationScriptConfig.FromBC.LSVersion $fromBCServerPath = $upgradeInitializationScriptConfig.FromBC.ServerPath $fromBCClientPath = $upgradeInitializationScriptConfig.FromBC.ClientPath $toVersion = $upgradeInitializationScriptConfig.ToBC.Version $toLSVersion = $upgradeInitializationScriptConfig.ToBC.LSVersion $multitenancy = $upgradeInitializationScriptConfig.Environment.Multitenant $customExtensions = $upgradeInitializationScriptConfig.CustomExtensions $fromVersion = $upgradeInitializationScriptConfig.FromBC.Version $fromMajorVersion = [int]($fromVersion.Split('.')[0]) $script = @() $script += "" $script += "###################### Initialization Helper ######################" $script += "" $script += "`$ErrorActionPreference = `"Stop`"" $script += "" $script += "Import-Module LSMigrationTools -Force" $script += "" $script += "## Get ALCompiler files" $script += "Get-ALCompilerFromArtifacts -Version $($toVersion)" $script += "" $script += "## Get txt2al files" $script += "Get-Txt2AlFromArtifacts" $script += "" $script += "## Create migration extensions folders" $script += "New-UpgradeAppsStructure -ImportSymbolsApp" $script += "" $script += "" $script += "########## C/AL - Tables renaming in Business Central 14 ##########" $script += "" $script += "`$baseFolder = `"$(Get-Location)`"" $script += "`$objectsOutputPath = Join-Path `$baseFolder `"Objects`"" $script += "" $script += "`$fromServerInstanceName = `"$fromServerInstanceName`"" if ($multitenancy) { $script += "### Update this with the right tenant name" } $script += "`$tenantId = `"default`"" $script += "" $sqlServer = $upgradeInitializationScriptConfig.SQL.Server $sqlServerInstance = $upgradeInitializationScriptConfig.SQL.Instance if ($sqlServerInstance -eq "") { $script += "`$fullDatabaseServer = `"$sqlServer`"" } else { $script += "`$fullDatabaseServer = `"$sqlServer\$sqlServerInstance`"" } $script += "`$databaseName = `"$($upgradeInitializationScriptConfig.SQL.Database)`"" $script += "" $script += "## BC 14" $script += "Import-Module `"$((Join-Path $fromBCServerPath 'Service\NavAdminTool.ps1'))`" -Force" $script += "Import-Module `"$((Join-Path $fromBCClientPath 'Roletailored Client\NavModelTools.ps1'))`" -Force" $script += ". `"$((Join-Path $fromBCClientPath 'Roletailored Client\NavModelTools.ps1'))`" -NavIde `"$((Join-Path $fromBCClientPath 'Roletailored Client\finsql.exe'))`" -Force" $script += "" $script += "Export-NAVApplicationObject -DatabaseServer `$fullDatabaseServer -DatabaseName `$databaseName -Path (Join-Path `$objectsOutputPath 'exported_bc14-cal-tables.txt') -Filter 'Type=Table;Id=1..1999999999'" $script += "Convert-BC14CALObjectsToTableSchemaOnly -ObjectsFilePath (Join-Path `$objectsOutputPath 'exported_bc14-cal-tables.txt') -OutputFilePath (Join-Path `$objectsOutputPath 'converted_bc14-cal-tables.txt')" $script += "" $script += "Import-NAVApplicationObject -DatabaseServer `$fullDatabaseServer -DatabaseName `$databaseName -Path (Join-Path `$objectsOutputPath 'converted_bc14-cal-tables.txt')" $script += "Compile-NAVApplicationObject -DatabaseServer `$fullDatabaseServer -DatabaseName `$databaseName -Filter 'Type=Table;Id=1..1999999999'" if ($fromMajorVersion -eq 14) { $script += "Delete-NAVApplicationObject -DatabaseServer `$fullDatabaseServer -DatabaseName `$databaseName -Filter 'Type=Table;Id=99009070..99009074|99009077' -SynchronizeSchemaChanges Force" } $script += "" $script += "Sync-NAVTenant -ServerInstance `$fromServerInstanceName -Tenant `$tenantId -Mode Sync -Force" $script += "" $script += "Export-NAVApplicationObject -DatabaseServer `$fullDatabaseServer -DatabaseName `$databaseName -Path (Join-Path `$objectsOutputPath 'exported_bc14-cal-tables_renamed.txt') -Filter 'Type=Table;Id=1..1999999999'" $script += "Convert-BC14CALToStrippedAL -ObjectsFilePath (Join-Path `$objectsOutputPath 'exported_bc14-cal-tables_renamed.txt') -OutputFilePath (Join-Path `$objectsOutputPath 'converted_bc14-al-tables_renamed.al')" $script += "" $script += "Copy-Item -Path (Join-Path `$objectsOutputPath 'converted_bc14-al-tables_renamed.al') (Join-Path `$baseFolder 'ExtensionsSourceCode\ls-upgrade-1st_version\src')" $script += "" $script += "" $script += "## Compile each one of the migration extensions" $script += "" $script += "`$baseFolder = `"$(Get-Location)`"" $script += "" $script += "### ls-upgrade-1st_version" $script += "`$appProjectFolder = Join-Path `$baseFolder `"ExtensionsSourceCode\ls-upgrade-1st_version`"" $script += "`$appOutputFile = Join-Path `$baseFolder `"MigrationFiles\ls-upgrade-1st_version.app`"" $script += "New-CompiledALProjectApp -appProjectFolder `$appProjectFolder -appOutputFile `$appOutputFile -appSymbolsFolder (Join-Path `$appProjectFolder `".alpackages`")" $script += "" $script += "### ls-upgrade-2nd_version-migration" $script += "`$appProjectFolder = Join-Path `$baseFolder `"ExtensionsSourceCode\ls-upgrade-2nd_version-migration`"" $script += "`$appOutputFile = Join-Path `$baseFolder `"MigrationFiles\ls-upgrade-2nd_version-migration.app`"" $script += "New-CompiledALProjectApp -appProjectFolder `$appProjectFolder -appOutputFile `$appOutputFile -appSymbolsFolder (Join-Path `$appProjectFolder `".alpackages`")" $script += "" $script += "### ls-upgrade-base-empty" $script += "`$appProjectFolder = Join-Path `$baseFolder `"ExtensionsSourceCode\ls-upgrade-base-empty`"" $script += "`$appOutputFile = Join-Path `$baseFolder `"MigrationFiles\ls-upgrade-base-empty.app`"" $script += "New-CompiledALProjectApp -appProjectFolder `$appProjectFolder -appOutputFile `$appOutputFile -appSymbolsFolder (Join-Path `$appProjectFolder `".alpackages`")" $script += "" $script += "### ls-upgrade-system-empty" $script += "`$appProjectFolder = Join-Path `$baseFolder `"ExtensionsSourceCode\ls-upgrade-system-empty`"" $script += "`$appOutputFile = Join-Path `$baseFolder `"MigrationFiles\ls-upgrade-system-empty.app`"" $script += "New-CompiledALProjectApp -appProjectFolder `$appProjectFolder -appOutputFile `$appOutputFile -appSymbolsFolder (Join-Path `$appProjectFolder `".alpackages`")" $script += "" $script += "### ls-upgrade-lscentral-empty" $script += "`$appProjectFolder = Join-Path `$baseFolder `"ExtensionsSourceCode\ls-upgrade-lscentral-empty`"" $script += "`$appOutputFile = Join-Path `$baseFolder `"MigrationFiles\ls-upgrade-lscentral-empty.app`"" $script += "New-CompiledALProjectApp -appProjectFolder `$appProjectFolder -appOutputFile `$appOutputFile -appSymbolsFolder (Join-Path `$appProjectFolder `".alpackages`")" $script += "" $script += "### ls-upgrade-lscentral_system_app-empty" $script += "`$appProjectFolder = Join-Path `$baseFolder `"ExtensionsSourceCode\ls-upgrade-lscentral_system_app-empty`"" $script += "`$appOutputFile = Join-Path `$baseFolder `"MigrationFiles\ls-upgrade-lscentral_system_app-empty.app`"" $script += "New-CompiledALProjectApp -appProjectFolder `$appProjectFolder -appOutputFile `$appOutputFile -appSymbolsFolder (Join-Path `$appProjectFolder `".alpackages`")" $script += "" foreach ($extension in $customExtensions) { $appPackageName = Get-AppPackageName -Publisher $extension.Publisher -Name $extension.Name $appPackageName = "$($appPackageName)-empty" $script += "### $($appPackageName)" $script += "`$appProjectFolder = Join-Path `$baseFolder `"ExtensionsSourceCode\$($appPackageName)`"" $script += "`$appOutputFile = Join-Path `$baseFolder `"MigrationFiles\$($appPackageName).app`"" $script += "New-CompiledALProjectApp -appProjectFolder `$appProjectFolder -appOutputFile `$appOutputFile -appSymbolsFolder (Join-Path `$appProjectFolder `".alpackages`")" $script += "" } if ($includeCustomizationAppPlaceholders) { $script += "### ls-upgrade-customization_app placeholder" $script += "`$appProjectFolder = Join-Path `$baseFolder `"ExtensionsSourceCode\ls-upgrade-customization_app`"" $script += "`$appOutputFile = Join-Path `$baseFolder `"MigrationFiles\<Customization App_14.0.0.0.app>`"" $script += "New-CompiledALProjectApp -appProjectFolder `$appProjectFolder -appOutputFile `$appOutputFile -appSymbolsFolder (Join-Path `$appProjectFolder `".alpackages`")" $script += "" } if ($upgradeMode -eq [UpgradeMode]::LS_14_18_TablesRenamingInV18) { $script += "### ls-upgrade-tables_renaming-1st_version-empty" $script += "`$appProjectFolder = Join-Path `$baseFolder `"ExtensionsSourceCode\ls-upgrade-tables_renaming-1st_version-empty`"" $script += "`$appOutputFile = Join-Path `$baseFolder `"MigrationFiles\LS Retail_ls-upgrade-tables_renaming_14.0.0.0.app`"" $script += "New-CompiledALProjectApp -appProjectFolder `$appProjectFolder -appOutputFile `$appOutputFile -appSymbolsFolder (Join-Path `$appProjectFolder `".alpackages`")" $script += "" $script += "### ls-upgrade-tables_renaming-2nd_version-old_tables_names" $script += "`$appProjectFolder = Join-Path `$baseFolder `"ExtensionsSourceCode\ls-upgrade-tables_renaming-2nd_version-old_tables_names`"" $script += "`$appOutputFile = Join-Path `$baseFolder `"MigrationFiles\LS Retail_ls-upgrade-tables_renaming_18.0.0.0.app`"" $script += "New-CompiledALProjectApp -appProjectFolder `$appProjectFolder -appOutputFile `$appOutputFile -appSymbolsFolder (Join-Path `$appProjectFolder `".alpackages`")" $script += "" $script += "### ls-upgrade-tables_renaming-3rd_version-new_tables_names" $script += "`$appProjectFolder = Join-Path `$baseFolder `"ExtensionsSourceCode\ls-upgrade-tables_renaming-3rd_version-new_tables_names`"" $script += "`$appOutputFile = Join-Path `$baseFolder `"MigrationFiles\LS Retail_ls-upgrade-tables_renaming_18.0.1.0.app`"" $script += "New-CompiledALProjectApp -appProjectFolder `$appProjectFolder -appOutputFile `$appOutputFile -appSymbolsFolder (Join-Path `$appProjectFolder `".alpackages`")" $script += "" $script += "### ls-upgrade-tables_renaming-4th_version-migration" $script += "`$appProjectFolder = Join-Path `$baseFolder `"ExtensionsSourceCode\ls-upgrade-tables_renaming-4th_version-migration`"" $script += "`$appOutputFile = Join-Path `$baseFolder `"MigrationFiles\LS Retail_ls-upgrade-tables_renaming_18.0.2.0.app`"" $script += "New-CompiledALProjectApp -appProjectFolder `$appProjectFolder -appOutputFile `$appOutputFile -appSymbolsFolder (Join-Path `$appProjectFolder `".alpackages`")" $script += "" } $script += "### Task 6: Prepare the existing database (Only applicable if there's any AL extension in the database)" $script += "Get-NAVAppInfo -ServerInstance `$fromServerInstanceName" $script += "Get-NAVAppInfo -ServerInstance `$fromServerInstanceName | % { Uninstall-NAVApp -ServerInstance `$fromServerInstanceName -Name `$_.Name -Version `$_.Version -Force }" $script += "Get-NAVAppInfo -ServerInstance `$fromServerInstanceName -SymbolsOnly | % { Unpublish-NAVApp -ServerInstance `$fromServerInstanceName -Name `$_.Name -Version `$_.Version }" $script += "" return $script } function Get-PreparationScript_FromLS15OrLater { $fromServerInstanceName = $upgradeInitializationScriptConfig.FromBC.ServerInstance $fromBCServerPath = $upgradeInitializationScriptConfig.FromBC.ServerPath $multitenancy = $upgradeInitializationScriptConfig.Environment.Multitenant $fromVersion = $upgradeInitializationScriptConfig.FromBC.Version $fromMajorVersion = [int]($fromVersion.Split('.')[0]) $script = @() $script += "" $script += "###################### Initialization Helper ######################" $script += "" $script += "`$ErrorActionPreference = `"Stop`"" $script += "" $script += "## Create migration extensions folders" $script += "New-UpgradeAppsStructure -ImportSymbolsApp" $script += "" $script += "" $script += "`$fromServerInstanceName = `"$fromServerInstanceName`"" $script += "" if ($multitenancy) { $script += "### Update this with the right tenant name" $script += "`$tenantId = `"default`"" $script += "" } $script += "## BC $($fromMajorVersion)" $script += "Import-Module `"$((Join-Path $fromBCServerPath 'Service\NavAdminTool.ps1'))`" -Force" $script += "" $script += "### Task 3: Prepare the existing database" $script += "Get-NAVAppInfo -ServerInstance `$fromServerInstanceName" $script += "Get-NAVAppInfo -ServerInstance `$fromServerInstanceName | % { Uninstall-NAVApp -ServerInstance `$fromServerInstanceName -Name `$_.Name -Version `$_.Version -Force }" $script += "Get-NAVAppInfo -ServerInstance `$fromServerInstanceName -SymbolsOnly | % { Unpublish-NAVApp -ServerInstance `$fromServerInstanceName -Name `$_.Name -Version `$_.Version }" $script += "" $script += "Stop-NAVServerInstance -ServerInstance `$fromServerInstanceName" $script += "" return $script } function Get-MigrationScript { $fromLSVersion = $upgradeInitializationScriptConfig.FromBC.LSVersion $fromLSMajorVersion = [int]($fromLSVersion.Split('.')[0]) $script = @() switch ($fromLSMajorVersion) { "14" { $script = Get-MigrationScript_FromLS14 break } default { $script = Get-MigrationScript_FromLS15OrLater break } } return $script } function Get-MigrationScript_FromLS14 { $sqlServer = $upgradeInitializationScriptConfig.SQL.Server $sqlServerInstance = $upgradeInitializationScriptConfig.SQL.Instance $databaseName = $upgradeInitializationScriptConfig.SQL.Database $fromVersion = $upgradeInitializationScriptConfig.FromBc.Version $fromLSVersion = $upgradeInitializationScriptConfig.FromBc.LSVersion $toServerInstanceName = $upgradeInitializationScriptConfig.ToBC.ServerInstance $toBCServerPath = $upgradeInitializationScriptConfig.ToBC.ServerPath $toVersion = $upgradeInitializationScriptConfig.ToBC.Version $toFullVersion = Get-ApplicationVersionFromArtifacts -version $upgradeInitializationScriptConfig.ToBC.Version $toLSVersion = $upgradeInitializationScriptConfig.ToBC.LSVersion $toLSApp = Get-LSCentralAppInfo -version $toLsVersion -country $country $multitenancy = $upgradeInitializationScriptConfig.Environment.Multitenant $customExtensions = $upgradeInitializationScriptConfig.CustomExtensions $script = @() $script += "" $script += "" $script += "######################################################### Step 1 - Going from LS Central $fromLSVersion (on BC $fromVersion) to LS Central $toLSVersion (on BC $toVersion) #############################################################" $script += "############# WARNING: Please make sure that you close and open a new Powershell console window otherwise Business Central Powershell modules might not load properly (Invoke-NAVApplicationDatabaseConversion will not be found) #########" $script += "" $script += "## BC Folders" $script += "`$toBCServerPath = `"$toBCServerPath`"" $script += "" $script += "## BC Server Instances" $script += "`$toServerInstanceName = `"$toServerInstanceName`"" $script += "" $script += "## SQL" if ($sqlServerInstance -eq "") { $script += "`$fullDatabaseServer = `"$sqlServer`"" } else { $script += "`$fullDatabaseServer = `"$sqlServer\$sqlServerInstance`"" } $script += "`$databaseServerOnly = `"$sqlServer`"" $script += "`$databaseInstance = `"$sqlServerInstance`"" $script += "`$databaseName = `"$databaseName`"" $script += "" $script += "## Base folder" $script += "`$baseFolder = `"$(Get-Location)`"" $script += "" $script += "# Internal variables builder" $script += "`$migrationFilesPath = Join-Path `$baseFolder `"MigrationFiles`"" $script += "`$licenseFile = Join-Path `$baseFolder `"License\DEV.bclicense`"" $script += "" if ($multitenancy) { $script += "### Update this with the right tenant name" $script += "`$tenantId = `"default`"" $script += "" } $script += "`$ErrorActionPreference = `"Stop`"" $script += "" $script += "" $script += "# LS Central $toLsVersion (BC $toVersion)" $script += "Import-Module (Join-Path `$toBCServerPath 'Service\NavAdminTool.ps1') -Force" $script += "" $script += "###################################################################################################################################" $script += "" $script += "# Task 7: Convert version 14 database" $script += "Invoke-NAVApplicationDatabaseConversion -DatabaseServer `$fullDatabaseServer -DatabaseName `$databaseName -Force" $script += "" $script += "# Task 8: Configure version 19 server for DestinationAppsForMigration" $script += "Set-NAVServerConfiguration -ServerInstance `$toServerInstanceName -KeyName DatabaseServer -KeyValue `$databaseServerOnly" $script += "Set-NAVServerConfiguration -ServerInstance `$toServerInstanceName -KeyName DatabaseName -KeyValue `$databaseName" $script += "Set-NAVServerConfiguration -ServerInstance `$toServerInstanceName -KeyName DatabaseInstance -KeyValue `$databaseInstance" $script += "Set-NavServerConfiguration -ServerInstance `$toServerInstanceName -KeyName EnableTaskScheduler -KeyValue false" $script += "" $script += "Set-NAVServerConfiguration -ServerInstance `$toServerInstanceName -KeyName DestinationAppsForMigration -KeyValue '[{`"appId`":`"73dac250-f355-4b89-9b27-f98837f2d1f2`", `"name`":`"ls-upgrade`", `"publisher`": `"LS Retail`"}]'" $script += "" $script += "Set-NAVServerInstance -ServerInstance `$toServerInstanceName -Restart" $script += "" $script += "# Task 9: Import License" $script += Add-ImportNAVServerLicenseToScript -LicenseFile `$licenseFile -IsMultitenant $multitenancy $script += "Set-NAVServerInstance -ServerInstance `$toServerInstanceName -Restart" $script += "" $script += "# Task 10: Publish DestinationAppsForMigrations extensions" $script += Add-PublishNAVAppToScript -Path "(Join-Path `$migrationFilesPath 'ls-upgrade-1st_version.app')" -IsMultitenant $multitenancy -SkipVerification if ($upgradeMode -eq [UpgradeMode]::BC14_18_TablesRenamingInBC18) { $script += Add-PublishNAVAppToScript -Path "(Join-Path `$migrationFilesPath 'LS Retail_ls-upgrade-tables_renaming_14.0.0.0.app')" -IsMultitenant $multitenancy -SkipVerification } $script += Add-PublishNAVAppToScript -Path "(Join-Path `$migrationFilesPath 'ls-upgrade-system-empty.app')" -IsMultitenant $multitenancy -SkipVerification $script += Add-PublishNAVAppToScript -Path "(Join-Path `$migrationFilesPath 'ls-upgrade-base-empty.app')" -IsMultitenant $multitenancy -SkipVerification $script += Add-PublishNAVAppToScript -Path "(Join-Path `$migrationFilesPath 'ls-upgrade-lscentral-empty.app')" -IsMultitenant $multitenancy -SkipVerification $script += Add-PublishNAVAppToScript -Path "(Join-Path `$migrationFilesPath 'ls-upgrade-lscentral_system_app-empty.app')" -IsMultitenant $multitenancy -SkipVerification foreach ($extension in $customExtensions) { $appPackageName = Get-AppPackageName -Publisher $extension.Publisher -Name $extension.Name $appPackageName = "$($appPackageName)-empty" $script += Add-PublishNAVAppToScript -Path "(Join-Path `$migrationFilesPath '$($appPackageName).app')" -IsMultitenant $multitenancy -SkipVerification } if ($includeCustomizationAppPlaceholders) { $script += "### This is a placeholder" $script += Add-PublishNAVAppToScript -Path "(Join-Path `$migrationFilesPath 'Customization App_14.0.0.0.app')" -IsMultitenant $multitenancy -SkipVerification } $script += Add-GetNAVAppInfoToScript $script += "" $script += "# Task 11: Synchronize tenant" if ($multitenancy) { $script += "Mount-NAVTenant -ServerInstance `$toServerInstanceName -DatabaseName `$databaseName -DatabaseServer `$fullDatabaseServer -Tenant `$tenantId -AllowAppDatabaseWrite -Force" } $script += Add-SyncNAVTenantToScript -IsMultitenant $multitenancy -Mode Sync -Force $script += Add-SyncNAVAppToScript -Name "ls-upgrade" -Version 1.0.0.0 $script += Add-SyncNAVAppToScript -Name "System Application" -Version 14.0.0.0 $script += Add-SyncNAVAppToScript -Name "Base Application" -Version 14.0.0.0 $script += Add-SyncNAVAppToScript -Name "LS Central System App" -Version 14.0.0.0 $script += Add-SyncNAVAppToScript -Name "LS Central" -Version 14.0.0.0 foreach ($extension in $customExtensions) { $script += Add-SyncNAVAppToScript -Name $($extension.Name) -Version 0.0.0.1 } if ($includeCustomizationAppPlaceholders) { $script += "### This is a placeholder" $script += Add-SyncNAVAppToScript -Name "<Customization app name>" -Version 14.0.0.0 } if ($upgradeMode -eq [UpgradeMode]::BC14_18_TablesRenamingInBC18) { $script += Add-SyncNAVAppToScript -Name "ls-upgrade-tables_renaming" -Version 14.0.0.0 } $script += "" $script += "# Task 12: Install DestinationAppsForMigration and move tables" $script += Add-StartNAVDataUpgradeToScript -FunctionExecutionMode Serial -SkipAppVersionCheck -Force -IsMultitenant $multitenancy $script += " " + (Add-GetNavDataUpgradeToScript -IsMultitenant $multitenancy -Progress) $script += " " + (Add-GetNavDataUpgradeToScript -IsMultitenant $multitenancy -Detailed) $script += (Add-GetNAVTenantToScript -IsMultitenant $multitenancy) + " # State must be Operational when the data upgrade is finished." $script += "" $script += Add-InstallNAVAppToScript -Name "System Application" -Version 14.0.0.0 $script += Add-InstallNAVAppToScript -Name "Base Application" -Version 14.0.0.0 $script += Add-InstallNAVAppToScript -Name "LS Central System App" -Version 14.0.0.0 $script += Add-InstallNAVAppToScript -Name "LS Central" -Version 14.0.0.0 foreach ($extension in $customExtensions) { $script += Add-InstallNAVAppToScript -Name $($extension.Name) -Version 0.0.0.1 } if ($includeCustomizationAppPlaceholders) { $script += "### This is a placeholder" $script += Add-InstallNAVAppToScript -Name "<Customization app name>" -Version 14.0.0.0 } if ($upgradeMode -eq [UpgradeMode]::BC14_18_TablesRenamingInBC18) { $script += Add-InstallNAVAppToScript -Name "ls-upgrade-tables_renaming" -Version 14.0.0.0 } $script += "" if ($multitenancy) { $script += "### REPEAT THESE STEPS FOR EACH TENANT" } $script += "" $script += "# Task 13: Publish final extensions" $script += Add-PublishNAVAppToScript -Path "(Join-Path `$migrationFilesPath 'ls-upgrade-2nd_version-migration.app')" -IsMultitenant $multitenancy -SkipVerification if ($upgradeMode -eq [UpgradeMode]::BC14_18_TablesRenamingInBC18) { $script += Add-PublishNAVAppToScript -Path "(Join-Path `$migrationFilesPath 'LS Retail_ls-upgrade-tables_renaming_18.0.0.0.app')" -IsMultitenant $multitenancy -SkipVerification } $script += Add-PublishNAVAppToScript -Path "(Join-Path `$migrationFilesPath 'Microsoft_System Application_$($toFullVersion).app')" -IsMultitenant $multitenancy -SkipVerification $script += Add-PublishNAVAppToScript -Path "(Join-Path `$migrationFilesPath 'Microsoft_Base Application_$($toFullVersion).app')" -IsMultitenant $multitenancy -SkipVerification $script += "`$appInfo = (Get-NAVAppInfo -ServerInstance `$toServerInstanceName -Name `"Application`" -SymbolsOnly)[0]" $script += Add-UnpublishNAVAppToScript -Name "Application" -Version "`$appInfo.Version.ToString()" -IsMultitenant $multitenancy $script += Add-PublishNAVAppToScript -Path "(Join-Path `$migrationFilesPath 'Microsoft_Application_$($toFullVersion).app')" -IsMultitenant $multitenancy -SkipVerification $script += "" $script += Add-PublishNAVAppToScript -Path "(Join-Path `$migrationFilesPath `"$($toLSApp.systemFile)`")" -IsMultitenant $multitenancy -SkipVerification $script += Add-PublishNAVAppToScript -Path "(Join-Path `$migrationFilesPath `"$($toLSApp.appFile)`")" -IsMultitenant $multitenancy -SkipVerification if ($customExtensions.Count -gt 0) { $script += "## UPDATE TO THE APPROPRIATE CUSTOM EXTENSION APP FILE PATH AND NAME." foreach ($extension in $customExtensions) { $appFilename = Get-AppFileName -Publisher $extension.Publisher -Name $extension.Name -Version $extension.Version $script += Add-PublishNAVAppToScript -Path "(Join-Path `$migrationFilesPath '$($appFilename)')" -IsMultitenant $multitenancy -SkipVerification } } if ($includeCustomizationAppPlaceholders) { $script += "### This is a placeholder" $script += Add-PublishNAVAppToScript -Path "(Join-Path `$migrationFilesPath `"<customization final app file>`")" -IsMultitenant $multitenancy -SkipVerification } $script += Add-GetNAVAppInfoToScript $script += "" $script += "# Task 14: Synchronize final extensions" $script += Add-SyncNAVAppToScript -Name "System Application" -Version $($toFullVersion) $script += Add-SyncNAVAppToScript -Name "Base Application" -Version $($toFullVersion) $script += Add-SyncNAVAppToScript -Name "Application" -Version $($toFullVersion) $script += Add-SyncNAVAppToScript -Name "$($toLSApp.systemAppName)" -Version $($toLSApp.systemAppVersion) $script += Add-SyncNAVAppToScript -Name "$($toLSApp.appName)" -Version $($toLSApp.appVersion) foreach ($extension in $customExtensions) { $script += Add-SyncNAVAppToScript -Name "$($extension.Name)" -Version $($extension.Version) } if ($includeCustomizationAppPlaceholders) { $script += "### This is a placeholder" $script += Add-SyncNAVAppToScript -Name "<Customization app name>" -Version "<Customization final app version>" } if ($upgradeMode -eq [UpgradeMode]::BC14_18_TablesRenamingInBC18) { $script += Add-SyncNAVAppToScript -Name "ls-upgrade-tables_renaming" -Version "18.0.0.0" } $script += "Sync-NAVApp -ServerInstance `$toServerInstanceName -Tenant `$tenantId -Name `"ls-upgrade`" -Version 2.0.0.0 # -Mode ForceSync # -> Only if needed." $script += "" if ($upgradeMode -eq [UpgradeMode]::BC14_18_TablesRenamingInBC18) { $script += "Set-NAVServerConfiguration -ServerInstance `$toServerInstanceName -KeyName DestinationAppsForMigration -KeyValue '[{`"appId`":`"04e836a7-2c96-4bed-9651-a5c57572bb22`", `"name`":`"ls-upgrade-renamed-tables`", `"publisher`": `"LS Retail`"}]'" $script += "Set-NAVServerInstance -ServerInstance `$toServerInstanceName -Restart" $script += "" $script += Add-PublishNAVAppToScript -Path "(Join-Path `$migrationFilesPath 'LS Retail_ls-upgrade-tables_renaming_18.0.1.0.app')" -IsMultitenant $multitenancy $script += "Sync-NAVApp -ServerInstance `$toServerInstanceName -Tenant `$tenantId -Name `"ls-upgrade-tables_renaming`" -Version 18.0.1.0 -Mode ForceSync -Force" $script += "" $script += Add-PublishNAVAppToScript -Path "(Join-Path `$migrationFilesPath 'LS Retail_ls-upgrade-tables_renaming_18.0.2.0.app')" -IsMultitenant $multitenancy $script += Add-SyncNAVAppToScript -Name "ls-upgrade-tables_renaming" -Version "18.0.2.0" } $script += "" $script += "# Task 15: Upgrade empty table migration extension" $script += Add-StartNAVAppDataUpgradeToScript -Name "ls-upgrade" -Version "2.0.0.0" -IsMultitenant $multitenancy $script += "" $script += "# Task 16: Clean sync and unpublish table migration extensions" $script += "Uninstall-NAVApp -ServerInstance `$toServerInstanceName -Tenant `$tenantId -Name `"ls-upgrade`" -Version 2.0.0.0" if ($upgradeMode -eq [UpgradeMode]::BC14_18_TablesRenamingInBC18) { $script += "Uninstall-NAVApp -ServerInstance `$toServerInstanceName -Tenant `$tenantId -Name `"ls-upgrade-renamed-tables`" -Version 18.0.2.0" } $script += "Sync-NAVApp -ServerInstance `$toServerInstanceName -Tenant `$tenantId -Name `"ls-upgrade`" -Version 2.0.0.0 -Mode clean" if ($upgradeMode -eq [UpgradeMode]::BC14_18_TablesRenamingInBC18) { $script += "Sync-NAVApp -ServerInstance `$toServerInstanceName -Tenant `$tenantId -Name `"ls-upgrade-renamed-tables`" -Version 18.0.2.0 -Mode clean" } $script += Add-UnpublishNAVAppToScript -Name "ls-upgrade" -Version "1.0.0.0" -IsMultitenant $multitenancy $script += Add-UnpublishNAVAppToScript -Name "ls-upgrade" -Version "2.0.0.0" -IsMultitenant $multitenancy if ($upgradeMode -eq [UpgradeMode]::BC14_18_TablesRenamingInBC18) { $script += Add-UnpublishNAVAppToScript -Name "ls-upgrade-renamed-tables" -Version "14.0.0.0" -IsMultitenant $multitenancy $script += "Unpublish-NAVApp -ServerInstance `$toServerInstanceName -Tenant `$tenantId -Name `"ls-upgrade-renamed-tables`" -Version 18.0.0.0" $script += Add-UnpublishNAVAppToScript -Name "ls-upgrade-renamed-tables" -Version "18.0.0.0" -IsMultitenant $multitenancy $script += Add-UnpublishNAVAppToScript -Name "ls-upgrade-renamed-tables" -Version "18.0.1.0" -IsMultitenant $multitenancy $script += Add-UnpublishNAVAppToScript -Name "ls-upgrade-renamed-tables" -Version "18.0.2.0" -IsMultitenant $multitenancy } $script += "" $script += "" $script += "# Task 17: Upgrade and install final extensions" $script += Add-StartNAVAppDataUpgradeToScript -Name "System Application" -Version $($toFullVersion) -IsMultitenant $multitenancy $script += Add-StartNAVAppDataUpgradeToScript -Name "Base Application" -Version $($toFullVersion) -IsMultitenant $multitenancy $script += Add-InstallNAVAppToScript -Name "Application" -Version $($toFullVersion) $script += Add-StartNAVAppDataUpgradeToScript -Name "$($toLSApp.systemAppName)" -Version $($toLSApp.systemAppVersion) -IsMultitenant $multitenancy $script += Add-StartNAVAppDataUpgradeToScript -Name "$($toLSApp.appName)" -Version $($toLSApp.appVersion) -IsMultitenant $multitenancy foreach ($extension in $customExtensions) { $script += Add-StartNAVAppDataUpgradeToScript -Name "$($extension.Name)" -Version $($extension.Version) -IsMultitenant $multitenancy } if ($includeCustomizationAppPlaceholders) { $script += "### This is a placeholder" $script += Add-StartNAVAppDataUpgradeToScript -Name "<Customization app name>" -Version "<Customization final app version>" -IsMultitenant $multitenancy } $script += "" $script += "Set-NAVServerInstance -ServerInstance `$toServerInstanceName -Restart" $script += "" $script += "# Task 18: Upgrade control add-ins" $script += "`$servicesAddinsFolder = Join-Path `$toBCServerPath 'Service\Add-ins'" $script += "Set-NAVAddIn -ServerInstance `$toServerInstanceName -AddinName 'Microsoft.Dynamics.Nav.Client.BusinessChart' -PublicKeyToken 31bf3856ad364e35 -ResourceFile (Join-Path `$servicesAddinsFolder 'BusinessChart\Microsoft.Dynamics.Nav.Client.BusinessChart.zip')" $script += "Set-NAVAddIn -ServerInstance `$toServerInstanceName -AddinName 'Microsoft.Dynamics.Nav.Client.FlowIntegration' -PublicKeyToken 31bf3856ad364e35 -ResourceFile (Join-Path `$servicesAddinsFolder 'FlowIntegration\Microsoft.Dynamics.Nav.Client.FlowIntegration.zip')" $script += "Set-NAVAddIn -ServerInstance `$toServerInstanceName -AddinName 'Microsoft.Dynamics.Nav.Client.OAuthIntegration' -PublicKeyToken 31bf3856ad364e35 -ResourceFile (Join-Path `$servicesAddinsFolder 'OAuthIntegration\Microsoft.Dynamics.Nav.Client.OAuthIntegration.zip')" $script += "Set-NAVAddIn -ServerInstance `$toServerInstanceName -AddinName 'Microsoft.Dynamics.Nav.Client.PageReady' -PublicKeyToken 31bf3856ad364e35 -ResourceFile (Join-Path `$servicesAddinsFolder 'PageReady\Microsoft.Dynamics.Nav.Client.PageReady.zip')" $script += "Set-NAVAddIn -ServerInstance `$toServerInstanceName -AddinName 'Microsoft.Dynamics.Nav.Client.PowerBIManagement' -PublicKeyToken 31bf3856ad364e35 -ResourceFile (Join-Path `$servicesAddinsFolder 'PowerBIManagement\Microsoft.Dynamics.Nav.Client.PowerBIManagement.zip')" $script += "Set-NAVAddIn -ServerInstance `$toServerInstanceName -AddinName 'Microsoft.Dynamics.Nav.Client.RoleCenterSelector' -PublicKeyToken 31bf3856ad364e35 -ResourceFile (Join-Path `$servicesAddinsFolder 'RoleCenterSelector\Microsoft.Dynamics.Nav.Client.RoleCenterSelector.zip')" $script += "Set-NAVAddIn -ServerInstance `$toServerInstanceName -AddinName 'Microsoft.Dynamics.Nav.Client.SatisfactionSurvey' -PublicKeyToken 31bf3856ad364e35 -ResourceFile (Join-Path `$servicesAddinsFolder 'SatisfactionSurvey\Microsoft.Dynamics.Nav.Client.SatisfactionSurvey.zip')" $script += "Set-NAVAddIn -ServerInstance `$toServerInstanceName -AddinName 'Microsoft.Dynamics.Nav.Client.SocialListening' -PublicKeyToken 31bf3856ad364e35 -ResourceFile (Join-Path `$servicesAddinsFolder 'SocialListening\Microsoft.Dynamics.Nav.Client.SocialListening.zip')" $script += "Set-NAVAddIn -ServerInstance `$toServerInstanceName -AddinName 'Microsoft.Dynamics.Nav.Client.VideoPlayer' -PublicKeyToken 31bf3856ad364e35 -ResourceFile (Join-Path `$servicesAddinsFolder 'VideoPlayer\Microsoft.Dynamics.Nav.Client.VideoPlayer.zip')" $script += "Set-NAVAddIn -ServerInstance `$toServerInstanceName -AddinName 'Microsoft.Dynamics.Nav.Client.WebPageViewer' -PublicKeyToken 31bf3856ad364e35 -ResourceFile (Join-Path `$servicesAddinsFolder 'WebPageViewer\Microsoft.Dynamics.Nav.Client.WebPageViewer.zip')" $script += "Set-NAVAddIn -ServerInstance `$toServerInstanceName -AddinName 'Microsoft.Dynamics.Nav.Client.WelcomeWizard' -PublicKeyToken 31bf3856ad364e35 -ResourceFile (Join-Path `$servicesAddinsFolder 'WelcomeWizard\Microsoft.Dynamics.Nav.Client.WelcomeWizard.zip')" $script += "" $script += "# Task 19: Install upgraded permissions sets" $script += "" $script += "# Task 20: Change application version" $script += "Set-NAVApplication -ServerInstance `$toServerInstanceName -ApplicationVersion $($toFullVersion) -Force" $script += Add-SyncNAVTenantToScript -IsMultitenant $multitenancy -Mode Sync -Force $script += "" $script += Add-StartNAVDataUpgradeToScript -FunctionExecutionMode Serial -Force -IsMultitenant $multitenancy $script += " " + (Add-GetNavDataUpgradeToScript -IsMultitenant $multitenancy -Progress) $script += " " + (Add-GetNavDataUpgradeToScript -IsMultitenant $multitenancy -Detailed) $script += (Add-GetNAVTenantToScript -IsMultitenant $multitenancy) + " # State must be Operational when the data upgrade is finished." $script += "" $script += "# Post-upgrade tasks" $script += Add-UnpublishNAVAppToScript -Name "System Application" -Version "14.0.0.0" -IsMultitenant $multitenancy $script += Add-UnpublishNAVAppToScript -Name "Base Application" -Version "14.0.0.0" -IsMultitenant $multitenancy $script += Add-UnpublishNAVAppToScript -Name "$($toLSApp.appName)" -Version "14.0.0.0" -IsMultitenant $multitenancy $script += Add-UnpublishNAVAppToScript -Name "$($toLSApp.systemAppName)" -Version "14.0.0.0" -IsMultitenant $multitenancy foreach ($extension in $customExtensions) { $script += Add-UnpublishNAVAppToScript -Name "$($extension.Name)" -Version "0.0.0.1" -IsMultitenant $multitenancy } if ($includeCustomizationAppPlaceholders) { $script += "### This is a placeholder" $script += Add-UnpublishNAVAppToScript -Name "<Customization app name>" -Version "14.0.0.0" -IsMultitenant $multitenancy } $script += Add-GetNAVAppInfoToScript $script += "" $script += "Set-NavServerConfiguration -ServerInstance `$toServerInstanceName -KeyName EnableTaskScheduler -KeyValue true" $script += "" $script += "Set-NAVServerInstance -ServerInstance `$toServerInstanceName -Restart" $script += "" $script += "" return $script } function Get-MigrationScript_FromLS15OrLater { $sqlServer = $upgradeInitializationScriptConfig.SQL.Server $sqlServerInstance = $upgradeInitializationScriptConfig.SQL.Instance $databaseName = $upgradeInitializationScriptConfig.SQL.Database $fromVersion = $upgradeInitializationScriptConfig.FromBc.Version $fromLSVersion = $upgradeInitializationScriptConfig.FromBc.LSVersion $toServerInstanceName = $upgradeInitializationScriptConfig.ToBC.ServerInstance $toBCServerPath = $upgradeInitializationScriptConfig.ToBC.ServerPath $toVersion = $upgradeInitializationScriptConfig.ToBC.Version $toFullVersion = Get-ApplicationVersionFromArtifacts -version $upgradeInitializationScriptConfig.ToBC.Version $toLSVersion = $upgradeInitializationScriptConfig.ToBC.LSVersion $toLSApp = Get-LSCentralAppInfo -version $toLsVersion -country $country $fromLSMajorVersion = [int]($fromLSVersion.Split('.')[0]) $fromLSMajorMinorVersion = (($fromLSVersion.Split('.')[0])+ "." + ($fromLSVersion.Split('.')[1])) $multitenancy = $upgradeInitializationScriptConfig.Environment.Multitenant $customExtensions = $upgradeInitializationScriptConfig.CustomExtensions $script = @() $script += "" $script += "" $script += "######################################################### Step 1 - Going from LS Central $fromLSVersion (on BC $fromVersion) to LS Central $toLSVersion (on BC $toVersion) #############################################################" $script += "############# WARNING: Please make sure that you close and open a new Powershell console window otherwise Business Central Powershell modules might not load properly (Invoke-NAVApplicationDatabaseConversion will not be found) #########" $script += "" $script += "## BC Folders" $script += "`$toBCServerPath = `"$toBCServerPath`"" $script += "" $script += "## BC Server Instances" $script += "`$toServerInstanceName = `"$toServerInstanceName`"" $script += "" $script += "## SQL" if ($sqlServerInstance -eq "") { $script += "`$fullDatabaseServer = `"$sqlServer`"" } else { $script += "`$fullDatabaseServer = `"$sqlServer\$sqlServerInstance`"" } $script += "`$databaseServerOnly = `"$sqlServer`"" $script += "`$databaseInstance = `"$sqlServerInstance`"" $script += "`$databaseName = `"$databaseName`"" $script += "" $script += "## Base folder" $script += "`$baseFolder = `"$(Get-Location)`"" $script += "" $script += "# Internal variables builder" $script += "`$migrationFilesPath = Join-Path `$baseFolder `"MigrationFiles`"" $script += "`$licenseFile = Join-Path `$baseFolder `"License\DEV.bclicense`"" $script += "" if ($multitenancy) { $script += "### Update this with the right tenant name" $script += "`$tenantId = `"default`"" $script += "" } $script += "`$ErrorActionPreference = `"Stop`"" $script += "" $script += "" $script += "# LS Central $toLsVersion (BC $toVersion)" $script += "Import-Module (Join-Path `$toBCServerPath 'Service\NavAdminTool.ps1') -Force" $script += "" $script += "###################################################################################################################################" $script += "" $script += "# Task 4: Convert application database" $script += "Invoke-NAVApplicationDatabaseConversion -DatabaseServer `$fullDatabaseServer -DatabaseName `$databaseName -Force" $script += "" $script += "# Task 5: Configure server" $script += "Set-NAVServerConfiguration -ServerInstance `$toServerInstanceName -KeyName DatabaseServer -KeyValue `$databaseServerOnly" $script += "Set-NAVServerConfiguration -ServerInstance `$toServerInstanceName -KeyName DatabaseName -KeyValue `$databaseName" $script += "Set-NAVServerConfiguration -ServerInstance `$toServerInstanceName -KeyName DatabaseInstance -KeyValue `$databaseInstance" $script += "Set-NavServerConfiguration -ServerInstance `$toServerInstanceName -KeyName EnableTaskScheduler -KeyValue false" $script += "Set-NAVServerInstance -ServerInstance `$toServerInstanceName -Restart" $script += "" $script += "# Task 6: Import license" $script += Add-ImportNAVServerLicenseToScript -LicenseFile `$licenseFile -IsMultitenant $multitenancy $script += "Set-NAVServerInstance -ServerInstance `$toServerInstanceName -Restart" $script += "" $script += "# Task 7: Publish extensions" $script += Add-PublishNAVAppToScript -Path "(Join-Path `$migrationFilesPath 'Microsoft_System Application_$($toFullVersion).app')" -IsMultitenant $multitenancy -SkipVerification $script += Add-PublishNAVAppToScript -Path "(Join-Path `$migrationFilesPath 'Microsoft_Base Application_$($toFullVersion).app')" -IsMultitenant $multitenancy -SkipVerification $script += Add-PublishNAVAppToScript -Path "(Join-Path `$migrationFilesPath 'Microsoft_Application_$($toFullVersion).app')" -IsMultitenant $multitenancy -SkipVerification $script += Add-PublishNAVAppToScript -Path "(Join-Path `$migrationFilesPath `"$($toLSApp.systemFile)`")" -IsMultitenant $multitenancy -SkipVerification $script += Add-PublishNAVAppToScript -Path "(Join-Path `$migrationFilesPath `"$($toLSApp.appFile)`")" -IsMultitenant $multitenancy -SkipVerification if ($customExtensions.Count -gt 0) { $script += "## UPDATE TO THE APPROPRIATE CUSTOM EXTENSION APP FILE PATH AND NAME." foreach ($extension in $customExtensions) { $appFilename = Get-AppFileName -Publisher $extension.Publisher -Name $extension.Name -Version $extension.Version $script += Add-PublishNAVAppToScript -Path "(Join-Path `$migrationFilesPath '$($appFilename)')" -IsMultitenant $multitenancy -SkipVerification } } if ($includeCustomizationAppPlaceholders) { $script += "### This is a placeholder" $script += Add-PublishNAVAppToScript -Path "(Join-Path `$migrationFilesPath `"<customization final app file>`")" -IsMultitenant $multitenancy -SkipVerification } $script += Add-GetNAVAppInfoToScript $script += "" $script += "# Task 8: Synchronize tenant" if ($multitenancy) { $script += "Mount-NAVTenant -ServerInstance `$toServerInstanceName -DatabaseName `$databaseName -DatabaseServer `$fullDatabaseServer -Tenant `$tenantId -AllowAppDatabaseWrite -Force" } $script += Add-SyncNAVTenantToScript -IsMultitenant $multitenancy -Mode Sync -Force $script += Add-SyncNAVAppToScript -Name "System Application" -Version $($toFullVersion) $script += Add-SyncNAVAppToScript -Name "Base Application" -Version $($toFullVersion) $script += Add-SyncNAVAppToScript -Name "Application" -Version $($toFullVersion) $script += Add-SyncNAVAppToScript -Name "LS Central System App" -Version $($toLSApp.systemAppVersion) if ($fromLSMajorMinorVersion -le 17.4) { $script += Add-SyncNAVAppToScript -Name "LS Central" -Version $($toLSApp.appVersion) -Mode ForceSync -Force } else { $script += Add-SyncNAVAppToScript -Name "LS Central" -Version $($toLSApp.appVersion) } foreach ($extension in $customExtensions) { $script += Add-SyncNAVAppToScript -Name $($extension.Name) -Version $($extension.Version) } if ($includeCustomizationAppPlaceholders) { $script += "### This is a placeholder" $script += Add-SyncNAVAppToScript -Name "<Customization app name>" -Version "<Customization app version>" } $script += "" $script += "# Task 9: Upgrade data" if ($multitenancy) { $script += "### REPEAT THESE STEPS FOR EACH TENANT" $script += Add-StartNAVDataUpgradeToScript -FunctionExecutionMode Serial -SkipAppVersionCheck -Force -IsMultitenant $multitenancy $script += " " + (Add-GetNavDataUpgradeToScript -IsMultitenant $multitenancy -Progress) $script += " " + (Add-GetNavDataUpgradeToScript -IsMultitenant $multitenancy -Detailed) $script += (Add-GetNAVTenantToScript -IsMultitenant $multitenancy) + " # State must be Operational when the data upgrade is finished." $script += "" } else { $script += Add-StartNAVAppDataUpgradeToScript -Name "System Application" -Version $($toFullVersion) -IsMultitenant $multitenancy $script += Add-StartNAVAppDataUpgradeToScript -Name "Base Application" -Version $($toFullVersion) -IsMultitenant $multitenancy $script += Add-StartNAVAppDataUpgradeToScript -Name "Application" -Version $($toFullVersion) -IsMultitenant $multitenancy if ($fromLSMajorVersion -ge "18") { $script += Add-StartNAVAppDataUpgradeToScript -Name "$($toLSApp.systemAppName)" -Version $($toLSApp.systemAppVersion) -IsMultitenant $multitenancy } else { $script += Add-InstallNAVAppToScript -Name "$($toLSApp.systemAppName)" -Version $($toLSApp.systemAppVersion) -IsMultitenant $multitenancy } $script += Add-StartNAVAppDataUpgradeToScript -Name "$($toLSApp.appName)" -Version $($toLSApp.appVersion) -IsMultitenant $multitenancy foreach ($extension in $customExtensions) { $script += Add-StartNAVAppDataUpgradeToScript -Name "$($extension.Name)" -Version $($extension.Version) -IsMultitenant $multitenancy } if ($includeCustomizationAppPlaceholders) { $script += "### This is a placeholder" $script += Add-StartNAVAppDataUpgradeToScript -Name "<Customization app name>" -Version "<Customization final app version>" -IsMultitenant $multitenancy } $script += "" } $script += "Set-NAVServerInstance -ServerInstance `$toServerInstanceName -Restart" $script += "" $script += "# Task 11: Upgrade control add-ins" $script += "`$servicesAddinsFolder = Join-Path `$toBCServerPath 'Service\Add-ins'" $script += "Set-NAVAddIn -ServerInstance `$toServerInstanceName -AddinName 'Microsoft.Dynamics.Nav.Client.BusinessChart' -PublicKeyToken 31bf3856ad364e35 -ResourceFile (Join-Path `$servicesAddinsFolder 'BusinessChart\Microsoft.Dynamics.Nav.Client.BusinessChart.zip')" $script += "Set-NAVAddIn -ServerInstance `$toServerInstanceName -AddinName 'Microsoft.Dynamics.Nav.Client.FlowIntegration' -PublicKeyToken 31bf3856ad364e35 -ResourceFile (Join-Path `$servicesAddinsFolder 'FlowIntegration\Microsoft.Dynamics.Nav.Client.FlowIntegration.zip')" $script += "Set-NAVAddIn -ServerInstance `$toServerInstanceName -AddinName 'Microsoft.Dynamics.Nav.Client.OAuthIntegration' -PublicKeyToken 31bf3856ad364e35 -ResourceFile (Join-Path `$servicesAddinsFolder 'OAuthIntegration\Microsoft.Dynamics.Nav.Client.OAuthIntegration.zip')" $script += "Set-NAVAddIn -ServerInstance `$toServerInstanceName -AddinName 'Microsoft.Dynamics.Nav.Client.PageReady' -PublicKeyToken 31bf3856ad364e35 -ResourceFile (Join-Path `$servicesAddinsFolder 'PageReady\Microsoft.Dynamics.Nav.Client.PageReady.zip')" $script += "Set-NAVAddIn -ServerInstance `$toServerInstanceName -AddinName 'Microsoft.Dynamics.Nav.Client.PowerBIManagement' -PublicKeyToken 31bf3856ad364e35 -ResourceFile (Join-Path `$servicesAddinsFolder 'PowerBIManagement\Microsoft.Dynamics.Nav.Client.PowerBIManagement.zip')" $script += "Set-NAVAddIn -ServerInstance `$toServerInstanceName -AddinName 'Microsoft.Dynamics.Nav.Client.RoleCenterSelector' -PublicKeyToken 31bf3856ad364e35 -ResourceFile (Join-Path `$servicesAddinsFolder 'RoleCenterSelector\Microsoft.Dynamics.Nav.Client.RoleCenterSelector.zip')" $script += "Set-NAVAddIn -ServerInstance `$toServerInstanceName -AddinName 'Microsoft.Dynamics.Nav.Client.SatisfactionSurvey' -PublicKeyToken 31bf3856ad364e35 -ResourceFile (Join-Path `$servicesAddinsFolder 'SatisfactionSurvey\Microsoft.Dynamics.Nav.Client.SatisfactionSurvey.zip')" $script += "Set-NAVAddIn -ServerInstance `$toServerInstanceName -AddinName 'Microsoft.Dynamics.Nav.Client.SocialListening' -PublicKeyToken 31bf3856ad364e35 -ResourceFile (Join-Path `$servicesAddinsFolder 'SocialListening\Microsoft.Dynamics.Nav.Client.SocialListening.zip')" $script += "Set-NAVAddIn -ServerInstance `$toServerInstanceName -AddinName 'Microsoft.Dynamics.Nav.Client.VideoPlayer' -PublicKeyToken 31bf3856ad364e35 -ResourceFile (Join-Path `$servicesAddinsFolder 'VideoPlayer\Microsoft.Dynamics.Nav.Client.VideoPlayer.zip')" $script += "Set-NAVAddIn -ServerInstance `$toServerInstanceName -AddinName 'Microsoft.Dynamics.Nav.Client.WebPageViewer' -PublicKeyToken 31bf3856ad364e35 -ResourceFile (Join-Path `$servicesAddinsFolder 'WebPageViewer\Microsoft.Dynamics.Nav.Client.WebPageViewer.zip')" $script += "Set-NAVAddIn -ServerInstance `$toServerInstanceName -AddinName 'Microsoft.Dynamics.Nav.Client.WelcomeWizard' -PublicKeyToken 31bf3856ad364e35 -ResourceFile (Join-Path `$servicesAddinsFolder 'WelcomeWizard\Microsoft.Dynamics.Nav.Client.WelcomeWizard.zip')" $script += "" $script += "# Task 12: Install upgraded permissions sets" $script += "" $script += "# Task 13: Change application version" $script += "Set-NAVApplication -ServerInstance `$toServerInstanceName -ApplicationVersion $($toFullVersion) -Force" $script += Add-SyncNAVTenantToScript -IsMultitenant $multitenancy -Mode Sync -Force $script += "" $script += Add-StartNAVDataUpgradeToScript -FunctionExecutionMode Serial -Force -IsMultitenant $multitenancy $script += " " + (Add-GetNavDataUpgradeToScript -IsMultitenant $multitenancy -Progress) $script += " " + (Add-GetNavDataUpgradeToScript -IsMultitenant $multitenancy -Detailed) $script += (Add-GetNAVTenantToScript -IsMultitenant $multitenancy) + " # State must be Operational when the data upgrade is finished." $script += "" $script += "#Task Post" $script += "Set-NavServerConfiguration -ServerInstance `$toServerInstanceName -KeyName EnableTaskScheduler -KeyValue true" $script += "" $script += "Set-NAVServerInstance -ServerInstance `$toServerInstanceName -Restart" $script += "" $script += "" return $script } function Add-PublishNAVAppToScript { param ( [Parameter(Mandatory)] [string] $Path, [switch] $Force, [switch] $SkipVerification, [bool] $IsMultitenant ) $result = "Publish-NAVApp -ServerInstance `$toServerInstanceName -Path $($Path)" if ($Force.IsPresent) { $result += " -Force" } if ($SkipVerification.IsPresent) { $result += " -SkipVerification" } if ($IsMultitenant) { $result += " -Tenant `$tenantId" } return $result } function Add-UnpublishNAVAppToScript { param ( [bool] $IsMultitenant, [string] $Name, [string] $Version ) $result = "Unpublish-NAVApp -ServerInstance `$toServerInstanceName" if ($Name -ne "") { $result += " -Name `"$($Name)`"" } if ($Version -ne "") { $result += " -Version $($Version)" } if ($IsMultitenant) { $result += " -Tenant `$tenantId" } return $result } function Add-SyncNAVAppToScript { param ( [Parameter(Mandatory)] [string] $Name, [string] $Version, [switch] $Force, [ValidateSet("Add","Clean","Development","ForceSync","None")] [string] $Mode, [bool] $IsMultitenant ) $result = "Sync-NAVApp -ServerInstance `$toServerInstanceName -Name `"$($Name)`"" if ($Version -ne "") { $result += " -Version $($Version)" } if ($Mode -ne "") { $result += " -Mode $($Mode)" } if ($Force.IsPresent) { $result += " -Force" } if ($IsMultitenant) { $result += " -Tenant `$tenantId" } return $result } function Add-InstallNAVAppToScript { param ( [bool] $IsMultitenant, [string] $Name, [string] $Version ) $result = "Install-NAVApp -ServerInstance `$toServerInstanceName -Name `"$($Name)`"" if ($Version -ne "") { $result += " -Version $($Version)" } if ($Force.IsPresent) { $result += " -Force" } if ($IsMultitenant) { $result += " -Tenant `$tenantId" } return $result } function Add-StartNAVAppDataUpgradeToScript { param ( [bool] $IsMultitenant, [string] $Name, [string] $Version ) $result = "Start-NAVAppDataUpgrade -ServerInstance `$toServerInstanceName -Name `"$($Name)`"" if ($Version -ne "") { $result += " -Version $($Version)" } if ($Force.IsPresent) { $result += " -Force" } if ($IsMultitenant) { $result += " -Tenant `$tenantId" } return $result } function Add-SyncNAVTenantToScript { param ( [switch] $Force, [ValidateSet("ForceSync","Sync","CheckOnly")] [string] $Mode, [bool] $IsMultitenant ) $result = "Sync-NAVTenant -ServerInstance `$toServerInstanceName" if ($Mode -ne "") { $result += " -Mode $($Mode)" } if ($Force.IsPresent) { $result += " -Force" } if ($IsMultitenant) { $result += " -Tenant `$tenantId" } return $result } function Add-GetNAVAppInfoToScript { param ( [bool] $IsMultitenant ) $result = "Get-NAVAppInfo -ServerInstance `$toServerInstanceName" if ($IsMultitenant) { $result += " -Tenant `$tenantId" } return $result } function Add-ImportNAVServerLicenseToScript { param ( [string] $LicenseFile, [bool] $IsMultitenant ) $result = "Import-NAVServerLicense -ServerInstance `$toServerInstanceName -LicenseFile `$licenseFile" if ($IsMultitenant) { $result += " -Tenant `$tenantId" } return $result } function Add-StartNAVDataUpgradeToScript { param ( [Parameter(Mandatory)] [ValidateSet("Serial","Paralel")] [string] $FunctionExecutionMode, [switch] $SkipAppVersionCheck, [switch] $Force, [bool] $IsMultitenant ) $result = "Start-NAVDataUpgrade -ServerInstance `$toServerInstanceName -FunctionExecutionMode $($FunctionExecutionMode)" if ($SkipAppVersionCheck.IsPresent) { $result += " -SkipAppVersionCheck" } if ($Force.IsPresent) { $result += " -Force" } if ($IsMultitenant) { $result += " -Tenant `$tenantId" } return $result } function Add-GetNAVTenantToScript { param ( [bool] $IsMultitenant ) $result = "Get-NAVTenant -ServerInstance `$toServerInstanceName" if ($IsMultitenant) { $result += " -Tenant `$tenantId" } return $result } function Add-GetNAVDataUpgradeToScript { param ( [switch] $Progress, [switch] $Detailed, [bool] $IsMultitenant ) $result = "Get-NAVDataUpgrade -ServerInstance `$toServerInstanceName" if ($Progress.IsPresent) { $result += " -Progress" } if ($Detailed.IsPresent) { $result += " -Detailed" } if ($IsMultitenant) { $result += " -Tenant `$tenantId" } return $result } function Get-DefaultDestinationVersion { $app = Get-LSCentralAppInfo -DefaultVersion return $app.version } Export-ModuleMember -Function New-UpgradeInitializationScript Export-ModuleMember -Function Add-PublishNAVAppToScript Export-ModuleMember -Function Add-UnpublishNAVAppToScript Export-ModuleMember -Function Add-SyncNAVAppToScript Export-ModuleMember -Function Add-InstallNAVAppToScript Export-ModuleMember -Function Add-StartNAVAppDataUpgradeToScript Export-ModuleMember -Function Add-SyncNAVTenantToScript Export-ModuleMember -Function Add-GetNAVAppInfoToScript Export-ModuleMember -Function Add-ImportNAVServerLicenseToScript Export-ModuleMember -Function Add-StartNAVDataUpgradeToScript Export-ModuleMember -Function Add-GetNAVDataUpgradeToScript Export-ModuleMember -Function Add-GetNAVTenantToScript Export-ModuleMember -Function Get-DefaultDestinationVersion |