diff --git a/AppHandling/Compile-AppInNavContainer.ps1 b/AppHandling/Compile-AppInNavContainer.ps1 index 8570f97db..31e4d658b 100644 --- a/AppHandling/Compile-AppInNavContainer.ps1 +++ b/AppHandling/Compile-AppInNavContainer.ps1 @@ -502,28 +502,43 @@ try { try { # Import types needed to invoke the compiler $alcPath = 'C:\build\vsix\extension\bin' - Add-Type -Path (Join-Path $alcPath Newtonsoft.Json.dll) - Add-Type -Path (Join-Path $alcPath System.Collections.Immutable.dll) - Add-Type -Path (Join-Path $alcPath System.IO.Packaging.dll) - Add-Type -Path (Join-Path $alcPath Microsoft.Dynamics.Nav.CodeAnalysis.dll) - - $packageStream = [System.IO.File]::OpenRead($symbolsFile) - $package = [Microsoft.Dynamics.Nav.CodeAnalysis.Packaging.NavAppPackageReader]::Create($PackageStream, $true) - $manifest = $package.ReadNavAppManifest() - - if ($manifest.application) { - @{ "publisher" = "Microsoft"; "name" = "Application"; "appId" = ''; "version" = $manifest.Application } + $alToolExe = Join-Path $alcPath 'win32\altool.exe' + $alToolExists = Test-Path -Path $alToolExe -PathType Leaf + if ($alToolExists) { + $manifest = & "$alToolExe" GetPackageManifest "$symbolsFile" | ConvertFrom-Json + if ($manifest.PSObject.Properties.Name -eq 'application' -and $manifest.application) { + @{ "publisher" = "Microsoft"; "name" = "Application"; "appId" = ''; "version" = $manifest.Application } + } + if ($manifest.PSObject.Properties.Name -eq 'dependencies') { + foreach ($dependency in $manifest.dependencies) { + @{ "publisher" = $dependency.Publisher; "name" = $dependency.name; "appId" = $dependency.id; "Version" = $dependency.Version } + } + } } - - foreach ($dependency in $manifest.dependencies) { - $appId = '' - if ($dependency.psobject.Properties.name -eq 'appid') { - $appId = $dependency.appid + else { + Add-Type -Path (Join-Path $alcPath Newtonsoft.Json.dll) + Add-Type -Path (Join-Path $alcPath System.Collections.Immutable.dll) + Add-Type -Path (Join-Path $alcPath System.IO.Packaging.dll) + Add-Type -Path (Join-Path $alcPath Microsoft.Dynamics.Nav.CodeAnalysis.dll) + + $packageStream = [System.IO.File]::OpenRead($symbolsFile) + $package = [Microsoft.Dynamics.Nav.CodeAnalysis.Packaging.NavAppPackageReader]::Create($PackageStream, $true) + $manifest = $package.ReadNavAppManifest() + + if ($manifest.application) { + @{ "publisher" = "Microsoft"; "name" = "Application"; "appId" = ''; "version" = $manifest.Application } } - elseif ($dependency.psobject.Properties.name -eq 'id') { - $appId = $dependency.id + + foreach ($dependency in $manifest.dependencies) { + $appId = '' + if ($dependency.psobject.Properties.name -eq 'appid') { + $appId = $dependency.appid + } + elseif ($dependency.psobject.Properties.name -eq 'id') { + $appId = $dependency.id + } + @{ "publisher" = $dependency.Publisher; "name" = $dependency.name; "appId" = $appId; "Version" = $dependency.Version } } - @{ "publisher" = $dependency.Publisher; "name" = $dependency.name; "appId" = $appId; "Version" = $dependency.Version } } } catch [System.Reflection.ReflectionTypeLoadException] { diff --git a/Common/Download-File.ps1 b/Common/Download-File.ps1 index 2753b27d2..035529d72 100644 --- a/Common/Download-File.ps1 +++ b/Common/Download-File.ps1 @@ -78,7 +78,8 @@ try { Invoke-WebRequest -UseBasicParsing -Uri $sourceUrl -OutFile $destinationFile } else { - if ($bcContainerHelperConfig.DoNotUseCdnForArtifacts) { + if ($bcContainerHelperConfig.DoNotUseCdnForArtifacts -or $sourceUrl -like 'https://bcinsider.azureedge.net/*') { + # Do not use CDN when configured or bcinsider $sourceUrl = ReplaceCDN -sourceUrl $sourceUrl } try { diff --git a/CompilerFolderHandling/Compile-AppWithBcCompilerFolder.ps1 b/CompilerFolderHandling/Compile-AppWithBcCompilerFolder.ps1 index d7b7e39d8..a83ba49f1 100644 --- a/CompilerFolderHandling/Compile-AppWithBcCompilerFolder.ps1 +++ b/CompilerFolderHandling/Compile-AppWithBcCompilerFolder.ps1 @@ -124,10 +124,8 @@ try { throw "CompilerFolder doesn't exist" } - $vsixPath = Join-Path $compilerFolder 'compiler' $dllsPath = Join-Path $compilerFolder 'dlls' $symbolsPath = Join-Path $compilerFolder 'symbols' - $binPath = Join-Path $vsixPath 'extension/bin' $appJsonFile = Join-Path $appProjectFolder 'app.json' $appJsonObject = [System.IO.File]::ReadAllLines($appJsonFile) | ConvertFrom-Json diff --git a/CompilerFolderHandling/New-BcCompilerFolder.ps1 b/CompilerFolderHandling/New-BcCompilerFolder.ps1 index 4a9f06dc5..0c096056c 100644 --- a/CompilerFolderHandling/New-BcCompilerFolder.ps1 +++ b/CompilerFolderHandling/New-BcCompilerFolder.ps1 @@ -216,6 +216,12 @@ try { } if ($isLinux) { + $alToolExePath = Join-Path $containerCompilerPath 'extension/bin/linux/altool' + if (Test-Path $alToolExePath) { + # Set execute permissions on altool + Write-Host "Setting execute permissions on altool" + & /usr/bin/env sudo pwsh -command "& chmod +x $alToolExePath" + } $alcExePath = Join-Path $containerCompilerPath 'extension/bin/linux/alc' if (Test-Path $alcExePath) { # Set execute permissions on alc diff --git a/HelperFunctions.ps1 b/HelperFunctions.ps1 index 81d378a1b..dc515c264 100644 --- a/HelperFunctions.ps1 +++ b/HelperFunctions.ps1 @@ -1118,13 +1118,16 @@ function GetAppInfo { $binPath = Join-Path $compilerFolder 'compiler/extension/bin' if ($isLinux) { $alcPath = Join-Path $binPath 'linux' + $alToolExe = Join-Path $alcPath 'altool' } else { $alcPath = Join-Path $binPath 'win32' + $alToolExe = Join-Path $alcPath 'altool.exe' } if (-not (Test-Path $alcPath)) { $alcPath = $binPath } + $alToolExists = Test-Path -Path $alToolExe -PathType Leaf $alcDllPath = $alcPath if (!$isLinux -and !$isPsCore) { $alcDllPath = $binPath @@ -1142,27 +1145,42 @@ function GetAppInfo { Write-Host " (cached)" } else { - if (!$assembliesAdded) { - Add-Type -AssemblyName System.IO.Compression.FileSystem - Add-Type -AssemblyName System.Text.Encoding - LoadDLL -Path (Join-Path $alcDllPath Newtonsoft.Json.dll) - LoadDLL -Path (Join-Path $alcDllPath System.Collections.Immutable.dll) - LoadDLL -Path (Join-Path $alcDllPath System.IO.Packaging.dll) - LoadDLL -Path (Join-Path $alcDllPath Microsoft.Dynamics.Nav.CodeAnalysis.dll) - $assembliesAdded = $true + if ($alToolExists) { + $manifest = CmdDo -Command $alToolExe -arguments @('GetPackageManifest', """$path""") -returnValue -silent | ConvertFrom-Json + $appInfo = @{ + "appId" = $manifest.id + "publisher" = $manifest.publisher + "name" = $manifest.name + "version" = $manifest.version + "application" = "$(if($manifest.PSObject.Properties.Name -eq 'application'){$manifest.application})" + "platform" = "$(if($manifest.PSObject.Properties.Name -eq 'platform'){$manifest.Platform})" + "propagateDependencies" = ($manifest.PSObject.Properties.Name -eq 'PropagateDependencies') -and $manifest.PropagateDependencies + "dependencies" = @(if($manifest.PSObject.Properties.Name -eq 'dependencies'){$manifest.dependencies | ForEach-Object { @{ "id" = $_.id; "name" = $_.name; "publisher" = $_.publisher; "version" = $_.version }}}) + } } - $packageStream = [System.IO.File]::OpenRead($path) - $package = [Microsoft.Dynamics.Nav.CodeAnalysis.Packaging.NavAppPackageReader]::Create($PackageStream, $true) - $manifest = $package.ReadNavAppManifest() - $appInfo = @{ - "appId" = $manifest.AppId - "publisher" = $manifest.AppPublisher - "name" = $manifest.AppName - "version" = "$($manifest.AppVersion)" - "dependencies" = @($manifest.Dependencies | ForEach-Object { @{ "id" = $_.AppId; "name" = $_.Name; "publisher" = $_.Publisher; "version" = "$($_.Version)" } }) - "application" = "$($manifest.Application)" - "platform" = "$($manifest.Platform)" - "propagateDependencies" = $manifest.PropagateDependencies + else { + if (!$assembliesAdded) { + Add-Type -AssemblyName System.IO.Compression.FileSystem + Add-Type -AssemblyName System.Text.Encoding + LoadDLL -Path (Join-Path $alcDllPath Newtonsoft.Json.dll) + LoadDLL -Path (Join-Path $alcDllPath System.Collections.Immutable.dll) + LoadDLL -Path (Join-Path $alcDllPath System.IO.Packaging.dll) + LoadDLL -Path (Join-Path $alcDllPath Microsoft.Dynamics.Nav.CodeAnalysis.dll) + $assembliesAdded = $true + } + $packageStream = [System.IO.File]::OpenRead($path) + $package = [Microsoft.Dynamics.Nav.CodeAnalysis.Packaging.NavAppPackageReader]::Create($PackageStream, $true) + $manifest = $package.ReadNavAppManifest() + $appInfo = @{ + "appId" = $manifest.AppId + "publisher" = $manifest.AppPublisher + "name" = $manifest.AppName + "version" = "$($manifest.AppVersion)" + "dependencies" = @($manifest.Dependencies | ForEach-Object { @{ "id" = $_.AppId; "name" = $_.Name; "publisher" = $_.Publisher; "version" = "$($_.Version)" } }) + "application" = "$($manifest.Application)" + "platform" = "$($manifest.Platform)" + "propagateDependencies" = $manifest.PropagateDependencies + } } Write-Host " (succeeded)" if ($appInfoCache) { diff --git a/ReleaseNotes.txt b/ReleaseNotes.txt index a6c26cd77..63c858ffd 100644 --- a/ReleaseNotes.txt +++ b/ReleaseNotes.txt @@ -1,4 +1,7 @@ 6.0.2 +When using Publish-PerTenantExtensionApps with a set of apps, which takes a very long time to publish, the AccessToken might expire and lead to failure. AccessToken is now refreshed when needed. +Issue #3254 vsix no longer includes dotnet framework 4.8 compatible dlls for version 24 +Avoid using CDN when downloading from bcinsider as this frequently changes and subsequently fails 6.0.1 New-AadAppsForBC doesn't work with the newer versions of Microsoft.Graph module (where the type of the accesstoken parameter has changed) diff --git a/Saas/Publish-PerTenantExtensionApps.ps1 b/Saas/Publish-PerTenantExtensionApps.ps1 index 35b0779ef..c4bf74a4e 100644 --- a/Saas/Publish-PerTenantExtensionApps.ps1 +++ b/Saas/Publish-PerTenantExtensionApps.ps1 @@ -49,6 +49,11 @@ function Publish-PerTenantExtensionApps { $telemetryScope = InitTelemetryScope -name $MyInvocation.InvocationName -parameterValues $PSBoundParameters -includeParameters @() try { + function GetAuthHeaders { + $bcAuthContext = Renew-BcAuthContext -bcAuthContext $bcAuthContext + return @{ "Authorization" = "Bearer $($bcAuthContext.AccessToken)" } + } + $newLine = @{} if (!$useNewLine) { $newLine = @{ "NoNewLine" = $true } @@ -70,18 +75,14 @@ try { throw "Authentication failed" } } - else { - $bcAuthContext = Renew-BcAuthContext -bcAuthContext $bcAuthContext - } $appFolder = Join-Path ([System.IO.Path]::GetTempPath()) ([guid]::NewGuid().ToString()) try { $appFiles = CopyAppFilesToFolder -appFiles $appFiles -folder $appFolder $automationApiUrl = "$($bcContainerHelperConfig.apiBaseUrl.TrimEnd('/'))/v2.0/$environment/api/microsoft/automation/v2.0" - $authHeaders = @{ "Authorization" = "Bearer $($bcauthcontext.AccessToken)" } Write-Host "$automationApiUrl/companies" - $companies = Invoke-RestMethod -Headers $authHeaders -Method Get -Uri "$automationApiUrl/companies" -UseBasicParsing + $companies = Invoke-RestMethod -Headers (GetAuthHeaders) -Method Get -Uri "$automationApiUrl/companies" -UseBasicParsing $company = $companies.value | Where-Object { ($companyName -eq "") -or ($_.name -eq $companyName) } | Select-Object -First 1 if (!($company)) { throw "No company $companyName" @@ -90,7 +91,7 @@ try { Write-Host "Company '$companyName' has id $companyId" Write-Host "$automationApiUrl/companies($companyId)/extensions" - $getExtensions = Invoke-WebRequest -Headers $authHeaders -Method Get -Uri "$automationApiUrl/companies($companyId)/extensions" -UseBasicParsing + $getExtensions = Invoke-WebRequest -Headers (GetAuthHeaders) -Method Get -Uri "$automationApiUrl/companies($companyId)/extensions" -UseBasicParsing $extensions = (ConvertFrom-Json $getExtensions.Content).value | Sort-Object -Property DisplayName if(!$hideInstalledExtensionsOutput) { @@ -147,20 +148,20 @@ try { Write-Host @newLine "publishing and installing" } if (!$existingApp) { - $extensionUpload = (Invoke-RestMethod -Method Get -Uri "$automationApiUrl/companies($companyId)/extensionUpload" -Headers $authHeaders).value + $extensionUpload = (Invoke-RestMethod -Method Get -Uri "$automationApiUrl/companies($companyId)/extensionUpload" -Headers (GetAuthHeaders)).value Write-Host @newLine "." if ($extensionUpload -and $extensionUpload.systemId) { $extensionUpload = Invoke-RestMethod ` -Method Patch ` -Uri "$automationApiUrl/companies($companyId)/extensionUpload($($extensionUpload.systemId))" ` - -Headers ($authHeaders + $ifMatchHeader + $jsonHeader) ` + -Headers ((GetAuthHeaders) + $ifMatchHeader + $jsonHeader) ` -Body ($body | ConvertTo-Json -Compress) } else { $ExtensionUpload = Invoke-RestMethod ` -Method Post ` -Uri "$automationApiUrl/companies($companyId)/extensionUpload" ` - -Headers ($authHeaders + $jsonHeader) ` + -Headers ((GetAuthHeaders) + $jsonHeader) ` -Body ($body | ConvertTo-Json -Compress) } Write-Host @newLine "." @@ -171,22 +172,22 @@ try { Invoke-RestMethod ` -Method Patch ` -Uri $extensionUpload.'extensionContent@odata.mediaEditLink' ` - -Headers ($authHeaders + $ifMatchHeader + $streamHeader) ` + -Headers ((GetAuthHeaders) + $ifMatchHeader + $streamHeader) ` -Body $fileBody | Out-Null Write-Host @newLine "." Invoke-RestMethod ` -Method Post ` -Uri "$automationApiUrl/companies($companyId)/extensionUpload($($extensionUpload.systemId))/Microsoft.NAV.upload" ` - -Headers ($authHeaders + $ifMatchHeader) | Out-Null + -Headers ((GetAuthHeaders) + $ifMatchHeader) | Out-Null Write-Host @newLine "." $completed = $false $errCount = 0 - $sleepSeconds = 5 + $sleepSeconds = 30 while (!$completed) { Start-Sleep -Seconds $sleepSeconds try { - $extensionDeploymentStatusResponse = Invoke-WebRequest -Headers $authHeaders -Method Get -Uri "$automationApiUrl/companies($companyId)/extensionDeploymentStatus" -UseBasicParsing + $extensionDeploymentStatusResponse = Invoke-WebRequest -Headers (GetAuthHeaders) -Method Get -Uri "$automationApiUrl/companies($companyId)/extensionDeploymentStatus" -UseBasicParsing $extensionDeploymentStatuses = (ConvertFrom-Json $extensionDeploymentStatusResponse.Content).value $completed = $true @@ -231,7 +232,7 @@ try { throw } finally { - $getExtensions = Invoke-WebRequest -Headers $authHeaders -Method Get -Uri "$automationApiUrl/companies($companyId)/extensions" -UseBasicParsing + $getExtensions = Invoke-WebRequest -Headers (GetAuthHeaders) -Method Get -Uri "$automationApiUrl/companies($companyId)/extensions" -UseBasicParsing $extensions = (ConvertFrom-Json $getExtensions.Content).value | Sort-Object -Property DisplayName if (!$hideInstalledExtensionsOutput) {