3CX

Questions about WAPT Packaging / Requests and help regarding Wapt packages.
Forum Rules
Community Forum Rules
* English support on www.reddit.com/r/wapt
* French community support is available on this forum
* Please prefix the topic title with [RESOLVED] if it is resolved.
* Please do not edit a topic that is tagged [RESOLVED]. Open a new topic referencing the old one.
* Specify the installed WAPT version, full version, and build number (2.2.1.11957 / 2.2.2.12337 / etc.) as well as the Enterprise/Discovery edition.
* Versions 1.8.2 and earlier are no longer supported. The only questions accepted regarding version 1.8.2 are related to upgrading to a supported version (2.1, 2.2, etc.).
* Specify the server OS (Linux/Windows) and version (Debian Buster/Bullseye - CentOS 7 - Windows Server 2012/2016/2019).
* Specify the OS of the administration/package creation machine and the machine with the problematic agent, if applicable (Windows 7/10/11/Debian 11/etc.).
* Avoid asking multiple questions when opening a topic, otherwise it may be ignored. If there are multiple topics, open separate topics, preferably one after the other and not all at the same time (i.e., do not spam the forum).
* Include code snippets, screenshots, and other images directly in the post. Links to Pastebin, Bitly, and other third-party sites will be systematically removed.
* As with any community forum, support is provided voluntarily by members. If you require commercial support, you can contact Tranquil IT's sales department at 02.40.97.57.55
Answer
smandel
Messages: 111
Registration: May 5, 2022 - 11:30

April 4, 2025 - 11:31

Good morning,

The "msi" version of the 3CX client is no longer being updated and I have not found a package in the WAPT store offering the updated MSIX version.
So I created a package for those who might be interested, inspired by the Teams UWP package from the store.
You must first download the latest versions of MSIX from https://store.rg-adguard.net/
There are probably better ways to write code, but it works :)

setup.py

Code: Select all

# -*- coding: utf-8 -*-
from setuphelpers import *

appx_package_name = "3CX"
appx_dir = makepath(systemdrive,programfiles, "3CX", "3CX.msix")
appx_dir_dependance = makepath(systemdrive,programfiles, "3CX", "Microsoft.WindowsAppRuntime.1.6.msix")

def install():
    # Declare local variables
    bin_path = glob.glob(f"{appx_package_name}*.msix")[0]
    bin_path_dependance = glob.glob(f"Microsoft.WindowsAppRuntime.1.6.msix")[0]
    mkdirs(makepath(systemdrive,programfiles,"3CX"))

    filecopyto(bin_path, appx_dir)
    filecopyto(bin_path, appx_dir_dependance)

    # Remove old versions
    appxprovisionedpackage = run_powershell(f'Get-AppXProvisionedPackage -Online | Where-Object DisplayName -Like "{appx_package_name}*"')
    if appxprovisionedpackage is None:
        remove_appx(appx_package_name, False)
        appxprovisionedpackage = {"Version": "0"}
    elif force:
        uninstall()

    #Installing the application
    if Version(appxprovisionedpackage["Version"], 4) < Version(control.get_software_version(), 4):
        print(f"Installing: {bin_path.split(os.sep)[-1]} ({control.get_software_version()})")
        killalltasks(ensure_list(control.impacted_process))
        run_powershell(f'Add-AppxProvisionedPackage -Online -PackagePath "{bin_path_dependance}" -SkipLicense')
        run_powershell(f'Add-AppxProvisionedPackage -Online -PackagePath "{bin_path}" -SkipLicense')

    else:
        print(f'{appxprovisionedpackage["PackageName"]} is already installed and up-to-date.')

    if isdir(makepath(programfiles,"3CX")):
        remove_tree(makepath(programfiles,"3CX"))

def uninstall():
    print(f"Removing AppX: {appx_package_name}")
    remove_appx(appx_package_name)


def audit():
    # Declaring local variables
    audit_result = "OK"
    audit_version = True
    appxprovisionedpackage = run_powershell(f'Get-AppXProvisionedPackage -Online | Where-Object DisplayName -Like "{appx_package_name}*"')

    # Auditing software
    if appxprovisionedpackage is None:
        print(f"{appx_package_name} is not installed.")
        audit_result = "ERROR"
    elif audit_version:
        if Version(appxprovisionedpackage.get("Version", "0"), 4) < Version(control.get_software_version(), 4):
            print(
                f'{appxprovisionedpackage["PackageName"]} is installed in version: {appxprovisionedpackage["Version"]} instead of: {control.get_software_version()}.'
            )
            audit_result = "WARNING"
        else:
            print(f'{appxprovisionedpackage["PackageName"]} is installed and up-to-date.')
    else:
        print(f'{appxprovisionedpackage["PackageName"]} is installed.')

    return audit_result


