[RESOLU] Paquet pour configurer un réseau Wifi sur Windows, Llinux et MacOS

Questions about WAPT Packaging / Requêtes et aides autour des paquets Wapt.
Règles du forum
Règles du forum communautaire
* English support on www.reddit.com/r/wapt
* Le support communautaire en français se fait sur ce forum
* Merci de préfixer le titre du topic par [RESOLU] s'il est résolu.
* Merci de ne pas modifier un topic qui est taggé [RESOLU]. Ouvrez un nouveau topic en référençant l'ancien
* Préciser version de WAPT installée, version complète ET numéro de build (2.2.1.11957 / 2.2.2.12337 / etc.) AINSI QUE l'édition Enterprise / Discovery
* Les versions 1.8.2 et antérieures ne sont plus maintenues. Les seules questions acceptées vis à vis de la version 1.8.2 sont liés à la mise à jour vers une version supportée (2.1, 2.2, etc.)
* Préciser OS du serveur (Linux / Windows) et version (Debian Buster/Bullseye - CentOS 7 - Windows Server 2012/2016/2019)
* Préciser OS de la machine d'administration/création des paquets et de la machine avec l'agent qui pose problème le cas échéant (Windows 7 / 10 / 11 / Debian 11 / etc.)
* Eviter de poser plusieurs questions lors de l'ouverture de topic, sinon il risque d'être ignorer. Si plusieurs sujet, ouvrir plusieurs topic, et de préférence les uns après les autres et pas tous en même temps (ie ne pas spammer le forum).
* Inclure directement les morceaux de code, les captures d'écran et autres images directement dans le post. Les liens vers les pastebin, les bitly et autres sites tierces seront systématiquement supprimés.
* Comme tout forum communautaire, le support est fait bénévolement par les membres. Si vous avez besoin d'un support commercial, vous pouvez contacter le service commercial Tranquil IT au 02.40.97.57.55
bastien30
Messages : 35
Inscription : 08 mars 2024 - 15:21

07 janv. 2026 - 13:09

Bonjour,

Voici un paquet permettant de configurer un réseau Wifi sur Windows (avec netsh), Linux (avec nmcli) et MacOS (avec networksetup).

Ca pourrait être largement amélioré, mais en l'état ça fonctionne sur mon parc :-)

setup.py :

Code : Tout sélectionner

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

# Wifi settings
wifi_ssid = r'MY-WIFI-NETWORK'
wifi_password = r'my-wifi-password'
hidden_ssid = False

# Globally enable verbose mode
all_verbose = False

def install():
    if platform.system() == 'Windows':
        set_wifi_profile_windows(ssid=wifi_ssid, password=wifi_password, hidden=hidden_ssid, verbose=all_verbose)
    elif platform.system() == 'Darwin':
        set_wifi_profile_macos(ssid=wifi_ssid, password=wifi_password, verbose=all_verbose)
    elif platform.system() == 'Linux':
        set_wifi_profile_linux(ssid=wifi_ssid, password=wifi_password, hidden=hidden_ssid, verbose=all_verbose)
    else:
        error('Operating System not supported !')

def uninstall():
    if platform.system() == 'Windows':
        remove_wifi_profile_windows(ssid=wifi_ssid, verbose=all_verbose)
    elif platform.system() == 'Darwin':
        remove_wifi_profile_macos(ssid=wifi_ssid, verbose=all_verbose)
    elif platform.system() == 'Linux':
        remove_wifi_profile_linux(ssid=wifi_ssid, verbose=all_verbose)
    else:
        error('Operating System not supported !')


#### MACOS WIFI FUNCTIONS

def set_wifi_profile_macos(ssid, password, verbose=False):
    r"""Configure and apply WIFI profile on MacOS using networksetup

    Args:
        ssid: network SSID to connect
        password: wifi pre-shared key
        verbose: if set to True, display commands used (default: False)
        
    Notes: 
      - networksetup does not care about hidden network, this method works in all cases
      - networksetup does not care about authentication and encryption modes, it always use the most secure option possible
      - the configured SSID will be set to connect automatically by default

    For more informations see https://www.hexnode.com/mobile-device-management/help/scripts-to-manage-wi-fi-network-settings-on-macos-devices/
    """
    # Remove existings profiles first
    remove_wifi_profile_macos(ssid, verbose=verbose)
    time.sleep(2)

    print(r'Creating or updating WLAN profile %s...' % ssid)
    cmd = r'sudo networksetup -setairportnetwork en0 %s %s' % (ssid, password)
    if verbose:
        print(r'Command used: %s' % cmd)
    run(cmd)

