From cb965cb9d9fd546b18b399097fbc4c1f109a86c8 Mon Sep 17 00:00:00 2001 From: Freddy Kristiansen Date: Wed, 24 Apr 2024 09:04:11 +0200 Subject: [PATCH] Issue3473 (#3505) Fixes #3473 + allowing mixed sessions (PS5/PS7) by not reusing cached session + do not pre-initialize a container session + speed up invoke-script --------- Co-authored-by: freddydk --- AppHandling/Clean-BcContainerDatabase.ps1 | 2 +- AzureAD/New-AadAppsForBc.ps1 | 11 ++-- AzureAD/Remove-AadAppsForBc.ps1 | 11 +--- .../Export-NavContainerDatabasesAsBacpac.ps1 | 66 ++++++++++--------- ContainerHandling/Get-NavContainerSession.ps1 | 16 ++++- .../Invoke-ScriptInNavContainer.ps1 | 10 +-- ContainerHandling/Wait-NavContainerReady.ps1 | 16 ----- TenantHandling/New-NavContainerTenant.ps1 | 2 +- 8 files changed, 66 insertions(+), 68 deletions(-) diff --git a/AppHandling/Clean-BcContainerDatabase.ps1 b/AppHandling/Clean-BcContainerDatabase.ps1 index 2211fee48..8a52d3cd1 100644 --- a/AppHandling/Clean-BcContainerDatabase.ps1 +++ b/AppHandling/Clean-BcContainerDatabase.ps1 @@ -96,7 +96,7 @@ try { $copyTables += @("Entitlement", "Entitlement Set", "Membership Entitlement") } - Invoke-ScriptInBCContainer -containerName $containerName -scriptblock { Param($platformVersion, $databaseName, $databaseServer, $databaseInstance, $copyTables, $multitenant) + Invoke-ScriptInBCContainer -containerName $containerName -useSession $false -usePwsh $false -scriptblock { Param($platformVersion, $databaseName, $databaseServer, $databaseInstance, $copyTables, $multitenant) Write-Host "Stopping ServiceTier in order to replace database" Set-NavServerInstance -ServerInstance $ServerInstance -stop diff --git a/AzureAD/New-AadAppsForBc.ps1 b/AzureAD/New-AadAppsForBc.ps1 index ef9a501d8..7830cf521 100644 --- a/AzureAD/New-AadAppsForBc.ps1 +++ b/AzureAD/New-AadAppsForBc.ps1 @@ -82,12 +82,13 @@ try { $accessToken = $bcAuthContext.accessToken } if ($accessToken) { - try { - # Connect-MgGraph changed type of accesstoken parameter from plain text to securestring along the way - Connect-MgGraph -accessToken (ConvertTo-SecureString -String $accessToken -AsPlainText -Force) | Out-Null + # Check the AccessToken since Microsoft Graph V2 requires a SecureString + $graphAccesTokenParameter = (Get-Command Connect-MgGraph).Parameters['AccessToken'] + if ($graphAccesTokenParameter.ParameterType -eq [securestring]) { + Connect-MgGraph -AccessToken (ConvertTo-SecureString -String $accessToken -AsPlainText -Force) | Out-Null } - catch [System.ArgumentException] { - Connect-MgGraph -accessToken $accessToken | Out-Null + else { + Connect-MgGraph -AccessToken $accessToken | Out-Null } } else { diff --git a/AzureAD/Remove-AadAppsForBc.ps1 b/AzureAD/Remove-AadAppsForBc.ps1 index ab5ede889..cd1b0c0ff 100644 --- a/AzureAD/Remove-AadAppsForBc.ps1 +++ b/AzureAD/Remove-AadAppsForBc.ps1 @@ -39,13 +39,6 @@ try { Install-Package Microsoft.Graph -Force -WarningAction Ignore | Out-Null } - # Check the AccessToken since Microsoft Graph V2 requires a SecureString - $graphAccesTokenParameter = (Get-Command Connect-MgGraph).Parameters['AccessToken'] - - if ($graphAccesTokenParameter.ParameterType -eq [securestring]){ - $useSecureStringForAccessToken = $true - } - # Connect to Microsoft.Graph if (!$useCurrentMicrosoftGraphConnection) { if ($bcAuthContext) { @@ -57,7 +50,9 @@ try { $accessToken = $bcAuthContext.accessToken } if ($accessToken) { - if ($useSecureStringForAccessToken){ + # Check the AccessToken since Microsoft Graph V2 requires a SecureString + $graphAccesTokenParameter = (Get-Command Connect-MgGraph).Parameters['AccessToken'] + if ($graphAccesTokenParameter.ParameterType -eq [securestring]) { Connect-MgGraph -AccessToken (ConvertTo-SecureString -String $accessToken -AsPlainText -Force) | Out-Null } else { diff --git a/Bacpac/Export-NavContainerDatabasesAsBacpac.ps1 b/Bacpac/Export-NavContainerDatabasesAsBacpac.ps1 index 65e99c495..3a939d7a8 100644 --- a/Bacpac/Export-NavContainerDatabasesAsBacpac.ps1 +++ b/Bacpac/Export-NavContainerDatabasesAsBacpac.ps1 @@ -17,6 +17,8 @@ Include this parameter to avoid checking entitlements. Entitlements are needed if the .bacpac file is to be used for cloud deployments. .Parameter includeDacPac Use this parameter to export databases as dacpac + .Parameter dacPacOnly + Use this parameter to export databases as dacpac only (skip Bacpac) .Parameter commandTimeout Timeout in seconds for the export command for every database. Default is 1 hour (3600). .Parameter diagnostics @@ -43,6 +45,7 @@ function Export-BcContainerDatabasesAsBacpac { [string[]] $tenant = @("default"), [int] $commandTimeout = 3600, [switch] $includeDacPac, + [switch] $dacPacOnly, [switch] $diagnostics, [switch] $doNotCheckEntitlements, [string[]] $additionalArguments = @() @@ -64,7 +67,7 @@ try { } $containerBacpacFolder = Get-BcContainerPath -containerName $containerName -path $bacpacFolder -throw - Invoke-ScriptInBcContainer -containerName $containerName -ScriptBlock { Param([PSCredential]$sqlCredential, $bacpacFolder, $tenant, $commandTimeout, $includeDacPac, $diagnostics, $additionalArguments, $doNotCheckEntitlements) + Invoke-ScriptInBcContainer -containerName $containerName -ScriptBlock { Param([PSCredential]$sqlCredential, $bacpacFolder, $tenant, $commandTimeout, $includeDacPac, $dacPacOnly, $diagnostics, $additionalArguments, $doNotCheckEntitlements) function CmdDo { Param( @@ -388,40 +391,43 @@ try { [Parameter(Mandatory=$false)] [int] $commandTimeout = 3600, [switch] $includeDacPac, + [switch] $dacPacOnly, [switch] $diagnostics, [Parameter(Mandatory=$false)] [string[]] $additionalArguments = @() ) - Write-Host "Exporting as BacPac..." + if (!$dacPacOnly) { + Write-Host "Exporting as BacPac..." - $arguments = @( - ('/Action:Export'), - ('/TargetFile:"'+$targetFile+'"'), - ('/SourceDatabaseName:"'+$databaseName+'"'), - ('/SourceServerName:"'+$databaseServer+'"'), - ('/OverwriteFiles:True') - ("/p:CommandTimeout=$commandTimeout") - ) - - if ($diagnostics) { - $arguments += @('/Diagnostics:True') - } - - if ($sqlCredential) { - $arguments += @( - ('/SourceUser:"'+$sqlCredential.UserName+'"'), - ('/SourcePassword:"'+([System.Runtime.InteropServices.Marshal]::PtrToStringAuto([System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($sqlCredential.Password)))+'"') + $arguments = @( + ('/Action:Export'), + ('/TargetFile:"'+$targetFile+'"'), + ('/SourceDatabaseName:"'+$databaseName+'"'), + ('/SourceServerName:"'+$databaseServer+'"'), + ('/OverwriteFiles:True') + ("/p:CommandTimeout=$commandTimeout") ) + + if ($diagnostics) { + $arguments += @('/Diagnostics:True') + } + + if ($sqlCredential) { + $arguments += @( + ('/SourceUser:"'+$sqlCredential.UserName+'"'), + ('/SourcePassword:"'+([System.Runtime.InteropServices.Marshal]::PtrToStringAuto([System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($sqlCredential.Password)))+'"') + ) + } + + if ($additionalArguments) { + $arguments += $additionalArguments + } + + CmdDo -command $sqlpackageExe -arguments ($arguments -join ' ') } - - if ($additionalArguments) { - $arguments += $additionalArguments - } - - CmdDo -command $sqlpackageExe -arguments ($arguments -join ' ') - if ($includeDacPac) { + if ($includeDacPac -or $dacPacOnly) { Write-Host "Extracting as DacPac..." $arguments = @( ('/Action:Extract'), @@ -481,7 +487,7 @@ try { Remove-WindowsUsers -DatabaseServer $databaseServerInstance -DatabaseName $tempAppDatabaseName -sqlCredential $sqlCredential Remove-ApplicationRoles -DatabaseServer $databaseServerInstance -DatabaseName $tempAppDatabaseName -sqlCredential $sqlCredential Remove-NavDatabaseSystemTableData -DatabaseServer $databaseServerInstance -DatabaseName $tempAppDatabaseName -sqlCredential $sqlCredential - Do-Export -DatabaseServer $databaseServerInstance -DatabaseName $tempAppDatabaseName -sqlCredential $sqlCredential -targetFile $appBacpacFileName -commandTimeout $commandTimeout -includeDacPac:$includeDacPac -diagnostics:$diagnostics -additionalArguments $additionalArguments + Do-Export -DatabaseServer $databaseServerInstance -DatabaseName $tempAppDatabaseName -sqlCredential $sqlCredential -targetFile $appBacpacFileName -commandTimeout $commandTimeout -includeDacPac:$includeDacPac -dacPacOnly:$dacPacOnly -diagnostics:$diagnostics -additionalArguments $additionalArguments $tenant | ForEach-Object { $sourceDatabase = $_ @@ -499,7 +505,7 @@ try { Remove-WindowsUsers -DatabaseServer $databaseServerInstance -DatabaseName $tempTenantDatabaseName -sqlCredential $sqlCredential Remove-ApplicationRoles -DatabaseServer $databaseServerInstance -DatabaseName $tempTenantDatabaseName -sqlCredential $sqlCredential Remove-NavTenantDatabaseUserData -DatabaseServer $databaseServerInstance -DatabaseName $tempTenantDatabaseName -sqlCredential $sqlCredential - Do-Export -DatabaseServer $databaseServerInstance -DatabaseName $tempTenantDatabaseName -sqlCredential $sqlCredential -targetFile $tenantBacpacFileName -commandTimeout $commandTimeout -includeDacPac:$includeDacPac -diagnostics:$diagnostics -additionalArguments $additionalArguments + Do-Export -DatabaseServer $databaseServerInstance -DatabaseName $tempTenantDatabaseName -sqlCredential $sqlCredential -targetFile $tenantBacpacFileName -commandTimeout $commandTimeout -includeDacPac:$includeDacPac -dacPacOnly:$dacPacOnly -diagnostics:$diagnostics -additionalArguments $additionalArguments } } else { $tempDatabaseName = "temp$DatabaseName" @@ -512,9 +518,9 @@ try { Remove-ApplicationRoles -DatabaseServer $databaseServerInstance -DatabaseName $tempDatabaseName -sqlCredential $sqlCredential Remove-NavDatabaseSystemTableData -DatabaseServer $databaseServerInstance -DatabaseName $tempDatabaseName -sqlCredential $sqlCredential Remove-NavTenantDatabaseUserData -DatabaseServer $databaseServerInstance -DatabaseName $tempDatabaseName -sqlCredential $sqlCredential - Do-Export -DatabaseServer $databaseServerInstance -DatabaseName $tempDatabaseName -sqlCredential $sqlCredential -targetFile $bacpacFileName -commandTimeout $commandTimeout -includeDacPac:$includeDacPac -diagnostics:$diagnostics -additionalArguments $additionalArguments + Do-Export -DatabaseServer $databaseServerInstance -DatabaseName $tempDatabaseName -sqlCredential $sqlCredential -targetFile $bacpacFileName -commandTimeout $commandTimeout -includeDacPac:$includeDacPac -dacPacOnly:$dacPacOnly -diagnostics:$diagnostics -additionalArguments $additionalArguments } - } -ArgumentList $sqlCredential, $containerBacpacFolder, $tenant, $commandTimeout, $includeDacPac, $diagnostics, $additionalArguments, $doNotCheckEntitlements + } -ArgumentList $sqlCredential, $containerBacpacFolder, $tenant, $commandTimeout, $includeDacPac, $dacPacOnly, $diagnostics, $additionalArguments, $doNotCheckEntitlements } catch { TrackException -telemetryScope $telemetryScope -errorRecord $_ diff --git a/ContainerHandling/Get-NavContainerSession.ps1 b/ContainerHandling/Get-NavContainerSession.ps1 index 5daffa3ef..35fb06f38 100644 --- a/ContainerHandling/Get-NavContainerSession.ps1 +++ b/ContainerHandling/Get-NavContainerSession.ps1 @@ -29,8 +29,18 @@ function Get-BcContainerSession { if ($sessions.ContainsKey($containerName)) { $session = $sessions[$containerName] try { - Invoke-Command -Session $session -ScriptBlock { $true } | Out-Null - if (!$reinit) { return $session } + $platformVersion = Invoke-Command -Session $session -ScriptBlock { [System.Version](get-item 'C:\Program Files\Microsoft Dynamics NAV\*\Service\Microsoft.Dynamics.Nav.Server.exe').Versioninfo.FileVersion } + if ($platformVersion -ge 24 -and ($usePwsh -xor $session.ConfigurationName -eq 'PowerShell.7')) { + # Cannot use existing session + Remove-PSSession -Session $session + $sessions.Remove($containerName) + $session = $null + } + else { + if (!$reinit) { + return $session + } + } } catch { Remove-PSSession -Session $session @@ -40,7 +50,7 @@ function Get-BcContainerSession { } if (!$session) { [System.Version]$platformVersion = Get-BcContainerPlatformVersion -containerOrImageName $containerName - if ($platformVersion -lt [System.Version]"24.0.0.0") { + if ($platformVersion.Major -lt 24) { $usePwsh = $false } $configurationName = 'Microsoft.PowerShell' diff --git a/ContainerHandling/Invoke-ScriptInNavContainer.ps1 b/ContainerHandling/Invoke-ScriptInNavContainer.ps1 index c63a11241..7619bad28 100644 --- a/ContainerHandling/Invoke-ScriptInNavContainer.ps1 +++ b/ContainerHandling/Invoke-ScriptInNavContainer.ps1 @@ -30,10 +30,12 @@ function Invoke-ScriptInBcContainer { [bool] $usePwsh = $bccontainerHelperConfig.usePwshForBc24 ) - $file = Join-Path $bcContainerHelperConfig.hostHelperFolder ([GUID]::NewGuid().Tostring()+'.ps1') - $containerFile = $containerFile = Get-BcContainerPath -containerName $containerName -path $file - if ($isInsideContainer -or "$containerFile" -eq "") { - $useSession = $true + if (!$useSession) { + $file = Join-Path $bcContainerHelperConfig.hostHelperFolder ([GUID]::NewGuid().Tostring()+'.ps1') + $containerFile = $containerFile = Get-BcContainerPath -containerName $containerName -path $file + if ($isInsideContainer -or "$containerFile" -eq "") { + $useSession = $true + } } if ($useSession) { diff --git a/ContainerHandling/Wait-NavContainerReady.ps1 b/ContainerHandling/Wait-NavContainerReady.ps1 index 5f2cb1f6c..b87427b52 100644 --- a/ContainerHandling/Wait-NavContainerReady.ps1 +++ b/ContainerHandling/Wait-NavContainerReady.ps1 @@ -42,16 +42,6 @@ function Wait-BcContainerReady { throw "Initialization of container $containerName failed" } - if ($isAdministrator -and $bcContainerHelperConfig.usePsSession -and $cnt -eq ($timeout-30)) { - try { - if (!$sessions.ContainsKey($containerName)) { - $containerId = Get-BcContainerId -containerName $containerName - $session = New-PSSession -ContainerId $containerId -RunAsAdministrator - $sessions.Add($containerName, $session) - } - } catch {} - } - if ($cnt % 5 -eq 0) { $inspect = docker inspect $containerName | ConvertFrom-Json if ($inspect.State.Status -eq "exited") { @@ -63,11 +53,6 @@ function Wait-BcContainerReady { } while (!($log.Contains("Ready for connections!"))) Write-Host - if ($bcContainerHelperConfig.usePsSession) { - try { - Get-BcContainerSession -containerName $containerName -reinit -silent | Out-Null - } catch {} - } Invoke-ScriptInBcContainer -containerName $containerName -scriptblock { $boo = $true @@ -76,7 +61,6 @@ function Wait-BcContainerReady { Start-Sleep -Seconds 1 } } - } } Set-Alias -Name Wait-NavContainerReady -Value Wait-BcContainerReady diff --git a/TenantHandling/New-NavContainerTenant.ps1 b/TenantHandling/New-NavContainerTenant.ps1 index bc9dd9175..70c1ee78f 100644 --- a/TenantHandling/New-NavContainerTenant.ps1 +++ b/TenantHandling/New-NavContainerTenant.ps1 @@ -46,7 +46,7 @@ try { throw "You cannot add a tenant called tenant" } - Invoke-ScriptInBcContainer -containerName $containerName -ScriptBlock { Param($containerName, $tenantId, [PSCredential]$sqlCredential, $sourceDatabase, $destinationDatabase, $alternateId, $doNotCopyDatabase, $allowAppDatabaseWrite, $applicationInsightsKey) + Invoke-ScriptInBcContainer -containerName $containerName -useSession $false -usePwsh $false -ScriptBlock { Param($containerName, $tenantId, [PSCredential]$sqlCredential, $sourceDatabase, $destinationDatabase, $alternateId, $doNotCopyDatabase, $allowAppDatabaseWrite, $applicationInsightsKey) $customConfigFile = Join-Path (Get-Item "C:\Program Files\Microsoft Dynamics NAV\*\Service").FullName "CustomSettings.config" [xml]$customConfig = [System.IO.File]::ReadAllText($customConfigFile)