tis-microsoft-office-2021-standard icon

Office LTSC Standard 2021

Silent install package for Office LTSC Standard 2021

16.0.14334.20344-15
Office
Office

package           : tis-microsoft-office-2021-standard
version           : 16.0.14334.20344-15
architecture      : x64
section           : base
priority          : optional
name              : Office LTSC Standard 2021
categories        : Office
maintainer        : WAPT Team,Tranquil IT,Kévin Guérineau, Jimmy PELÉ,Clément Baziret
description       : Microsoft Office 2021 is a version of the Microsoft Office suite
depends           : 
conflicts         : tis-microsoft-access-2016-runtime,tis-microsoft-office-2016,tis-microsoft-office-2013,tis-microsoft-office-365-entreprise,tis-microsoft-office-2019-professional
maturity          : PROD
locale            : all
target_os         : windows
min_wapt_version  : 2.3
sources           : https://www.microsoft.com/download/details.aspx?id=49117
installed_size    : 2362231960
impacted_process  : EXCEL,GROOVE,MSACCESS,MSPUB,ONENOTE,OUTLOOK,POWERPNT,WINWORD
description_fr    : Microsoft Office 2021 est une version de la suite Microsoft Office
description_pl    : Microsoft Office 2021 to wersja pakietu biurowego Microsoft Office
description_de    : Microsoft Office 2021 ist eine Version der Microsoft Office-Suite
description_es    : Microsoft Office 2021 es una versión del paquete Microsoft Office
description_pt    : O Microsoft Office 2021 é uma versão do pacote Microsoft Office
description_it    : Microsoft Office 2021 è una versione della suite Microsoft Office
description_nl    : Microsoft Office 2021 is een versie van de Microsoft Office-suite
description_ru    : Microsoft Office 2021 - это версия пакета Microsoft Office
audit_schedule    : 
editor            : Microsoft
keywords          : microsoft,office,2021,version,suite
licence           : proprietary_restricted,wapt_public
homepage          : https://www.office.com/
package_uuid      : 49a97779-19d8-4d99-a7c2-679b236cdf43
valid_from        : 
valid_until       : 
forced_install_on : 
changelog         : 
min_os_version    : 10.0
max_os_version    : 
icon_sha256sum    : 2ac98141bf5b6777083f2bcbeab3ab034c01dff77718e108774575aaaa54a144
signer            : Tranquil IT
signer_fingerprint: 8c5127a75392be9cc9afd0dbae1222a673072c308c14d88ab246e23832e8c6bb
signature_date    : 2025-10-23T14:08:51.000000
signed_attributes : package,version,architecture,section,priority,name,categories,maintainer,description,depends,conflicts,maturity,locale,target_os,min_wapt_version,sources,installed_size,impacted_process,description_fr,description_pl,description_de,description_es,description_pt,description_it,description_nl,description_ru,audit_schedule,editor,keywords,licence,homepage,package_uuid,valid_from,valid_until,forced_install_on,changelog,min_os_version,max_os_version,icon_sha256sum,signer,signer_fingerprint,signature_date,signed_attributes
signature         : sE/v5Wm+jfE+MgYR8RLzOebJ1s3tfPGrxYFrTwp5Xuy3/fJU2g1bNR3EwXsC9ZmsXrZnXCKjLwb2sQSr5nnXDrgtQpVXxPnJUivlXK9CpH6rnZ2ZPNvHJertAyWHA9VND6c/KZPWMh7R7s5aRdr6FygToC5KaE2zrB+sGgkhmyWq9c4CNr+j1gKNSlqwoSCSPMrbPkAn51w8jfAlVSGX7jum+7fQmTVmtvs5LchLqmstn6VpIxfz7fZIXjQKPu4s6kPZI05B81EfImzYrrseQzYaB5OIPrHbhpF/wis+YzjNQKhSjQrNbP4xnCgZvcnSqwZ3mTYQvvNO723TomAwig==

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

"""
Ressources:
https://config.office.com/deploymentsettings
https://admx.help/?Category=Office2016&Policy=office16.Office.Microsoft.Policies.Windows::L_SCLCacheOverride
https://admx.help/?Category=Office2016&Policy=excel16.Office.Microsoft.Policies.Windows::L_SaveExcelfilesas

"""

app_uninstallkey = "Standard2021Volume - fr-fr"