def remove_wifi_profile_macos(ssid, verbose=False):
    r"""Remove WIFI profile if exists on MacOS using networksetup

    Args:
        ssid: profile SSID to remove
        verbose: if set to True, display command used
    """
    print(r'Removing WLAN profile %s if exists...' % ssid)
    # Note: WIFI stay connected after removal but can't reconnect after reboot or disconnection
    cmd = r'sudo networksetup -removepreferredwirelessnetwork en0 %s ' % ssid
    if verbose:
        print(r'Command used: %s' % cmd)
    run_notfatal(cmd)


#### WINDOWS FUNCTIONS

def set_wifi_profile_windows(ssid, password, authentication_mode="WPA2PSK", encryption_mode="AES", connection_mode="auto", hidden=False, verbose=False):
    r"""Configure and apply WIFI profile on Windows using netsh

    Args:
        ssid: network SSID to connect
        password: wifi pre-shared key
        authentication_mode: authentication method to use for connection (default: WPA2PSK)
        encryption_mode: encryption type to use for connection (default: AES)
        connection_mode: wether to enable wifi automatic connection, can be 'auto' or 'manual' (default: auto)
        hidden: if set to True, configure a hidden network (default: False)
        verbose: if set to True, display generated XML and commands used (default: False)
        
    For more informations see https://learn.microsoft.com/fr-fr/uwp/schemas/mobilebroadbandschema/wlan/schema-root
    """
    import tempfile

    if connection_mode not in ("auto", "manuel"):
        error("Error: connection_mode can be 'auto' or 'manual' only !")
    
    xml_template = """<?xml version="1.0"?>
<WLANProfile xmlns="http://www.microsoft.com/networking/WLAN/profile/v1">
    <name>{tmpl_ssid}</name>
    <SSIDConfig>
        <SSID>
            <name>{tmpl_ssid}</name>
        </SSID>
        <nonBroadcast>{tmpl_hidden}</nonBroadcast>
    </SSIDConfig>
    <connectionType>ESS</connectionType>
    <connectionMode>{tmpl_connection_mode}</connectionMode>
    <MSM>
        <security>
            <authEncryption>
                <authentication>{tmpl_authentication_mode}</authentication>
                <encryption>{tmpl_encryption_mode}</encryption>
                <useOneX>false</useOneX>
            </authEncryption>
            <sharedKey>
                <keyType>passPhrase</keyType>
                <protected>false</protected>
                <keyMaterial>{tmpl_password}</keyMaterial>
            </sharedKey>
        </security>
    </MSM>
</WLANProfile>"""

    if hidden:
        hidden_value = r'true'
    else:
        hidden_value = r'false'

    # Replace variables in template
    xml_data = xml_template.format(
        tmpl_ssid = ssid,
        tmpl_hidden = hidden_value,
        tmpl_connection_mode = connection_mode,
        tmpl_authentication_mode = authentication_mode,
        tmpl_encryption_mode = encryption_mode,
        tmpl_password = password
    )

    # Remove existings profiles first
    remove_wifi_profile_windows(ssid, verbose=verbose)  
    time.sleep(2)

    # Use try/finally to ensure XML file is always deleted
    try:
        # Use temporary file
        with tempfile.NamedTemporaryFile(mode="w+", suffix=".xml", delete=False, encoding="utf-8") as tmpfile:
            tmpfile.write(xml_data)
            tmpfile.flush()  # force write on disk
            xml_file = tmpfile.name

            if verbose:
                tmpfile.seek(0)
                print("XML content:\n%s" % tmpfile.read())

        print(r'Creating or updating WLAN profile %s...' % ssid)
        cmd = r'netsh wlan add profile filename=%s user=all' % xml_file
        if verbose:
            print(r'Command used: %s' % cmd)
        run(cmd)
    finally:
        remove_file(xml_file)

def remove_wifi_profile_windows(ssid, verbose=False):
    r"""Remove WIFI profile if exists on Windows using netsh

    Args:
        ssid: profile SSID to remove
        verbose: if set to True, display command used
    """
    print(r'Removing WLAN profile %s if exists...' % ssid)
    cmd = r'netsh wlan delete profile name= %s' % ssid
    if verbose:
        print(r'Command used: %s' % cmd)
    run_notfatal(cmd)


