Extension/Upgrade-Extensions.ps1

<#
.SYNOPSIS
    Upgrades extensions in the database
.DESCRIPTION
    For the specified instance performs installation or upgrade of the extensions.
    Extension files (*.app) are searched in the folder and then processed one by one.
    If the extension is not present in the database then it gets installed.
    If there is a version of extension already installed its version is checked. If installed version is lover that the one in the folder then extension is upgraded. It's skipped otherwise.
    If there are dependencies between extensions being installed then files should be named accordingly. Files will be frocessed in alphabetical order.
    There are ways to narrow down list of extensions to be processed.
        `Path` parameter can point to the file or folder. If it points to the file then only that file will be processed and `Apps` parameter will be ignored.
        If `Path` parameter points to the folder and `Apps` parameter contains list of filenemes then only those files from the folder will be processed.
        If `Apps` parameter is not provided then all *.app files from `Path` folder will be processed.
    Path parameter can be omitted, current working folder will be used then.
.EXAMPLE
    Upgrade-Extensions -instanceName BC140
    Installs/upgrades all extensions from the current working folder
.EXAMPLE
    Upgrade-Extensions -instanceName BC140 -path "c:\extensions"
    Installs/upgrades all extensions from folder
.EXAMPLE
    Upgrade-Extensions -instanceName BC140 -path "c:\extensions" -apps "01 - Ext1.app", "03 - Ext1.app"
    Installs/upgrades two extensions from folder. Supposed that there might have been "02 - Ext1.app" in the same folder, which will be skipped in this case.
.EXAMPLE
    Upgrade-Extensions -instanceName BC140 -path "c:\extensions\02 - Ext1.app"
    Installs/upgrades an extension from file
.NOTES
    Must be run as administrator because it requires to tun Sync-NavTenant cmdlet.
#>

function Upgrade-Extension {
    [alias("ugex")]
    [cmdletbinding(SupportsShouldProcess)]
    param(
        # Destination BC instance where extensions should be installed/upgraded to.
        [Parameter(Mandatory = $false, ValueFromPipeline)]
        [ArgumentCompleter({ Import-NavModule -Admin; Get-NAVServerInstance | % { $_.ServerInstance -replace ".*\$", "" } })]
        [ValidateScript( { $_ -ne ""} )]
        [string]$instanceName = $PatchHelperConfig.DefaultInstance,
        # Path to folder with extension files or fullname of the extension.
        [Parameter(Mandatory = $false)]
        [string]$path = (Get-Location),
        # Array of app file names
        [Parameter(Mandatory = $false)]
        [string[]]$apps,
        [switch]$offline
    )
    process {
        # Error handling behavior
        $ErrorActionPreference = "Stop"
        Write-Host "Upgrading extensions on $instanceName" -ForegroundColor Green
        $UpgradeScriptPath = Join-Path $PSScriptRoot "Extension Upgrade Scripts\ExtensionUpgrade.ps1"
        if (-not $apps) {
            if (Test-Path $path -PathType Leaf) {
                $apps = @([System.IO.Path]::GetFileName($path))
                $path = [System.IO.Path]::GetDirectoryName($path)
            } else {
                $apps = Get-ChildItem -Path $path -Filter '*.app' -File | % { [System.IO.Path]::GetFileName($_) }
            }
        }else {
            if (Test-Path $path -PathType Leaf) {
                throw "`Path` parameter points to the file, not folder. Don't use `apps` parameter if you specified file in the `path` parameter." }
        }
        if (-not $apps) { throw "No apps found in $path" }
        $apps | % {
            Write-Host $_ -ForegroundColor Gray
            $appPath = Join-Path $path $_
            if ($PSCmdlet.ShouldProcess((Join-Path $path $_),"Upgrade extension")){
                & $UpgradeScriptPath -ServerInstance $instanceName -Path $appPath -SkipVerification $True -InstallIfAbsent $True | Write-Host
            }
            # (optionally) Report to mothership about patch installation
            if (!$offline) {
                if (!$PatchHelperConfig.CustomerName -or !$PatchHelperConfig.ReportURL -or !$PatchHelperConfig.DefaultInstance) {
                    Write-Warning "Installation reporting is not configured. Please run Register-PatchHelper or use -offline switch"
                } else {
                    if ($PatchHelperConfig.DefaultInstance -eq $instanceName) {
                        $inf = Get-NAVAppInfo -Path $appPath
                        if ($PSCmdlet.ShouldProcess("-extensionName ""$($inf.Name)"" -extensionVersion ""$($inf.Version.ToString())""", "Send-PatchInfo")) {
                            Send-PatchInfo -extensionName $inf.Name -extensionVersion $inf.Version.ToString()
                        }
                    }
                }
            }
        }
    }
}

Export-ModuleMember -Function * -Alias *