def install():
    # Declaring local variables
    package_version = control.get_software_version()
    silentflags = "/configure configuration.xml"

    # uninstalling older versions of office if needed
    uninstall_mso2013_if_needed("Office15.STANDARD")
    uninstall_mso2016_if_needed("Office16.STANDARD")
    uninstall_other_office_edition(app_uninstallkey.split(" ")[0])

    # Installing the software
    install_exe_if_needed(
        "setup.exe",
        silentflags=silentflags,
        timeout=1200,
        accept_returncodes=[1641, 3010, 0],
        key=app_uninstallkey,
        min_version=package_version,
    )

    # TODO "setup.exe /customize configuration.xml if up-to-date"

    # Adding silent uninstall command
    quiet_uninstall = installed_softwares(uninstallkey=app_uninstallkey)[0]["uninstall_string"] + " DisplayLevel=False"
    if "OfficeClickToRun.exe" in quiet_uninstall:
        register_uninstall(
            uninstallkey=app_uninstallkey,
            quiet_uninstall_string=quiet_uninstall,
        )


def session_setup():
    print("Disabling: MSO telemetry")
    # https://admx.help/?Category=Office2016&Policy=office16.Office.Microsoft.Policies.Windows::L_OfficeOSMPreventedHostApplications
    registry_set(HKEY_CURRENT_USER, r"software\policies\microsoft\office\16.0\osm\preventedapplications", "wdsolution", 1)
    registry_set(HKEY_CURRENT_USER, r"software\policies\microsoft\office\16.0\osm\preventedapplications", "xlsolution", 1)
    registry_set(HKEY_CURRENT_USER, r"software\policies\microsoft\office\16.0\osm\preventedapplications", "pptsolution", 1)
    registry_set(HKEY_CURRENT_USER, r"software\policies\microsoft\office\16.0\osm\preventedapplications", "olksolution", 1)
    registry_set(HKEY_CURRENT_USER, r"software\policies\microsoft\office\16.0\osm\preventedapplications", "accesssolution", 1)
    registry_set(HKEY_CURRENT_USER, r"software\policies\microsoft\office\16.0\osm\preventedapplications", "projectsolution", 1)
    registry_set(HKEY_CURRENT_USER, r"software\policies\microsoft\office\16.0\osm\preventedapplications", "publishersolution", 1)
    registry_set(HKEY_CURRENT_USER, r"software\policies\microsoft\office\16.0\osm\preventedapplications", "visiosolution", 1)
    registry_set(HKEY_CURRENT_USER, r"software\policies\microsoft\office\16.0\osm\preventedapplications", "onenotesolution", 1)
    # https://admx.help/?Category=Office2016&Policy=office16.Office.Microsoft.Policies.Windows::L_OfficeOSMPreventedSolutionTypes
    registry_set(HKEY_CURRENT_USER, r"software\policies\microsoft\office\16.0\osm\preventedsolutiontypes", "documentfiles", 1)
    registry_set(HKEY_CURRENT_USER, r"software\policies\microsoft\office\16.0\osm\preventedsolutiontypes", "templatefiles", 1)
    registry_set(HKEY_CURRENT_USER, r"software\policies\microsoft\office\16.0\osm\preventedsolutiontypes", "comaddins", 1)
    registry_set(HKEY_CURRENT_USER, r"software\policies\microsoft\office\16.0\osm\preventedsolutiontypes", "appaddins", 1)
    registry_set(HKEY_CURRENT_USER, r"software\policies\microsoft\office\16.0\osm\preventedsolutiontypes", "agave", 1)
    # https://admx.help/?Category=Office2016&Policy=office16.Office.Microsoft.Policies.Windows::L_EnableLogging
    # registry_set(HKEY_CURRENT_USER, r"software\policies\microsoft\office\16.0\osm", "enablelogging", 0)
    registry_set(HKEY_CURRENT_USER, r"software\policies\microsoft\office\16.0\osm", "enableupload", 0)
    registry_set(HKEY_CURRENT_USER, r"software\policies\microsoft\office\16.0\osm", "enablefileobfuscation", 1)
    # # https://admx.help/?Category=Office2016&Policy=office16.Office.Microsoft.Policies.Windows::L_Onlinecontentoptions
    # registry_set(HKEY_CURRENT_USER, r"software\policies\microsoft\office\16.0\common\internet", "useonlinecontent", 0)
    # # https://admx.help/?Category=Office2016&Policy=office16.Office.Microsoft.Policies.Windows::L_ServiceLevelOptions
    # registry_set(HKEY_CURRENT_USER, r"software\policies\microsoft\office\16.0\common\internet", "serviceleveloptions", 0)