#### LINUX FUNCTIONS

def set_wifi_profile_linux(ssid, password, hidden=False, verbose=False):
    r"""Configure and apply WIFI profile on Linux using nmcli

    Args:
        ssid: network SSID to connect
        password: wifi pre-shared key
        hidden: if set to True, configure a hidden network (default: False)
        verbose: if set to True, display commands used (default: False)

        Note: 
          - nmcli does not care about authentication and encryption modes, it always use the most secure option possible
          - the configured SSID will be set to connect automatically by default

        For more informations see https://networkmanager.dev/docs/api/latest/nmcli.html
    """
    if hidden:
        hidden_value = r'yes'
    else:
        hidden_value = r'no'

    print(r'Creating or updating WLAN profile %s...' % ssid)

    # Remove existings profiles first
    remove_wifi_profile_linux(ssid, verbose=verbose)
    time.sleep(2)

    # Get interface name
    cmd = "nmcli d | grep wifi | grep -v p2p | awk \'{print $1}\'"
    if verbose:
        print(r'Getting wifi interface name with command: %s' % cmd)
    ifname = run(cmd).strip()
    if ifname == "":
        error(r'Error getting wifi interface name !')

    # Add connection
    cmd = r'nmcli con add type wifi con-name %s ssid "%s" ifname %s' % (ssid, ssid, ifname)
    if verbose:
        print(r'Creating wifi connection with command: %s' % cmd)
    run(cmd)

    # Try to connect (sometimes nmcli needs time to be able to interact with previously created connection)
    cmd = r'nmcli dev wifi con "%s" name "%s" password "%s" hidden %s' % (ssid, ssid, password, hidden_value)
    if verbose:
        print(r'Connecting to wifi network with command: %s' % cmd)
    try_nb = 12
    sleep_duration = 5
    for i in range(1, try_nb):
        time.sleep(sleep_duration)
        try:
            print(r'Trying to connect... %s/%s ' % (i, try_nb), end="")
            run(cmd)
        except:
            print(r'FAILED')
            continue
        else:
            print(r'SUCCESS')
            return True
    error(r'Error: cannot connect to wifi network %s after %s attempts !' % (ssid, try_nb))

def remove_wifi_profile_linux(ssid, verbose=False):
    r"""Remove WIFI profile if exists on Linux using nmcli

    Args:
        ssid: profile SSID to remove
        verbose: if set to True, display command used
    """
    print(r'Removing WLAN profile %s if exists...' % ssid)
    cmds = [r'nmcli con delete "%s" ' % ssid,
            r'nmcli con delete "Auto %s" ' % ssid] # Linux Mint create a "Auto <SSID>" connection when configured through GUI, ensure it's deleted too
    if verbose:
        print(r'Commands used: %s' % cmds)
    for cmd in cmds:
        run_notfatal(cmd)
Avatar de l’utilisateur
vcardon
Expert WAPT
Messages : 272
Inscription : 06 oct. 2017 - 22:55
Localisation : Nantes, FR

08 janv. 2026 - 19:09

Bonjour bastien30

Merci pour ton paquet, je te propose une amélioration en t'inspirant de https://www.wapt.fr/fr/doc/wapt-create- ... se-feature.

En effet, les mots de passe dans les paquets WAPT sont des données sensibles et confidentielles et les paquets WAPT sont publiquement visibles by design.

L'astuce proposée dans le lien est une excellente méthode pour protéger une information sensible contenue dans un paquet WAPT.
Vincent CARDON
Tranquil IT
bastien30
Messages : 35
Inscription : 08 mars 2024 - 15:21

08 janv. 2026 - 22:16

Bonjour Vincent,

Alors pour être franc mon paquet intègre bien ce mécanisme mais je me base sur une ancienne version de ce paquet que j'ai un peu modifiée.
Bien que fonctionnel, c'est certainement moins optimisé que la dernière version présente sur le store.
Je l'utilise dans d'autres paquets que j'ai fait il y a un certain temps... et donc c'est plus rapide de copier-coller quand j'en ai besoin :roll:

Voici la version complète du coup !

setup.py :

Code : Tout sélectionner

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