def remove_appx(package, default_user=True):
    """Remove Windows AppX package from the computer environment, excluding NonRemovable packages.

    Args:
        package (str): AppX package name. You can use an asterisk (*) as a wildcard.
        default_user (bool): Remove AppX package from the Windows image to prevent installation for new users.

    .. versionchanged:: 2.5
        No longer try to remove NonRemovable AppX package

    .. versionchanger:: 2.6
        No longer use run_powershell for uninstall
    """

    if running_as_admin() or running_as_system():
        if default_user:
            ps_script = f'Get-AppXProvisionedPackage -Online | Where-Object DisplayName -Like ""{package}*"" | Remove-AppxProvisionedPackage -Online -AllUsers'
            run_powershell_script(ps_script, output_format="text")

        ps_script = f'Get-AppxPackage -Name ""{package}*"" -AllUsers | Where-Object -property NonRemovable -notlike True | Remove-AppxPackage -AllUsers'
        run_powershell_script(ps_script, output_format="text")

    else:
        ps_script = f'Get-AppxPackage -Name ""{package}"" | Where-Object -property NonRemovable -notlike True | Remove-AppxPackage'
        run_powershell_script(ps_script, output_format="text")
update-package.py

Code: Select all

# -*- coding: utf-8 -*-
from setuphelpers import *
from setupdevhelpers import *


def update_package():
    # Declaring local variables
    package_updated = False
    proxies = get_proxies()
    if not proxies:
        proxies = get_proxies_from_wapt_console()

    download_url = "https://downloads-global.3cx.com/downloads/3cxsoftphone/3CX.msix"
    latest_bin = download_url.split("/")[-1]

    # Deleting binaries
    remove_file(latest_bin)

    # Downloading latest binaries
    print("Download URL is: %s" % download_url)
    if not isfile(latest_bin):
        print("Downloading: %s" % latest_bin)
        wget(download_url, latest_bin, proxies=proxies)
    else:
        print("Binary is present: %s" % latest_bin)

    # Checking version from file
    if get_os_name() == "Windows" and "windows" in control.target_os.lower():
        version_bin = unzip(latest_bin, ".", "3CXSoftphone.exe")[0]
        version = get_version_from_binary(version_bin).split("+")[-2]
        remove_file((version_bin))
    else:
        version = control.get_software_version()

    # Changing version of the package
    if Version(version, 4) > Version(control.get_software_version(), 4):
        print("Software version updated (from: %s to: %s)" % (control.get_software_version(), Version(version)))
        package_updated = True
    else:
        print("Software version up-to-date (%s)" % Version(version))
    control.set_software_version(version)
    control.save_control_to_wapt()

    # Validating update-package-sources
    return package_updated

    # # Changing version of the package and validating update-package-sources
    # return complete_control_version(control, version)
control

Code: Select all

package           : xxx-3cx-msix
version           : 20.0.751.0-3
architecture      : x64
section           : base
priority          : optional
name              : 3CX
categories        : Office
maintainer        : xxx
description       : 3CX is a unified communications application that allows users to manage their calls, messages and meetings
depends           :
conflicts         :
maturity          : PROD
locale            : all
target_os         : windows
min_wapt_version  : 2.3
sources           : https://downloads-global.3cx.com/downloads/3cxsoftphone/3CX.msix
installed_size    : 271764868
impacted_process  : 3CXSoftphone
description_fr    : 3CX est une application de communication unifiée permettant aux utilisateurs de gérer leurs appels, leurs messages et leurs réunions
description_pl    : 3CX to aplikacja do ujednoliconej komunikacji, która pozwala użytkownikom zarządzać połączeniami, wiadomościami i spotkaniami
description_de    : 3CX ist eine Unified-Communications-Anwendung, mit der Benutzer ihre Anrufe, Nachrichten und Besprechungen verwalten können
description_es    : 3CX es una aplicación de comunicaciones unificadas que permite a los usuarios gestionar sus llamadas, mensajes y reuniones
description_pt    : A 3CX é uma aplicação de comunicações unificadas que permite aos utilizadores gerir as suas chamadas, mensagens e reuniões
description_it    : 3CX è un'applicazione per le comunicazioni unificate che consente agli utenti di gestire chiamate, messaggi e riunioni
description_nl    : 3CX is een toepassing voor Unified Communications waarmee gebruikers hun gesprekken, berichten en vergaderingen kunnen beheren
description_ru    : 3CX - это приложение для унифицированных коммуникаций, которое позволяет пользователям управлять своими звонками, сообщениями и встречами
audit_schedule    :
editor            : 3CX Software DMCC
keywords          : collaboration,meetings,video
licence           : proprietary_free,wapt_public
homepage          : https://www.3cx.com/
package_uuid      : 628a2ed4-e0b3-4e80-8fc6-87788d9a07b3
valid_from        :
valid_until       :
forced_install_on :
changelog         : https://www.3cx.com/blog/change-log/windows-app/
smandel
Messages: 111
Registration: May 5, 2022 - 11:30

April 4, 2025 - 11:34

And don't forget to deploy these registry keys on the workstations or via GPO to avoid errors during package installation:

Code: Select all

[HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\Appx]
"AllowDevelopmentWithoutDevLicense"=dword:00000001
"AllowAllTrustedApps"=dword:00000001
Answer