def uninstall_other_office_edition(edition_uninstallkey):
    # Initializing variables
    silent_uninstall_file_path = makepath(tempfile.gettempdir(), "remove_other_office.xml")
    uninstall_configuration_xml_content = r"""<Configuration>
    <Remove All="TRUE">
    </Remove>
    <Display Level="none" CompletionNotice="No" SuppressModal="Yes" AcceptEula="Yes" />
    <Setting Id="SETUP_REBOOT" Value="Never" />
    <Setting Id="REBOOT" Value="ReallySuppress"/>
</Configuration>
"""
    # Modify XML
    with open(silent_uninstall_file_path, "w") as xml_file:
        xml_file.write(uninstall_configuration_xml_content)

    # Uninstalling Office if needed
    for to_uninstall in installed_softwares():
        killalltasks(control.get_impacted_process_list())
        if ("OfficeClickToRun.exe" in to_uninstall["uninstall_string"]) and not (edition_uninstallkey in to_uninstall["key"]):
            print("Removing: %s (%s)" % (to_uninstall["name"], to_uninstall["version"]))
            app_uninstall_cmd = to_uninstall["uninstall_string"] + " DisplayLevel=False"
            run(app_uninstall_cmd)
            wait_uninstallkey_absent(to_uninstall["key"])


def uninstall_mso2016_if_needed(uninstallkey):
    # Initializing variables
    silent_uninstall_file_path = makepath(tempfile.gettempdir(), "remove_o2016.xml")
    uninstall_configuration_xml_content = r"""<Configuration>
    <Remove All="TRUE">
    </Remove>
    <Display Level="none" CompletionNotice="No" SuppressModal="Yes" AcceptEula="Yes" />
    <Setting Id="SETUP_REBOOT" Value="Never" />
    <Setting Id="REBOOT" Value="ReallySuppress"/>
</Configuration>
"""
    # Modify XML
    with open(silent_uninstall_file_path, "w") as xml_file:
        xml_file.write(uninstall_configuration_xml_content)

    # Uninstalling Office if needed
    for to_uninstall in installed_softwares(uninstallkey=uninstallkey):
        print("Removing: %s (%s)" % (to_uninstall["name"], to_uninstall["version"]))
        killalltasks(control.get_impacted_process_list())
        if "OfficeClickToRun.exe" in to_uninstall["uninstall_string"]:
            app_uninstall_cmd = to_uninstall["uninstall_string"] + " DisplayLevel=False"
            run(app_uninstall_cmd)
            wait_uninstallkey_absent(to_uninstall["key"])
        else:
            run(to_uninstall["uninstall_string"] + ' /config "%s"' % silent_uninstall_file_path)
            wait_uninstallkey_absent(to_uninstall["key"])


def uninstall_mso2013_if_needed(uninstallkey):
    # Initializing variables
    silent_uninstall_file_path = makepath(tempfile.gettempdir(), "remove_o2013.xml")
    uninstall_configuration_xml_content = r"""<Configuration>
    <Remove All="TRUE">
    </Remove>
    <Display Level="none" CompletionNotice="No" SuppressModal="Yes" AcceptEula="Yes" />
    <Setting Id="SETUP_REBOOT" Value="Never" />
    <Setting Id="REBOOT" Value="ReallySuppress"/>
</Configuration>
"""
    # Modify XML
    with open(silent_uninstall_file_path, "w") as xml_file:
        xml_file.write(uninstall_configuration_xml_content)

    # Uninstalling Office if needed
    for to_uninstall in installed_softwares(uninstallkey=uninstallkey):
        print("Removing: %s (%s)" % (to_uninstall["name"], to_uninstall["version"]))
        killalltasks(control.get_impacted_process_list())
        run(to_uninstall["uninstall_string"] + ' /config "%s"' % silent_uninstall_file_path)
        wait_uninstallkey_absent(to_uninstall["key"])

# -*- coding: utf-8 -*-
from setuphelpers import *
import waptguihelper
import webbrowser
import os
import sys

if "__file__" in locals():
    sys.path.insert(0, os.path.dirname(os.path.realpath(__file__)))
