Modules/businessdev.ALbuild.Marketplace/Public/Submit-BcMarketplaceApp.ps1
|
function Submit-BcMarketplaceApp { <# .SYNOPSIS Submits an AL app to Microsoft Marketplace (AppSource) end to end. .DESCRIPTION Orchestrates a Marketplace submission: authenticates (Partner Center and product-ingestion scopes), resolves the product by name, uploads the app (and library apps) and creates a submission, waits for validation, and optionally promotes it to live. Requires a valid ALbuild license. .PARAMETER ProductName The Marketplace product (offer) name. OPTIONAL - defaults to the main app's manifest name. Provide it only to override (e.g. when the offer name differs from the app name). .PARAMETER AppPath A folder of built .app files, or a single .app file. The main app and its library (dependency) apps are selected automatically and TEST apps are excluded - so a task can just point at the build output folder without naming a specific, version-stamped file. .PARAMETER LibraryAppPath Optional additional folder(s) or .app file(s) whose apps are submitted as library apps, for offers whose main app and library app are built by different pipelines/repositories and so arrive as separate release artifacts (e.g. Address Validation + its Extension License library). Test apps are excluded. Only valid with -AppPath. .PARAMETER AppFile (Legacy) An explicit main .app file. Prefer -AppPath. Ignored when -AppPath is given. .PARAMETER LibraryAppFile Optional dependent/library .app files (only used with the legacy -AppFile). .PARAMETER TenantId Azure AD tenant id for the Partner Center service principal. .PARAMETER ClientId Service principal client id. .PARAMETER ClientSecret Service principal client secret. .PARAMETER PublisherId Numeric publisher/Seller ID (Partner Center > Settings > Account settings > Identifiers). Required by the Partner Center ingestion API (sent as the 'x-ms-publisherId' header). .PARAMETER AutoPromote Promote to live after successful validation. .PARAMETER TimeoutMinutes Validation timeout. Default 30. .EXAMPLE Submit-BcMarketplaceApp -AppPath .\output -TenantId $tenantId -ClientId $clientId -ClientSecret $clientSecret -PublisherId '1234567' -AutoPromote Submits the main app and its library apps from the build output folder and promotes the submission to live once it validates. .OUTPUTS PSCustomObject with ProductId, SubmissionId, State, Substate, Promoted. #> [CmdletBinding(SupportsShouldProcess, DefaultParameterSetName = 'Path')] [OutputType([PSCustomObject])] param( [string] $ProductName, [Parameter(Mandatory, ParameterSetName = 'Path')] [string] $AppPath, [Parameter(ParameterSetName = 'Path')] [string[]] $LibraryAppPath = @(), [Parameter(Mandatory, ParameterSetName = 'Legacy')] [string] $AppFile, [Parameter(ParameterSetName = 'Legacy')] [string[]] $LibraryAppFile = @(), [Parameter(Mandatory)] [string] $TenantId, [Parameter(Mandatory)] [string] $ClientId, [Parameter(Mandatory)] [object] $ClientSecret, [Parameter(Mandatory)] [string] $PublisherId, [switch] $AutoPromote, [int] $TimeoutMinutes = 30 ) Assert-ALbuildLicensed -Feature 'Marketplace' # Resolve the apps to submit. -AppPath (folder or file) auto-selects the main app + library apps and # drops test apps; -AppFile is the explicit legacy path. if ($PSCmdlet.ParameterSetName -eq 'Path') { $resolveArgs = @{ Path = $AppPath } if (@($LibraryAppPath).Count -gt 0) { $resolveArgs['LibraryPath'] = $LibraryAppPath } $set = Resolve-BcMarketplaceAppSet @resolveArgs $AppFile = $set.MainApp.File $LibraryAppFile = @($set.LibraryApps | ForEach-Object { $_.File }) if (-not $ProductName) { $ProductName = $set.MainApp.Name Write-ALbuildLog "No product name supplied; using the main app's manifest name '$ProductName'." } } elseif (-not $ProductName) { # Legacy path with no explicit name: derive it from the app's manifest. $ProductName = (Expand-BcAppFile -Path $AppFile).Name Write-ALbuildLog "No product name supplied; using the app's manifest name '$ProductName'." } if (-not $ProductName) { throw 'Could not determine the Marketplace product name (no -ProductName and no readable app manifest).' } # Product lookup uses the Graph product-ingestion scope; the submission uses the Partner Center scope # (which requires the PublisherId / x-ms-publisherId header). $graphAuth = New-BcMarketplaceAuthContext -TenantId $TenantId -ClientId $ClientId -ClientSecret $ClientSecret -Scope 'https://graph.microsoft.com/.default' -PublisherId $PublisherId $partnerAuth = New-BcMarketplaceAuthContext -TenantId $TenantId -ClientId $ClientId -ClientSecret $ClientSecret -Scope 'https://api.partner.microsoft.com/.default' -PublisherId $PublisherId Write-ALbuildLog "Resolving product '$ProductName' ..." $products = @(Get-BcMarketplaceProduct -AuthContext $graphAuth -Name $ProductName) if ($products.Count -eq 0) { throw "Marketplace product '$ProductName' was not found (product name = the offer 'alias')." } if ($products.Count -gt 1) { throw "Multiple products match '$ProductName' ($(($products | ForEach-Object { $_.alias }) -join ', ')); use a more specific name." } $product = $products[0] Write-ALbuildLog "Product '$($product.alias)' ($($product.id))." if (-not $PSCmdlet.ShouldProcess($product.alias, 'Create and validate Marketplace submission')) { return } # New-BcMarketplaceSubmission uploads the package(s), creates the preview submission, waits for # validation and (with -AutoPromote) promotes to live - the proven Publish-AppSourceApp flow. return New-BcMarketplaceSubmission -AuthContext $partnerAuth -ProductId $product.id ` -AppFile $AppFile -LibraryAppFile $LibraryAppFile -AutoPromote:$AutoPromote -TimeoutMinutes $TimeoutMinutes } |