Modules/businessdev.ALbuild.RuntimePackages/Private/Get-BcRuntimePackageFileName.ps1

function Get-BcRuntimePackageFileName {
    <#
    .SYNOPSIS
        Returns the runtime package file name by BC convention: '<publisher>_<name>_<version>.app'.
 
    .DESCRIPTION
        This name is not cosmetic - it is half of a live contract. Runtime packages are published to
        blob storage as '<appId>/<platformVersion>/<publisher>_<name>_<version>.app', and that path is
        what downloads.365businessdev.com links, what the blob retention rules match on, and what the
        planner compares against to decide whether a package already exists. Deriving it differently
        anywhere would make the planner rebuild everything (name never matches) or the retention delete
        the wrong file.
 
        Spaces are deliberately kept: unlike a NuGet id segment, the BC file-name convention uses the
        publisher and app name verbatim.
 
    .PARAMETER Publisher
        The app.json publisher.
 
    .PARAMETER Name
        The app.json name.
 
    .PARAMETER Version
        The app version.
 
    .OUTPUTS
        System.String
    #>

    [CmdletBinding()]
    [OutputType([string])]
    param(
        [Parameter(Mandatory)] [AllowEmptyString()] [string] $Publisher,
        [Parameter(Mandatory)] [AllowEmptyString()] [string] $Name,
        [Parameter(Mandatory)] [AllowEmptyString()] [string] $Version
    )

    return ('{0}_{1}_{2}.app' -f $Publisher, $Name, $Version)
}