from setupdevhelpers import *


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

    # if not the first run it will use the last setup downloaded if you want to get an updated one you can remove setup.exe and relaunch the update package
    if not isfile("setup.exe") and not params.get("running_as_luti"):
        waptguihelper.message_dialog(
            "You browser will open",
            "Please download Office Deployment Tool by clicking the download button",
        )
        webbrowser.open("https://www.microsoft.com/download/details.aspx?id=49117")
        waptguihelper.message_dialog("Waiting for download", "Click OK when the download is complete", waptguihelper.ID_OK)
        # Copy to pkg
        latest_bin = waptguihelper.filename_dialog(
            "Please provide downloaded Office Deployment Tool to copy in this package",
            makepath(user_home_directory, "Downloads"),
            "",
            "EXE Files|*.exe",
        )

        # Extract Office Deployment Tool
        print("Copying: " + latest_bin)
        run(rf'"{latest_bin}" /extract:"{extract_path}" /quiet"')

        print("Extract Office Deployment Tool")
        filecopyto(".\\extract\\setup.exe", basedir)
        remove_file(latest_bin)
        if isdir("extract"):
            remove_tree("extract")

    elif params.get("running_as_luti"):
        user_agent =  'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:78.0) Gecko/20100101 Firefox/88.0'
        data = [ u for u in json.loads(wgets('https://www.microsoft.com/en-us/download/details.aspx?id=49117',user_agent=user_agent,proxies=proxies).split('<script>window.__DLCDetails__=',1)[1].split('</script>')[0])["dlcDetailsView"]['downloadFile'] if u['name'].endswith('.exe')][0]
        download_url = data['url']
        latest_bin = download_url.split("/")[-1]
        wget(download_url, latest_bin, proxies=proxies)

        # Extract Office Deployment Tool
        print("Copying: " + latest_bin)
        run(rf'"{latest_bin}" /extract:"{extract_path}" /quiet"')

        print("Extract Office Deployment Tool")
        filecopyto(".\\extract\\setup.exe", basedir)
        remove_file(latest_bin)
        if isdir("extract"):
            remove_tree("extract")

    # if not the first run it will use the last XML used if you want to get a new one you can remove configuration.xml and relaunch the update package
    if not isfile("configuration.xml"):
        waptguihelper.message_dialog(
            "Your browser will open",
            "Please complete your deployment settings with the online Office Customization Tool and download it by clicking Export.\nNote that you can go back anytime on the online tool to edit your configuration (by clicking Import)",
        )
        webbrowser.open("https://config.office.com/deploymentsettings")
        waptguihelper.message_dialog("Waiting for download", "Click OK when the XML is completed and downloaded", waptguihelper.ID_OK)
        xml_configuration = waptguihelper.filename_dialog(
            "Please select your XML configuration file", basedir, "configuration.xml", "XML Files|*.xml"
        )  # makepath(user_home_directory, "Downloads")
        if not isfile("configuration.xml"):
            filecopyto(
                xml_configuration,
                basedir + "\\configuration.xml",
            )

    # Asking to remove the last downloaded sources
    if isdir("Office"):
        if not params.get("running_as_luti"):
            response = ask_message(control.package, "Do you want to remove the last downloaded sources?", 35)
            if response == 6:
                print("Removing last sources folder downloaded")
                remove_tree("Office")
        else:
            print("Removing last sources folder downloaded")
            remove_tree("Office")
    else:
        # Download Office with XML configuration
        print("Downloading Office with XML configuration")
        if windows_version() >= WindowsVersions.Windows10:
            run("setup.exe /download configuration.xml", timeout=2400)  # DisplayLevel=Full # not working
        else:
            error("MSO setup.exe can no longer be run on this OS")

    # Getting version from source dir
    version = glob.glob("Office/Data/**/")[0].split(os.sep)[1]

    # 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()

    # Getting Product ID and Language ID from configuration.xml parsing file
    with open("configuration.xml", "r", encoding="utf8") as f:
        for line in f:
            if "OfficeClientEdition" in line:
                architecture = line.split('"')[1]
                print("OfficeClientEdition: %s" % architecture)
                if architecture == "64":
                    architecture = "x64"
                else:
                    architecture = "all"
            if "Product ID" in line:
                product_id = line.split('"')[1]
                print("Product ID: %s" % product_id)
            if "Language ID" in line:
                language_id = line.split('"')[1]
                print("Language ID: %s" % language_id)
                break

    if control.architecture != architecture:
        control.architecture = architecture
        control.save_control_to_wapt()

    # Asking pkg infos if needed
    if control.locale not in language_id and "-template" in control.package:
        control.locale = waptguihelper.input_dialog(control.package, "You may wanna change locale to: %s" % language_id.split("-")[0], "all")
        print("Changing locale to: %s in WAPT\\control" % control.locale)
        control.save_control_to_wapt()

    complete_control_categories(control)
    complete_control_name(control, control.name, params.get("running_as_luti"))
    complete_control_package(control, control.package, params.get("running_as_luti"), False)
    complete_control_description(control, control.description, params.get("running_as_luti"), "update_package")

    # changing uninstallkey:
    new_lines = []
    with open("setup.py", "r", encoding="utf8") as f:
        for line in f.readlines():
            if line.startswith("app_uninstallkey"):
                line = f'app_uninstallkey = "{product_id} - {language_id}"\n'
                print(f'uninstallkey in setup updated to app_uninstallkey = "{product_id} - {language_id}"\n')
            new_lines.append(line)
    with open("setup.py", "w", encoding="utf8", newline="\n") as f:
        f.writelines(new_lines)

    # Validating or not update-package-sources
    return package_updated