wifi_ssid = r'MY-WIFI-NETWORK'
hidden_ssid = False
encrypted_txt_file = makepath(r'certs', r'encrypt-txt.json')

all_verbose = False

def install():
    # Decrypt WIFI password if hosts_uuid exists in encrypted txt file
    encryptlist = json_load_file(encrypted_txt_file)
    if WAPT.host_uuid in encryptlist:
        host_key = WAPT.get_host_key()
        encrypted_txt = host_key.decrypt(base64.b64decode(encryptlist[WAPT.host_uuid])).decode('utf-8')
    else:
        print('Host UUID %s not found in %s, nothing to do !' % (WAPT.host_uuid, encrypted_txt_file))
        return 0

    if platform.system() == 'Windows':
        set_wifi_profile_windows(ssid=wifi_ssid, password=encrypted_txt, hidden=hidden_ssid, verbose=all_verbose)
    elif platform.system() == 'Darwin':
        set_wifi_profile_macos(ssid=wifi_ssid, password=encrypted_txt, verbose=all_verbose)
    elif platform.system() == 'Linux':
        set_wifi_profile_linux(ssid=wifi_ssid, password=encrypted_txt, hidden=hidden_ssid, verbose=all_verbose)
    else:
        error('Operating System not supported !')

def uninstall():
    if platform.system() == 'Windows':
        remove_wifi_profile_windows(ssid=wifi_ssid, verbose=all_verbose)
    elif platform.system() == 'Darwin':
        remove_wifi_profile_macos(ssid=wifi_ssid, verbose=all_verbose)
    elif platform.system() == 'Linux':
        remove_wifi_profile_linux(ssid=wifi_ssid, verbose=all_verbose)
    else:
        error('Operating System not supported !')


#### MACOS WIFI FUNCTIONS

def set_wifi_profile_macos(ssid, password, verbose=False):
    r"""Configure and apply WIFI profile on MacOS using networksetup

    Args:
        ssid: network SSID to connect
        password: wifi pre-shared key
        verbose: if set to True, display generated XML and command used (default: False)
        
    Notes: 
      - networksetup does not care about hidden network, this method works in all cases
      - networksetup does not care about authentication and encryption modes, it always use the most secure option possible
      - the configured SSID will be set to connect automatically by default

    For more informations see https://www.hexnode.com/mobile-device-management/help/scripts-to-manage-wi-fi-network-settings-on-macos-devices/
    """
    # Remove existings profiles first
    remove_wifi_profile_macos(ssid, verbose=verbose)
    time.sleep(2)

    print(r'Creating or updating WLAN profile %s...' % ssid)
    cmd = r'sudo networksetup -setairportnetwork en0 %s %s' % (ssid, password)
    if verbose:
        print(r'Command used: %s' % cmd)
    run(cmd)

def remove_wifi_profile_macos(ssid, verbose=False):
    r"""Remove WIFI profile if exists on MacOS using networksetup

    Args:
        ssid: profile SSID to remove
        verbose: if set to True, display command used
    """
    print(r'Removing WLAN profile %s if exists...' % ssid)
    # Note: WIFI stay connected after removal but can't reconnect after reboot or disconnection
    cmd = r'sudo networksetup -removepreferredwirelessnetwork en0 %s ' % ssid
    if verbose:
        print(r'Command used: %s' % cmd)
    run_notfatal(cmd)


#### WINDOWS FUNCTIONS

