tis-quickassist
2024.806.1625.0-57
Help family and friends with their PC or get help from them using Quick Assist. Use a remote connection to view their screen or request full control during a session, make annotations, use a laser pointer, and more to help fix PC problems
2831 downloads
See build result See VirusTotal scan
Description
- package : tis-quickassist
- name : Quick Assist
- version : 2024.806.1625.0-57
- categories : System and network
- maintainer : WAPT Team,Tranquil IT,Jimmy PELÉ,Pierre COSSON
- installed_size : 3703063
- editor : Microsoft
- licence : Proprietary
- signature_date : 2024-08-24T18:00:13.142787
- size : 34.95 Mo
- locale : all
- target_os : windows
- impacted_process : QuickAssist
- architecture : all
- Homepage : https://insider.office.com/fr/blog/remote-assistance-with-quick-assist-is-changing
- Depends :
control
package : tis-quickassist
version : 2024.806.1625.0-57
architecture : all
section : base
priority : optional
name : Quick Assist
categories : System and network
maintainer : WAPT Team,Tranquil IT,Jimmy PELÉ,Pierre COSSON
description : Help family and friends with their PC or get help from them using Quick Assist. Use a remote connection to view their screen or request full control during a session, make annotations, use a laser pointer, and more to help fix PC problems
depends : tis-webview2
conflicts :
maturity : PROD
locale : all
target_os : windows
min_wapt_version : 2.3
sources : https://apps.microsoft.com/store/detail/9P7BP5VNWKX5
installed_size : 3703063
impacted_process : QuickAssist
description_fr : Aidez vos proches à utiliser leur PC ou demandez-leur de l'aide grâce à l'Assistance rapide. Utilisez une connexion à distance pour afficher leur écran ou demander un contrôle total au cours d'une session, effectuer des annotations, utiliser un pointeur laser, et bien plus encore pour aider à résoudre les problèmes de PC
description_pl : Pomóż rodzinie i znajomym z ich komputerem lub uzyskaj od nich pomoc za pomocą Quick Assist. Użyj zdalnego połączenia, aby wyświetlić ich ekran lub poprosić o pełną kontrolę podczas sesji, tworzyć adnotacje, używać wskaźnika laserowego i nie tylko, aby pomóc w rozwiązywaniu problemów z komputerem
description_de : Helfen Sie Familie und Freunden mit ihrem PC oder lassen Sie sich von ihnen mit Quick Assist helfen. Verwenden Sie eine Fernverbindung, um den Bildschirm zu sehen oder die volle Kontrolle während einer Sitzung anzufordern, machen Sie Anmerkungen, verwenden Sie einen Laserpointer und vieles mehr, um PC-Probleme zu beheben
description_es : Ayude a sus familiares y amigos con su PC u obtenga ayuda de ellos utilizando Quick Assist. Utilice una conexión remota para ver su pantalla o solicitar el control total durante una sesión, hacer anotaciones, utilizar un puntero láser, y más para ayudar a solucionar problemas de PC
description_pt : Ajude familiares e amigos com o seu PC ou obtenha ajuda deles utilizando o Quick Assist. Utilize uma ligação remota para ver o ecrã ou solicite o controlo total durante uma sessão, faça anotações, utilize um ponteiro laser e muito mais para ajudar a resolver problemas do PC
description_it : Aiutate familiari e amici con il loro PC o fatevi aiutare da loro con Quick Assist. Utilizzate una connessione remota per visualizzare lo schermo o richiedere il controllo completo durante una sessione, fate annotazioni, usate un puntatore laser e altro ancora per risolvere i problemi del PC
description_nl : Help familie en vrienden met hun pc of krijg hulp van hen met Quick Assist. Gebruik een verbinding op afstand om hun scherm te bekijken of vraag om volledige controle tijdens een sessie, maak aantekeningen, gebruik een laseraanwijzer en meer om pc-problemen te helpen oplossen
description_ru : Помогайте родным и друзьям в работе с ПК или получайте помощь от них с помощью Quick Assist. Используйте удаленное подключение для просмотра их экрана или запрашивайте полный контроль во время сеанса, делайте аннотации, используйте лазерную указку и многое другое, чтобы помочь устранить проблемы с ПК
audit_schedule :
editor : Microsoft
keywords :
licence : Proprietary
homepage : https://insider.office.com/fr/blog/remote-assistance-with-quick-assist-is-changing
package_uuid : fc160dee-55fe-474d-8484-54397b6111df
valid_from :
valid_until :
forced_install_on :
changelog :
min_os_version : 10.0.17763
max_os_version :
icon_sha256sum : 6a095eca1edd81c0b31c28a35896ad188b2effd12912773f1e79abde58217659
signer : Tranquil IT
signer_fingerprint: 8c5127a75392be9cc9afd0dbae1222a673072c308c14d88ab246e23832e8c6bb
signature : W7o9FUtC6xfTX/zcM9WcmS4xPFWCjti0jHHeFC6nAma1bk0f4KQj6n8jBBOSPMt0zlsfFTqMgP2a8Q+BWmm8ryhpk0U5l2/5mkuKrMK9eLT6FBZHh70FosOJ/g1d3p8E1YDG+KSsi1iO5wRiIQJpwGj+i1tGcYRZQeoRgdW/v6QHiOm0iETNHKUW84VsDQeGn1UJMZ4/mksbT3IL0MAP1bUEVx8CPhuayhy9/mWguoRsrbvxPgQf3DRF61ha2b7rbstC+Ada8j294wMWqdOxUmudeLWnqnyCkiujaFaccXqEkqfbfHOHeODT0gO6lASui5yZh7g1TfhFVxSKX8eW1g==
signature_date : 2024-08-24T18:00:13.142787
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
Setup.py
# -*- coding: utf-8 -*-
from setuphelpers import *
appx_package_name = "MicrosoftCorporationII.QuickAssist"
appx_dir = makepath(programfiles, "WindowsAppsInstallers")
def install():
# Declare local variables
bins_dir = control.package.split("-", 1)[1]
old_appx_bins_dir = makepath(appx_dir, bins_dir)
appx_bins_dir = makepath(os.getcwd(), bins_dir)
# Removing sources because they are no longer needed
if isdir(old_appx_bins_dir):
print("Removing: %s" % (old_appx_bins_dir))
remove_tree(old_appx_bins_dir)
if dir_is_empty(appx_dir):
print("Removing: %s since it is empty" % (appx_dir))
remove_tree(appx_dir)
# Removing binaries of different architectures
for f in glob.glob(appx_bins_dir + "/*"):
fname = f.split(os.sep)[-1]
if control.architecture == "all":
if "x86" in glob.glob(makepath(appx_bins_dir, f"{appx_package_name}_*"))[0].split(os.sep)[-1]:
if not "x86" in fname and not "neutral" in fname:
remove_file(f)
else:
if not get_host_architecture() in fname and not "neutral" in fname:
remove_file(f)
else:
if not get_host_architecture() in fname and not "neutral" in fname:
remove_file(f)
bin_path = glob.glob(makepath(appx_bins_dir, f"{appx_package_name}_*"))[0]
dependencies_pathes = ",".join([f'"{a}"' for a in glob.glob(makepath(appx_bins_dir, "*")) if not appx_package_name in a])
add_appx_cmd = f'Add-AppxProvisionedPackage -Online -PackagePath "{bin_path}" -SkipLicense'
if dependencies_pathes:
add_appx_cmd += f" -DependencyPackagePath {dependencies_pathes}"
# Installing the UWP application if needed
appxprovisionedpackage = run_powershell(f'Get-AppXProvisionedPackage -Online | Where-Object DisplayName -Like "{appx_package_name}"')
if appxprovisionedpackage is None:
appxprovisionedpackage = {"Version": "0"}
if Version(appxprovisionedpackage["Version"], 4) < Version(control.get_software_version(), 4) or force:
print(f"Installing: {bin_path.split(os.sep)[-1]}")
killalltasks(ensure_list(control.impacted_process))
run_powershell(add_appx_cmd, output_format="text")
else:
print(f'{appxprovisionedpackage["PackageName"]} is already installed and up-to-date.')
def uninstall():
# Declare local variables
bins_dir = control.package.split("-", 1)[1]
appx_bins_dir = makepath(appx_dir, bins_dir)
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.
.. versionadded:: 2.2
.. versionchanged:: 2.5
No longer try to remove NonRemovable AppX package
"""
if running_as_admin() or running_as_system():
if default_user:
run_powershell(
f'Get-AppXProvisionedPackage -Online | Where-Object DisplayName -Like "{package}" | Remove-AppxProvisionedPackage -Online -AllUsers',
output_format="text",
)
run_powershell(
r'Get-AppxPackage -Name "%s" -AllUsers | Where-Object {{ -not ($_.NonRemovable) }} | Remove-AppxPackage -AllUsers' % package,
output_format="text",
)
else:
run_powershell(r'Get-AppxPackage -Name "%s" | Where-Object {{ -not ($_.NonRemovable) }} | Remove-AppxPackage' % package, output_format="text")
update_package.py
# -*- coding: utf-8 -*-
from setuphelpers import *
import requests
import re
import json
import os
import sys
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()
microsoft_store_url = control.sources
if not microsoft_store_url:
store_id = ask_input(
control.package,
"Enter the application ProductId or the link from the Microsoft Store (web address: https://apps.microsoft.com/store/apps)",
microsoft_store_url,
raise_error=True,
).split("/")[-1]
else:
store_id = microsoft_store_url.split("/")[-1]
store_id = store_id.split("?")[0].split("#")[0].upper()
if store_id:
microsoft_store_url = "https://apps.microsoft.com/store/detail/%s" % store_id
control.sources = microsoft_store_url
control.save_control_to_wapt()
package_prefix = control.package.split("-")[0]
selected = None
# check setup.py incase the package name does not match the installer file
appx_package_name = ""
with open("setup.py", "r", encoding="utf8") as f:
for line in f.readlines():
if line.startswith("appx_package_name"):
appx_package_name = line.split("=")[1].split('"')[1]
break
old_appx_package_name = appx_package_name
# Getting info from adguard api
res = requests.post(
"https://store.rg-adguard.net/api/GetFiles",
"type=ProductId&url=%s&ring=RP&lang=fr-FR" % store_id,
headers={"content-type": "application/x-www-form-urlencoded"},
proxies=proxies,
)
all_files = []
for bs_search in bs_find_all(res.text, "a"):
if not "BlockMap" in bs_search.text and not "eappxbundle" in bs_search.text and not "emsixbundle" in bs_search.text:
# bin_name = bs_search.text.replace("~", "_")
bin_name = str(bs_search.text)
if not get_file_extension(bin_name):
continue
version = bin_name.split("_")[1]
download_url = bs_search["href"]
pkg_splitted = re.split(r"_\d+\.", bin_name)[0]
package_name = package_prefix + "-" + pkg_splitted.split("_")[0].replace(".", "-").lower()
software_name = bin_name.split("_")[0].replace("-", " ").replace(".", " ")
package_arch = get_uwp_filename_arch(bin_name, appx_package_name)
file_dict = {
"version": version,
"bin_name": bin_name,
"package_name": package_name,
"software_name": software_name,
"package_arch": package_arch,
"download_url": download_url,
}
all_files.append(file_dict)
if (
"template-microsoft-store" in control.package
or not appx_package_name
or not len([a for a in all_files if appx_package_name in a["bin_name"]]) != 0
):
if not all_files:
error(f"API returned an empty list for URL: {microsoft_store_url}, please try again")
selected = ask_grid(
"Please select the App version that you want to package",
all_files,
"GRT_SELECTED",
'{"columns":[{"propertyname":"version","datatype":"String","required":false,"readonly":false,"width":130},{"propertyname":"bin_name","datatype":"String","required":false,"readonly":false,"width":420},{"propertyname":"package_name","datatype":"String","required":false,"readonly":false,"width":190},{"propertyname":"software_name","datatype":"String","required":false,"readonly":false,"width":172},{"propertyname":"package_arch","datatype":"String","required":false,"readonly":false,"width":88},{"propertyname":"download_url","datatype":"String","required":false,"readonly":false,"width":1472}]}',
)
appx_package_name = selected[0]["bin_name"].split("_")[0]
# Avoiding downloads loop and avoid keeping sources of other apps
bins_dir = control.package.split("-", 1)[1]
for dir_name in glob.glob("**/"):
dir_name = dir_name.split(os.sep)[0]
if dir_name in ["WAPT", "__pycache__"]:
continue
if dir_name == bins_dir:
for f in (
glob.glob(f"{dir_name}/*.appxbundle")
+ glob.glob(f"{dir_name}/*.msixbundle")
+ glob.glob(f"{dir_name}/*.appx")
+ glob.glob(f"{dir_name}/*.msix")
):
shutil.move(f, ".")
else:
remove_tree(dir_name)
if isfile("package.json"):
remove_file("package.json")
# Updating package.json ignored_versions list
if isfile("package.json"):
package_json = json_load_file("package.json")
else:
package_json = {"version_prefix": None, "ignored_versions": []}
if selected:
ignored_versions = list(
set(
package_json["ignored_versions"]
+ [v["version"] for v in all_files if appx_package_name in v["bin_name"] and v["version"] != selected[0]["version"]]
)
)
ignored_versions.sort()
package_json["ignored_versions"] = ignored_versions
json_write_file("package.json", package_json)
else:
ignored_versions = package_json["ignored_versions"]
version_prefix = package_json.get("version_prefix", None)
# Downloading app files
download_app_files(all_files, appx_package_name, proxies=proxies, ignored_versions=ignored_versions, version_prefix=version_prefix)
# # Import xmltodict for make_uwp_app_dict()
# if not isfile("xmltodict.py"):
# pip_download_xmltodict = "waptpython -m pip download xmltodict -d %s" % basedir
# if proxies:
# pip_download_xmltodict += " --proxy %s" % proxies["http"]
# run(pip_download_xmltodict)
# unzip(glob.glob("*.whl")[0], ".", "xmltodict.py")
# remove_file(glob.glob("*.whl")[0])
# Keep app files
uwp_app_dict = make_uwp_app_dict(appx_package_name)
newer_uwp_app = get_newer_uwp_app(uwp_app_dict, tdf_list=None)
version = newer_uwp_app["Version"]
# Downloading dependency files
dependencies_to_download = []
if newer_uwp_app["Dependencies"]:
for dependency in newer_uwp_app["Dependencies"]:
dependencies_to_download.append(get_newer_uwp_depency(dependency, all_files, min_version=dependency["MinVersion"]))
if dependencies_to_download:
for dependency_file in all_files:
latest_bin = dependency_file["bin_name"]
if not True in [d in latest_bin for d in dependencies_to_download]: # ignore unecessary dependencies
continue
if not "all" in ensure_list(control.architecture):
if not get_uwp_filename_arch(latest_bin) in ensure_list(control.architecture) and not "neutral" in latest_bin:
if isfile(latest_bin):
remove_file(latest_bin)
continue
if latest_bin.split(".")[-1].lower().startswith("e"): # ignore encrypted uwp apps
continue
download_url = dependency_file["download_url"]
if download_url.split("/")[2].endswith("microsoft.com"):
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)
else:
error("ERROR: The retrieved URL will not download from microsoft's servers")
# Applying or asking control informations once
if not old_appx_package_name or old_appx_package_name != appx_package_name:
# control.impacted_process and control.installed_size
if newer_uwp_app.get("b4:Dependencies", None):
appx_file = sorted(newer_uwp_app["b4:Dependencies"], key=lambda arch: ["x64", "x86", "arm64", "arm"].index(arch.get("Architecture")))[0][
"FileName"
]
appx_dir = appx_file.rsplit(".", 1)[0]
unzip(newer_uwp_app["FileName"], ".", appx_file)
unzip(appx_file)
else:
appx_dir = newer_uwp_app["FileName"].rsplit(".", 1)[0]
unzip(newer_uwp_app["FileName"])
complete_control_impacted_process(control, appx_dir)
control.installed_size = get_size(appx_dir)
if isdir(appx_dir):
remove_tree(appx_dir)
# No dependencies since it will be contained
control.depends = ""
control.save_control_to_wapt()
# control.architecture
control.architecture = get_uwp_architectures(newer_uwp_app)
if "," in control.architecture:
complete_control_min_wapt_version(control, "2.4", True)
# control.min_os_version and control.max_os_version
set_control_os_version_uwp_app(newer_uwp_app)
# control.name
bs_name = bs_find(microsoft_store_url + "?gl=US&hl=en-US", "meta", "property", "og:title", allow_redirects=True)["content"]
control_name = bs_name.split("Get ")[-1].split(" from the Microsoft Store")[0]
control_name = complete_control_name(control, control_name)
# control.package
control_package = package_prefix + "-" + control_name.lower()
complete_control_package(control, control_package, params.get("running_as_luti"))
# control.description
control_description = bs_find(microsoft_store_url + "?gl=US&hl=en-US", "meta", "property", "og:description", allow_redirects=True)["content"]
complete_control_description(control, control_description, params.get("running_as_luti"), "update_package", 250)
# control.description_fr = bs_find(microsoft_store_url + "?gl=FR&hl=fr-FR", "meta", "property", "og:description", allow_redirects=True)["content"]
# control.categories
complete_control_categories(control)
# Updating setup.py appx_package_name variable
new_lines = []
with open("setup.py", "r", encoding="utf8") as f:
for line in f.readlines():
if line.startswith("appx_package_name"):
line = 'appx_package_name = "%s"\n' % appx_package_name
new_lines.append(line)
with open("setup.py", "w", encoding="utf8", newline="\n") as f:
f.writelines(new_lines)
# Get icon.png
icon_png = []
if "b4:Dependencies" in newer_uwp_app:
if newer_uwp_app["b4:Dependencies"]:
temp_appx = unzip(newer_uwp_app["FileName"], ".", newer_uwp_app["b4:Dependencies"][0]["FileName"], False)
icon_png = unzip(newer_uwp_app["b4:Dependencies"][0]["FileName"], ".", "*.targetsize-48_altform-unplated.png", False)
if not icon_png:
icon_png = unzip(newer_uwp_app["b4:Dependencies"][0]["FileName"], ".", "*.targetsize-48.png", False)
if not icon_png:
icon_png = unzip(newer_uwp_app["b4:Dependencies"][0]["FileName"], ".", "**/PkgSmallLogo.png", False)
if icon_png:
shutil.move(icon_png[0], "WAPT\\icon.png")
for f in temp_appx:
if isfile(f):
remove_file(f)
if not icon_png:
icon_png = unzip(newer_uwp_app["FileName"], ".", "*.targetsize-48_altform-unplated.png", False)
if not icon_png:
icon_png = unzip(newer_uwp_app["FileName"], ".", "*.targetsize-48.png", False)
if icon_png:
shutil.move(icon_png[0], "WAPT\\icon.png")
[remove_file(a) for a in glob.glob("*.png")]
# Placing binaries in a dir ["appxbundle", "msixbundle", "appx", "msix]
for f in glob.glob("*.part"):
remove_file(f)
bins_dir = control.package.split("-", 1)[1]
if isdir(bins_dir):
remove_tree(bins_dir)
mkdirs(bins_dir)
for uwp_file in glob.glob(f'{newer_uwp_app["Name"]}*{newer_uwp_app["Version"]}*.*'):
if not isfile(makepath(bins_dir, uwp_file)):
shutil.move(uwp_file, bins_dir)
if uwp_app_dict[newer_uwp_app["FileName"]]["Dependencies"] is not None:
for l in [glob.glob(a["Name"] + "_*") for a in uwp_app_dict[newer_uwp_app["FileName"]]["Dependencies"]]:
for f in l:
if not isfile(makepath(bins_dir, f)):
shutil.move(f, bins_dir)
# Removing remaining files ["appxbundle", "msixbundle", "appx", "msix]
for f in glob.glob("*.appxbundle") + glob.glob("*.msixbundle") + glob.glob("*.appx") + glob.glob("*.msix"):
remove_file(f)
# Changing version of the package and validating update-package-sources
return complete_control_version(control, version)
def json_write_file(json_file, data, indent=4, sort_keys=False, encoding="utf-8", newline="\n"):
"""
Write dictionary to a JSON file.
Args:
json_file (str): Path to the JSON file.
data (dict): Dictionary content.
indent (int or str): Tabulation size for indentation; default: 4 spaces.
sort_keys (bool): Sort the keys alphabetically or not; default: False.
encoding (str): File encoding; default: 'utf-8'.
newline (str): Newline character(s) to use; default: 'LF'.
"""
with open(json_file, "w", encoding=encoding, newline=newline) as write_file:
json.dump(data, write_file, sort_keys=sort_keys, indent=indent)
def download_app_files(all_files, appx_package_name, proxies=None, ignored_versions=[], version_prefix=None):
for app_file in all_files:
latest_bin = app_file["bin_name"]
if not latest_bin.startswith(f"{appx_package_name}_"): # ignore other files
continue
if latest_bin.split(".")[-1].lower().startswith("e"): # ignore encrypted UWP apps
continue
if version_prefix is not None and not Version(app_file["version"], len(version_prefix.split("."))) == Version(
version_prefix, len(version_prefix.split("."))
):
continue
if any(
Version(app_file["version"], len(ignored_version.split("."))) == Version(ignored_version, len(ignored_version.split(".")))
for ignored_version in ignored_versions
):
continue
download_url = app_file["download_url"]
if download_url.split("/")[2].endswith("microsoft.com"):
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)
else:
error("ERROR: The retrieved URL will not download from Microsoft's servers")
def get_uwp_architectures(newer_uwp_app):
"""
Returns a comma-separated string of compatible architectures extracted from the 'control.architecture'
within the provided 'newer_uwp_app' dictionary.
Args:
newer_uwp_app (dict): A dictionary representing a Universal Windows Platform (UWP) app.
Returns:
str: A comma-separated string of compatible architectures (e.g., "x64,arm64,x86,arm"). If no
compatible architectures are found, it returns "all".
"""
architecture_list = []
desired_order = ["x64", "x86", "arm64", "arm"]
if newer_uwp_app.get("b4:Dependencies", None):
for before_dependency in newer_uwp_app.get("b4:Dependencies"):
architecture_list.append(before_dependency["Architecture"])
sorted_architecture_list = sorted(architecture_list, key=lambda arch: desired_order.index(arch))
control_architecture = ",".join(sorted_architecture_list)
if control_architecture.startswith("x64,x86"):
control_architecture = "all"
return control_architecture
else:
return get_uwp_filename_arch(newer_uwp_app["FileName"], newer_uwp_app["Name"])
def get_uwp_filename_arch(appx_filename, appx_package_name=None):
"""
Returns the architecture of a Universal Windows Platform (UWP) app based on the provided 'appx_filename'
and optionally, the 'appx_package_name'.
Args:
appx_filename (str): The filename of the UWP app package.
appx_package_name (str, optional): The package name of the UWP app. Defaults to None.
Returns:
str: The architecture of the UWP app, which can be "x64", "arm64", "x86", or "all" (if no specific
architecture is detected).
"""
if not appx_package_name:
appx_package_name = None
if len(glob.glob(f'{appx_package_name}*{appx_filename.split("_")[1]}*')) > 1:
pass
elif "arm64" in appx_filename:
return "arm64"
elif "arm" in appx_filename:
return "arm"
elif "x64" in appx_filename:
return "x64"
if appx_filename is not None and "x86" in appx_filename and (appx_package_name is None or not appx_package_name in appx_filename):
return "x86"
return "all"
def get_newer_uwp_app(uwp_app_dict, version_prefix=None, min_version=None, max_version=None, tdf_list=["Windows.Universal", "Windows.Desktop"]):
"""Get the newer Universal Windows Platform (UWP) app from a dictionary of UWP apps based on specified criteria.
Args:
uwp_app_dict (dict): A dictionary containing UWP app information with app IDs as keys and app details as values.
version_prefix (str, optional): The prefix of the version number to filter the apps. Defaults to None.
min_version (str, optional): The minimum version of the UWP app. Defaults to None.
max_version (str, optional): The maximum version of the UWP app. Defaults to None.
tdf_list (list, optional): A list of target device families to filter the apps. Defaults to ["Windows.Universal", "Windows.Desktop"].
Returns:
dict or None: The dictionary containing the details of the newer UWP app that matches the specified criteria, or None if no app is found.
"""
newer_version = "0"
for uwp_app in uwp_app_dict.values():
to_skip = True
if version_prefix is not None and Version(uwp_app["Version"], len(version_prefix.split("."))) != Version(
version_prefix, len(version_prefix.split("."))
):
continue
if tdf_list is not None and uwp_app["TargetDeviceFamily"] is not None:
if not uwp_app["TargetDeviceFamily"]:
continue
for tdf in tdf_list:
for uwp_app_tdf in uwp_app["TargetDeviceFamily"]:
if (
tdf == uwp_app_tdf["Name"]
and (min_version is None or Version(min_version, 3) == Version(uwp_app_tdf["MinVersion"], 3))
and (max_version is None or Version(max_version, 3) == Version(uwp_app_tdf["MaxVersionTested"], 3))
):
to_skip = False
else:
to_skip = False
if to_skip:
continue
if control.max_os_version:
if not Version(uwp_app["MinVersion"], 3) < Version(control.max_os_version, 3):
continue
if Version(newer_version) < Version(uwp_app["Version"]):
newer_uwp_app = uwp_app
newer_version = newer_uwp_app["Version"]
return newer_uwp_app
def get_newer_uwp_depency(dependency_dict, all_files_dict, version_prefix=None, min_version=None):
"""Returns a list of the bin_name of the latest required dependencies"""
newer_version = "0"
for uwp_app in all_files_dict:
if not uwp_app["bin_name"].startswith(f'{dependency_dict["Name"]}_'):
continue
if version_prefix is not None and Version(uwp_app["version"], len(version_prefix.split("."))) != Version(
version_prefix, len(version_prefix.split("."))
):
continue
if Version(newer_version) < Version(uwp_app["version"]):
newer_uwp_depency = uwp_app
newer_version = uwp_app["version"]
return newer_uwp_depency["bin_name"].split(newer_version + "_")[0] + newer_version + "_"
def make_uwp_app_dict(appx_package_name):
import xmltodict
ms_app_db = {}
# for ms_app_file in (
# glob.glob("*.appxbundle")
# + glob.glob("*.msixbundle")
# + glob.glob("*.appx")
# + glob.glob("*.msix")
# ):
for ms_app_file in (
glob.glob(f"{appx_package_name}*.appxbundle")
+ glob.glob(f"{appx_package_name}*.msixbundle")
+ glob.glob(f"{appx_package_name}*.appx")
+ glob.glob(f"{appx_package_name}*.msix")
):
data_dict = {}
before_dependencies = []
sub_dependencies = []
dependency_data_dict = None
manifest = unzip(ms_app_file, ".", "AppxManifest.xml", False)
bundle_manifest = unzip(ms_app_file, ".", "AppxMetadata\\AppxBundleManifest.xml", False)
ms_app_info = {
"FileName": ms_app_file,
}
if not manifest:
if bundle_manifest:
with open(bundle_manifest[0], encoding="utf8") as xml_file:
data_dict = xmltodict.parse(xml_file.read(), attr_prefix="")
if type(data_dict["Bundle"]["Packages"]["Package"]) == dict:
data_dict["Bundle"]["Packages"]["Package"] = [dict(data_dict["Bundle"]["Packages"]["Package"])]
for app_pkg in list(data_dict["Bundle"]["Packages"]["Package"]):
if app_pkg["Type"] == "application":
before_dependency_info = {
"FileName": app_pkg["FileName"],
"Version": app_pkg["Version"],
"Architecture": app_pkg["Architecture"],
}
before_dependencies.append(before_dependency_info)
if before_dependencies:
for dependency in before_dependencies:
unzip(
ms_app_file,
".",
makepath(
dependency["FileName"],
),
False,
)
manifest = unzip(dependency["FileName"], ".", makepath("AppxManifest.xml"), False)
if isfile(dependency["FileName"]):
remove_file(dependency["FileName"])
with open(manifest[0], encoding="utf8") as xml_file:
dependency_data_dict = xmltodict.parse(xml_file.read(), attr_prefix="")
if dependency_data_dict["Package"].get("Dependencies"):
if dependency_data_dict["Package"]["Dependencies"].get("PackageDependency"):
sub_dependencies = list(dependency_data_dict["Package"]["Dependencies"]["PackageDependency"])
if type(dependency_data_dict["Package"]["Dependencies"]["PackageDependency"]) == dict:
sub_dependencies = [dict(dependency_data_dict["Package"]["Dependencies"]["PackageDependency"])]
if type(dependency_data_dict["Package"]["Dependencies"]["PackageDependency"]) == list:
sub_dependencies = dependency_data_dict["Package"]["Dependencies"]["PackageDependency"]
if dependency_data_dict["Package"]["Dependencies"].get("TargetDeviceFamily"):
if not "TargetDeviceFamily" in ms_app_info:
if type(dependency_data_dict["Package"]["Dependencies"]["TargetDeviceFamily"]) == dict:
ms_app_info["TargetDeviceFamily"] = [dict(dependency_data_dict["Package"]["Dependencies"]["TargetDeviceFamily"])]
if type(dependency_data_dict["Package"]["Dependencies"]["TargetDeviceFamily"]) == list:
ms_app_info["TargetDeviceFamily"] = dependency_data_dict["Package"]["Dependencies"]["TargetDeviceFamily"]
else:
error("nothing to parse")
else:
manifest = unzip(ms_app_file, ".", makepath("AppxManifest.xml"), False)
with open(manifest[0], encoding="utf8") as xml_file:
dependency_data_dict = xmltodict.parse(xml_file.read(), attr_prefix="")
if dependency_data_dict["Package"].get("Dependencies"):
if "PackageDependency" in dependency_data_dict["Package"]["Dependencies"]:
sub_dependencies = list(dependency_data_dict["Package"]["Dependencies"]["PackageDependency"])
if type(dependency_data_dict["Package"]["Dependencies"]["PackageDependency"]) == dict:
sub_dependencies = [dict(dependency_data_dict["Package"]["Dependencies"]["PackageDependency"])]
if type(dependency_data_dict["Package"]["Dependencies"]["PackageDependency"]) == list:
sub_dependencies = dependency_data_dict["Package"]["Dependencies"]["PackageDependency"]
if "TargetDeviceFamily" in dependency_data_dict["Package"]["Dependencies"]:
if not "TargetDeviceFamily" in ms_app_info:
if type(dependency_data_dict["Package"]["Dependencies"]["TargetDeviceFamily"]) == dict:
ms_app_info["TargetDeviceFamily"] = [dict(dependency_data_dict["Package"]["Dependencies"]["TargetDeviceFamily"])]
if type(dependency_data_dict["Package"]["Dependencies"]["TargetDeviceFamily"]) == list:
ms_app_info["TargetDeviceFamily"] = dependency_data_dict["Package"]["Dependencies"]["TargetDeviceFamily"]
else:
ms_app_info.update({"Dependencies": None})
if ms_app_info.get("TargetDeviceFamily"):
ms_app_info.update(
{
"MinVersion": ms_app_info["TargetDeviceFamily"][0]["MinVersion"],
"MaxVersionTested": ms_app_info["TargetDeviceFamily"][0]["MaxVersionTested"],
}
)
elif dependency_data_dict is not None and dependency_data_dict["Package"].get("Prerequisites"):
ms_app_info.update(
{
"MinVersion": dependency_data_dict["Package"]["Prerequisites"]["OSMinVersion"],
"MaxVersionTested": dependency_data_dict["Package"]["Prerequisites"]["OSMaxVersionTested"],
}
)
else:
ms_app_info.update({"TargetDeviceFamily": None})
if data_dict:
ms_app_info.update(data_dict["Bundle"]["Identity"])
else:
ms_app_info.update(dependency_data_dict["Package"]["Identity"])
if "ProcessorArchitecture" in ms_app_info:
ms_app_info.update({"Architecture": ms_app_info["ProcessorArchitecture"]})
if before_dependencies:
ms_app_info["b4:Dependencies"] = before_dependencies
else:
ms_app_info.update({"b4:Dependencies": None})
if sub_dependencies:
ms_app_info["Dependencies"] = sub_dependencies
else:
ms_app_info.update({"Dependencies": None})
ms_app_db[ms_app_file] = ms_app_info
for xml_file in glob.glob("AppxManifest.xml") + glob.glob("AppxBundleManifest.xml"):
remove_file(xml_file)
return ms_app_db
def set_control_os_version_uwp_app(
newer_uwp_app,
force_values=False,
priority_windows=WindowsVersions.Windows11,
eol_windows=WindowsVersions.Windows10v2004,
silent=False,
):
if newer_uwp_app.get("MinVersion") and newer_uwp_app.get("MaxVersionTested"):
control.min_os_version = ".".join(
newer_uwp_app["MinVersion"].split(".")[: 2 if ".".join(newer_uwp_app["MinVersion"].split(".")[:3]).endswith("0") else 3]
)
# MaxVersionTested value seems not reliable, now asking to change control.max_os_version
if not Version(newer_uwp_app["MaxVersionTested"], 3) <= eol_windows: # Ignore end-of-life Windows versions
if control.max_os_version != ".".join(newer_uwp_app["MaxVersionTested"].split(".")[:3]):
if force_values:
control.max_os_version = ".".join(newer_uwp_app["MaxVersionTested"].split(".")[:3])
else:
if not silent:
control_max_os_version = ask_input(
control.package,
f'INFO: You may wanna change "control.max_os_version" by "{".".join(newer_uwp_app["MaxVersionTested"].split(".")[:3])}" or "{newer_uwp_app["MaxVersionTested"]}"',
"",
raise_error=False,
)
if control_max_os_version or control_max_os_version == "":
control.max_os_version = control_max_os_version
else:
print(
f'INFO: You may wanna change "control.max_os_version" by "{".".join(newer_uwp_app["MaxVersionTested"].split(".")[:3])}"'
)
else:
if control.max_os_version != "":
if force_values:
control.max_os_version = ""
else:
if not silent:
control_max_os_version = ask_message(
control.package,
f'INFO: You may wanna erase "control.max_os_version : {control.max_os_version}"',
3 + 32,
raise_error=False,
)
if control_max_os_version == 6:
control.max_os_version = ""
control.save_control_to_wapt()
d757329ca5a04af89c4b4a5199cff2ec144f6e7dc1f18f78a0df740b3ad9237f : setup.py
eeea401680156134d23d517f57d30e48530059e9f7e63016c4f1629e18325cb0 : __pycache__/setupdevhelpers.cpython-38.pyc
af74ae98ae38b3ab980f506dce6ded95a1d0309b9fe2ce72d0c30b544b36af24 : __pycache__/xmltodict.cpython-38.pyc
df3d87926a1d9780b7a76e145c3eae17f58e825fd7a9c1b2017608929da0d86f : quickassist/Microsoft.VCLibs.140.00.UWPDesktop_14.0.33728.0_arm__8wekyb3d8bbwe.appx
077a3d1a5d0622bd3004dca85f5e192d6e98ec79b83d4aa06766759ea6c09c3d : quickassist/Microsoft.VCLibs.140.00.UWPDesktop_14.0.33728.0_x64__8wekyb3d8bbwe.appx
831118f2f5cac8e29284e4ecc23bf4236436ccc2ea4a7c225c4946f8cfd29dd3 : quickassist/Microsoft.VCLibs.140.00.UWPDesktop_14.0.33728.0_arm64__8wekyb3d8bbwe.appx
efc92adcc812674e266e42564787b380be0faba7c0b52968432beeabd6d5c775 : quickassist/MicrosoftCorporationII.QuickAssist_2024.806.1625.0_neutral_~_8wekyb3d8bbwe.appxbundle
596c7175c0b0fa27ed292a44f4681f687720a77e34e007bf6c403d1940e46005 : quickassist/Microsoft.VCLibs.140.00.UWPDesktop_14.0.33728.0_x86__8wekyb3d8bbwe.appx
b76b0817226a3659bf1ea8caa6e61a4ac17b535d4b89855aedd691a619d944a5 : update_package.py
27903ed717f85f26e2825a8ad66c92ca32f76abc3c2f5a1783bbe3de430b8409 : package.json
6a095eca1edd81c0b31c28a35896ad188b2effd12912773f1e79abde58217659 : WAPT/icon.png
a5a97261381e1d0ad46ee15916abec9c2631d0201f5cc50ceb0197a165a0bbbf : WAPT/certificate.crt
364e01205533a0c6907fb9e8a8f70353985ae81ead35b71aade9a4253184f847 : xmltodict.py
2468a123904bc2c2f62ea7c61641a90b4650b9148917a3424ed324b231901858 : setupdevhelpers.py
8fde476dd6c990f63afd714f59e90fd340b7e71f88ed28281a0e642404ad7d4e : luti.json
46a4311f1929c7f842dabf99d9d9f63142e20fa3d7de8be29a24158c2b8d9715 : WAPT/control