9771b0e4640be35c3cfa54e060e54b5b992362b5499500418c744017f4b617dc : Office/Data/16.0.14334.20344/i640.cab
a7267002150cf90b8b1c13cf7f165949a38b8a5bc5618135e3a368902ba0b283 : Office/Data/16.0.14334.20344/i640.cab.cat
752491d266ef5bf1bc457a5de805848f83677797149e9c5431b7db5ca29b7439 : Office/Data/16.0.14334.20344/i641036.cab
91015778e2b170f171c5830f3a94030525a3a9e8f2668ccebbe156e3186e187e : Office/Data/16.0.14334.20344/s640.cab
bd756b077cd7828688ea6ef1e772b24fe579c411cbd753c9f89496081a342b84 : Office/Data/16.0.14334.20344/s641036.cab
59421c2463bf58d55007b0f46b2322750c9383bbc9d2a17e68a8f0da638c9798 : Office/Data/16.0.14334.20344/sa640.cab
51d15198d4fa57ba5b1337172e727b4dae114c545465b526aadb60c766b4fefa : Office/Data/16.0.14334.20344/stream.x64.fr-fr.dat
2ef27cae484691edee9f1697649d5398d91b1c8439315d36d35e4c1c8f59405f : Office/Data/16.0.14334.20344/stream.x64.fr-fr.dat.cat
f7b882b14de2a92b21ad5b4c4badbbb3b59274eff04665b3dca192b3008b7e86 : Office/Data/16.0.14334.20344/stream.x64.x-none.arm64x.dat
c79a7dbe2b606944338bcf11240f56e5f5146cc9f9689963c07952bdcd29671d : Office/Data/16.0.14334.20344/stream.x64.x-none.arm64x.dat.cat
3062b2cb5a497d01f4b964a70dd667786f0eb4b5ef9f00a08d5c7ab7d5d68dff : Office/Data/16.0.14334.20344/stream.x64.x-none.dat
3ca198dbafe5a5551f8402ae1369074ff6d10aa85726e06546bfd98a30aaef26 : Office/Data/16.0.14334.20344/stream.x64.x-none.dat.cat
424e46611ac1f989a3ca90f51976b96cfd3fcc16b2b0c7dda8f8c4942dafaaf4 : Office/Data/v64.cab
424e46611ac1f989a3ca90f51976b96cfd3fcc16b2b0c7dda8f8c4942dafaaf4 : Office/Data/v64_16.0.14334.20344.cab
38d056ab130f7bf7c481c12636a4e9959de36561d3dfcbe54c6e3571bc0c1dc3 : WAPT/certificate.crt
536eacb24d69918d068531fdc4f3eab63fbe40ddd0991af53616c22f61edf9c7 : WAPT/control
2ac98141bf5b6777083f2bcbeab3ab034c01dff77718e108774575aaaa54a144 : WAPT/icon.png
2dde629629fc6edbb04f24cc5dc1ef550a9313399bb9dc75cb1181bf19d1b872 : configuration.xml
c484a1b90716d28a0d93f746a8c390bb92fe5d78ffae488861961f8be00761e3 : luti.json
ed26519c1db29f1cc16eb21a1d492b8b6d241c4d86fe2de127ef6854d21cf5ae : setup.exe
2aee81c583fd3ed7324e3d7606b78e502eeaf8c3dd9da0e215d8e5e5a53aadaa : setup.py
253f0ac3ab3e7dac7aa743a436b5f0cf5c85ec36c26125796490880642c6a82a : setupdevhelpers.py
06551c84bc512b415697d9d201e2d37a0af50694e02e117d2dbadc8c89e3e5a9 : update_package.py