def set_wifi_profile_windows(ssid, password, authentication_mode="WPA2PSK", encryption_mode="AES", connection_mode="auto", hidden=False, verbose=False):
    r"""Configure and apply WIFI profile on Windows using netsh

    Args:
        ssid: network SSID to connect
        password: wifi pre-shared key
        authentication_mode: authentication method to use for connection (default: WPA2PSK)
        encryption_mode: encryption type to use for connection (default: AES)
        connection_mode: wether to enable wifi automatic connection, can be 'auto' or 'manual' (default: auto)
        hidden: if set to True, configure a hidden network (default: False)
        verbose: if set to True, display generated XML and command used (default: False)
        
    For more informations see https://learn.microsoft.com/fr-fr/uwp/schemas/mobilebroadbandschema/wlan/schema-root
    """
    import tempfile

    if connection_mode not in ("auto", "manuel"):
        error("Error: connection_mode can be 'auto' or 'manual' only !")
    
    xml_template = """<?xml version="1.0"?>
<WLANProfile xmlns="http://www.microsoft.com/networking/WLAN/profile/v1">
    <name>{tmpl_ssid}</name>
    <SSIDConfig>
        <SSID>
            <name>{tmpl_ssid}</name>
        </SSID>
        <nonBroadcast>{tmpl_hidden}</nonBroadcast>
    </SSIDConfig>
    <connectionType>ESS</connectionType>
    <connectionMode>{tmpl_connection_mode}</connectionMode>
    <MSM>
        <security>
            <authEncryption>
                <authentication>{tmpl_authentication_mode}</authentication>
                <encryption>{tmpl_encryption_mode}</encryption>
                <useOneX>false</useOneX>
            </authEncryption>
            <sharedKey>
                <keyType>passPhrase</keyType>
                <protected>false</protected>
                <keyMaterial>{tmpl_password}</keyMaterial>
            </sharedKey>
        </security>
    </MSM>
</WLANProfile>"""

    if hidden:
        hidden_value = r'true'
    else:
        hidden_value = r'false'

    # Replace variables in template
    xml_data = xml_template.format(
        tmpl_ssid = ssid,
        tmpl_hidden = hidden_value,
        tmpl_connection_mode = connection_mode,
        tmpl_authentication_mode = authentication_mode,
        tmpl_encryption_mode = encryption_mode,
        tmpl_password = password
    )

    # Remove existings profiles first
    remove_wifi_profile_windows(ssid, verbose=verbose)  
    time.sleep(2)

    # Use try/finally to ensure XML file is always deleted
    try:
        # Use temporary file
        with tempfile.NamedTemporaryFile(mode="w+", suffix=".xml", delete=False, encoding="utf-8") as tmpfile:
            tmpfile.write(xml_data)
            tmpfile.flush()  # force write on disk
            xml_file = tmpfile.name

            if verbose:
                tmpfile.seek(0)
                print("XML content:\n%s" % tmpfile.read())

        print(r'Creating or updating WLAN profile %s...' % ssid)
        cmd = r'netsh wlan add profile filename=%s user=all' % xml_file
        if verbose:
            print(r'Command used: %s' % cmd)
        run(cmd)
    finally:
        remove_file(xml_file)

def remove_wifi_profile_windows(ssid, verbose=False):
    r"""Remove WIFI profile if exists on Windows using netsh

    Args:
        ssid: profile SSID to remove
        verbose: if set to True, display command used
    """
    print(r'Removing WLAN profile %s if exists...' % ssid)
    cmd = r'netsh wlan delete profile name= %s' % ssid
    if verbose:
        print(r'Command used: %s' % cmd)
    run_notfatal(cmd)


#### LINUX FUNCTIONS

def set_wifi_profile_linux(ssid, password, hidden=False, verbose=False):
    r"""Configure and apply WIFI profile on Linux using nmcli

    Args:
        ssid: network SSID to connect
        password: wifi pre-shared key
        hidden: if set to True, configure a hidden network (default: False)
        verbose: if set to True, display generated XML and command used (default: False)

        Note: 
          - nmcli does not care about authentication and encryption modes, it always use the most secure option possible
          - the configured SSID will be set to connect automatically by default

        For more informations see https://networkmanager.dev/docs/api/latest/nmcli.html
    """
    if hidden:
        hidden_value = r'yes'
    else:
        hidden_value = r'no'

    print(r'Creating or updating WLAN profile %s...' % ssid)

    # Remove existings profiles first
    remove_wifi_profile_linux(ssid, verbose=verbose)
    time.sleep(2)

    # Get interface name
    cmd = "nmcli d | grep wifi | grep -v p2p | awk \'{print $1}\'"
    if verbose:
        print(r'Getting wifi interface name with command: %s' % cmd)
    ifname = run(cmd).strip()
    if ifname == "":
        error(r'Error getting wifi interface name !')

    # Add connection
    cmd = r'nmcli con add type wifi con-name %s ssid "%s" ifname %s' % (ssid, ssid, ifname)
    if verbose:
        print(r'Creating wifi connection with command: %s' % cmd)
    run(cmd)

    # Try to connect (sometimes nmcli needs time to be able to interact with previously created connection)
    cmd = r'nmcli dev wifi con "%s" name "%s" password "%s" hidden %s' % (ssid, ssid, password, hidden_value)
    if verbose:
        print(r'Connecting to wifi network with command: %s' % cmd)
    try_nb = 12
    sleep_duration = 5
    for i in range(1, try_nb):
        time.sleep(sleep_duration)
        try:
            print(r'Trying to connect... %s/%s ' % (i, try_nb), end="")
            run(cmd)
        except:
            print(r'FAILED')
            continue
        else:
            print(r'SUCCESS')
            return True
    error(r'Error: cannot connect to wifi network %s after %s attempts !' % (ssid, try_nb))

def remove_wifi_profile_linux(ssid, verbose=False):
    r"""Remove WIFI profile if exists on Linux using nmcli

    Args:
        ssid: profile SSID to remove
        verbose: if set to True, display command used
    """
    print(r'Removing WLAN profile %s if exists...' % ssid)
    cmds = [r'nmcli con delete "%s" ' % ssid,
            r'nmcli con delete "Auto %s" ' % ssid] # Linux Mint create a "Auto <SSID>" connection when configured through GUI, ensure it's deleted too
    if verbose:
        print(r'Commands used: %s' % cmds)
    for cmd in cmds:
        run_notfatal(cmd)
update_package.py :

Code : Tout sélectionner

# -*- coding: UTF-8 -*-
from setuphelpers import *
import json
import base64
from waptcrypto import SSLCertificate
import waptguihelper

encrypted_txt_file = makepath(r'certs', r'encrypt-txt.json')

def update_package():
    # Get server URL
    urlserver = inifile_readstring(makepath(install_location('WAPT_is1'),'wapt-get.ini'),'global','wapt_server').replace('https://','')

    # Connect to API
    print(r'Asking user for WAPT server credentials...')
    credentials_url = waptguihelper.login_password_dialog('Credentials for wapt server',urlserver,'admin','')
    WAPT.waptserver.post('api/v3/login' ,data=json.dumps({'user': credentials_url["user"], 'password':credentials_url["password"]}))

    # Get WIFI password
    print(r'Asking user for WIFI password...')
    encrypted_txt = waptguihelper.input_dialog("Encrypting with WAPT", "Enter the WIFI password: ", "")
    if not encrypted_txt:
        error("Please provide WIFI password !")

    # Remove certs directory and recreate it empty
    if isdir("certs"):
        remove_tree("certs")
    mkdirs("certs")

    # Get certificates from all hosts
    data = WAPT.waptserver.get("api/v3/hosts?columns=host_certificate&limit=1000000")["result"]

    # Encrypt WIFI password with all certificates
    print(r'Encrypting WIFI password with all hosts certificates...')
    encrypt_dict = {}
    for value in data:
        if value["host_certificate"]:
            host_cert = SSLCertificate(crt_string=value["host_certificate"])
            encrypt_dict[value["uuid"]] = base64.b64encode(host_cert.encrypt(encrypted_txt.encode("utf-8"))).decode("utf-8")
            print(value["computer_fqdn"] + ":" + value["uuid"] + ":" + encrypt_dict[value["uuid"]])

    # Write encrypted password to json file
    json_write_file(encrypted_txt_file, encrypt_dict)

    print("\nPackage updated with success !")
Et le petit fichier texte que j'ajoute dans ce genre de paquets, pour que mes collègues sachent comment il fonctionne grossièrement, et comment le mettre à jour :

Code : Tout sélectionner

## Principe :

- on chiffre le mot de passe wifi avec chacune des clés publique de chacun des agents WAPT et on l'exporte dans un fichier texte
- lors de l'installation, chacun des agents WAPT pourra déchiffrer le mot de passe grace à sa clé privée

-> ainsi, le mot de passe wifi n'est pas en clair dans le paquet (il l'est uniquement le temps de l'installation)


## Mettre à jour le paquet :

- dans VSCode, lancer l'update-package depuis le menu de gauche

- entrer les identifiants d'accès à WAPT (identique au mot de passe de la console)

- lorsque c'est demandé, entrer le mot de passe wifi

- si aucune erreur, la console en bas de VSCode doit afficher "Package updated with success !"

- on supprime le dossier __pycache__ à la racine du paquet

- on incrémente le numéro de version du paquet (la partie après le tiret)

- on peut build-upload le paquet ;)
Répondre