khiops icon indicating copy to clipboard operation
khiops copied to clipboard

Khiops GUI is blocked by a group strategy for non-standard installation directory

Open marcboulle opened this issue 1 year ago • 8 comments

Description

Pour les installation sur les directory non standards (cf wiki https://github.com/KhiopsML/khiops/wiki/Manual-Package-Testing-Protocol)

Select the installation directory
- the default C:\Program Files\khiops (or  C:\Applications\khiops)
- one within the user home directory (ex: C:\Users\<USERNAME>\khiops)
- another directory (ex: C:\Temp\khiops)

L'installation se passe bien, mais l'exécution ne marche (pour les deux derniers cas) qu'en mode administrateur. Sinon, il ne se passe rien (aucun message visible). En lançant depuis le shell, on obtient: "Ce programme est bloqué par une stratégie de groupe. Pour plus d’informations, contactez votre administrateur système."

Deux problèmes à résoudre:

  • est-il possible d'avoir un message utilisateur explicite dans ce cas, sans passer par un lancement depuis un shell dos
  • reproduire, mieux qualifier et résoudre le problème de blocage (est-ce un problème spécifique Orange?)

Context

  • Khiops version: 10.2.3

marcboulle avatar Nov 13 '24 09:11 marcboulle

Curieusement, seul le khiops.cmd est bloqué en mode utilisateur. Et en fait, n'importe quel fichier .cmd est bloqué, même un simple echo hello Quand je lance l'exe (signé) sur mon poste développeur (c'est possible, car mon environnement de développement a le path bien configuré), cela marche.

Selon le support DSI Orange, c'est normal: les seuls emplacements autorisés sont C:\Program files et C:\Applications Cela provient d'une règle de Windows AppLocker On peut le voir dans l'application Observateur d'évènements, en allant dans Journaux des applications et services/Microsoft/Windows/AppLocker/MSI et Scripts, puis par clic bouton doit sur Filtrer le journal actuel, en selectionnant le Niveau d'événement à Critique, Avertissement, Erreur, on a les info sur les fichiers .cmd bloqués.

marcboulle avatar Nov 21 '24 09:11 marcboulle

Problème apparemment impossible à résoudre

Issue pour ajouter a minima un warning sur le site site web: https://github.com/KhiopsML/khiops-doc/issues/60

marcboulle avatar Nov 21 '24 14:11 marcboulle

Paradoxalement, un exe signé passerait, alors qu'un cmd est bloqué. Une solution un peu délirante et usine à gaz serait de remplacer le khiops.cmd par un khiops.exe de lancement de Khiops:

  • lors de l'installation (en mode administrateur), lancer khiops_env --env > khiops_env.txt pour obtenir la liste des variables d'environnement et leur valeur
  • le khiops.exe procéderait alors en trois étapes:
    • lecture du khiops_env.txt pour obtenir les valeurs des variables d'environnement
    • paramétrage de l'environnement
    • lancement de MODL.exe

Autre question:

  • quid du comportement de pykhiops installé via pip si Khiops est installé dans un répertoire non standard?
  • le lancement de khiops_env par pykhiops risque de poser problème?

marcboulle avatar Nov 22 '24 10:11 marcboulle

Test avec @popescu-v du lancement de khiops_env.cmd sous Windows, en mode standard (non administrateur):

import subprocess as sp

with sp.Popen(["khiops_env.cmd", "--env"],
    stdout=sp.PIPE,
    stderr=sp.PIPE,
    universal_newlines=True) as khiops_env_process:
    stdout, stderr =  khiops_env_process.communicate()
    print("return code: " + str(khiops_env_process.returncode))
    print("stdout: " + str(stdout))
    print("stderr: " + str(stderr))

Les sorties sont

return code: 1
stdout: 
stderr: Ce programme est bloqu‚ par une strat‚gie de groupe. Pour plus d'informations, contactez votre administrateur systŠme.


Process finished with exit code 0

marcboulle avatar Nov 28 '24 09:11 marcboulle

We could also add the warning to the Installation Wizard (Windows)

lucaurelien avatar Jan 09 '25 14:01 lucaurelien

Actualisation avril 2025

Une stagiaire ayant reçue une machine récente e-buro vient d'avoir ce type de problème, y compris après une installation standard de khiops dans C:\Program files:

  • le lancement de la GUI en mode admin marche correctement
  • le lancement en mode utilisateur déclenche deux messages de type Ce programme est bloqué‚ par une stratégie de groupe, mais étonnamment, l'outil se lance quand même
  • le lancement depuis un jupyter notebook après installation par pip ne marche pas, avec le message d'erreur affiché dans le notebook Image
    • tentative avec la commande Unblock-File .\khiops_env.cmd lancée depuis un powershell: sans effet
    • finalement, en lançant le .cmd de jupyter en mode admin, cela a marché
  • l'installation depuis conda ne marche pas pour des raisons de proxy, malgré les nombreux essais effectués, tous sans succès
    • tentative en configurant HTTP_PROXY et HTTPS_PROXY via les variable d’environnement (Connection to proxy... timeout)
    • tentative via les manips indiquées ici (page référencée depuis notre site aussi) https://www.anaconda.com/docs/tools/working-with-conda/reference/proxy
    • tentative via le VPN interne

marcboulle avatar Apr 08 '25 11:04 marcboulle

According to the official documentation, it seems to be possible to sign PowerShell scripts: https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_signing?view=powershell-7.5#methods-of-signing-scripts. Perhaps one possibility would be to try this approach for a basic PowerShell script first, to validate it and, if successful, port khiops_env.cmd to PowerShell?

popescu-v avatar Apr 08 '25 13:04 popescu-v

A minima décrire le mode d'emploi pour l'utilisation de khiops python sur e-buro

  • via conda ou via pip
  • utilisation depuis un notebook, pycharm...

marcboulle avatar Apr 09 '25 09:04 marcboulle

The POC was done in PR #721.

  • Translation of CMD scripts into PowerShell.
  • signature of all scripts and binaries.

Summary:

  • You can not launch PowerShell scripts (*.ps1) directly. You must use the "powershell -command script.ps1" command.
  • Installation goes smoothly.
  • :point_right: You can install and run Khiops outside the standard path.

Warnings:

  • In some environments, PowerShell is not in the path, even if it is installed and PowerShell path is not in the registry. I have no idea how to retrieve it. However, it seems the path is always the same: C:\Windows\System32\WindowsPowerShell\v1.0.
  • Khiops now depends on Powershell. Should we install it in the Khiops installer, like MPI?
  • khiops_env is now a PowerShell script. Is this okay for khiops-python and other Khiops enablers?

bruno-at-orange avatar Jul 28 '25 14:07 bruno-at-orange

Pour afficher l'erreur au lancement, dans le racourci, il faudrait intercepter stderr et ouvrir un pop-up.

bruno-at-orange avatar Jul 30 '25 09:07 bruno-at-orange

Expliquer sur le site l'origine du problème : c'est pas Khiops mais applocker

  • ce problème existe pour tous les outils de développement exploitant des fichiers de command .cmd: Visual C++, python, conda, virtual env...

bruno-at-orange avatar Jul 30 '25 09:07 bruno-at-orange

Afficher l'erreur au lancement, dans le racourci, il faudrait intercepter stderr et ouvrir un pop-up.

Reproduire le problème

Il suffit d'installer Khiops dans ujn répertoire autre que c:\program files, par exemple dans c:\users\<user id>

Dans ce cas, si on lance sans le mode administrateur, il ne se passe rien. Cela vient du fait que le .cmd affiche un message dans la console, puis est fermé aussitôt.

A noter: le fait que le désinstalleur ne soit pas signer provoque des comportement erratique.

Solution

Au lieu de la commande actuelle C:\Users\miib6422\khiops\bin\khiops.cmd, utiliser la commande suivante obtenu après de nombreux essais erreurs cmd /c "setx TEMP_LOG %TEMP%\khiops_%RANDOM%.log > NUL && C:\Users\miib6422\khiops\bin\khiops.cmd 2> %TEMP_LOG% & for %F in (%TEMP_LOG%) do @if %~zF neq 0 start "Unable to start Khiops" cmd /k type %TEMP_LOG% & exit"

  • cmd /c
    • pour lancer une série de commandes
    • sinon, ça ne marche pas quand on lance en tant qu'administrateur
  • setx TEMP_LOG %TEMP%\khiops_%RANDOM% > NUL
    • setx: pour avoir une variable d'environnement qui soit valide pour les shells suivants (sinon, avec set, les shells suivants ont perdu la valeur)
    • %RANDOM%: pour générer un nom de fichier temporaire unique (sinon, le process khiops.cmd 'locke' le fichier temporaire, et on ne peut lancer deux fois Khiops simultanément)
    • > NUL: pour éviter un echo dans la console signalant la variable d'environnement positionnée par setx est bien enregistrée
  • 2> %TEMP_LOG%: redirection de la sortie d'erreur dans un fichier de log
  • for %F in (%TEMP_LOG%) do @if %~zF neq 0: pour tester si ce fichier est vide ou non
  • start "Unable to start Khiops" cmd /k type %TEMP_LOG%: en cas d'erreur, lancement d'une nouvelle console avec titre "Unable to start Khiops", et affichage du contenu de l'erreur
  • exit: sinon, la fenêtre de console initiale reste quand on quitte Khiops

Résultat

Quand on lance en mode administrateur: ça marche

Quand on lance sans mode administrateur, on obtient la fenêtre de console suivante:

Image

Il reste possible de lancer deux exécution de Khiops simultanément, ce qui est quasiment indispensable dans certain contextes. Par exemple, on lance un Khiops avec un traitement, potentiellement long. En attendant, on lance un nouveau khiops pour travailler sur un autre problème.

Les erreurs de base diagnostiquées par le script khiops.cmd lui-même sont toujours correctement traitées

Problème de l'icône

On a deux icônes dans la barre de tâche, un pour le cmd, un pour Khiops Image

Solution possible: garder l'icône orange pour le cmd, et associer l’icône de la pyramide multi-couleur pour les binaire de khiops et khiops-coclustering

Problème des fichiers temporaires

Chaque exécution crée un nouveau fichier temporaire.

  • ce n'est pas bien grave
  • pas de solution simple trouvée, après quelques essais de destruction du fichier temporaire avant ou après le exit final
  • on est très proche de la limite de la longueur d'une commande en une ligne depuis une icône de lancement du bureau (à moins de 20 caractère de la imite, apparement)

Reste à faire:

  • tests complémentaires, éventuellement
  • industrialiser la solution dans l'installeur Windows
  • résoudre le problème des doubles icônes, en ayant une icône dédié au shell, et une icône dédiée à Khiops

marcboulle avatar Jul 31 '25 08:07 marcboulle

Autre solution à explorer:

  • avoir une tout petit binaire start_khiops.exe qui ne fait que lancer un .cmd
  • ce binaire peut être signé, et donc ne pas être bloqué par la stratégie groupe
  • ce binaire ne serait utilisé que depuis les raccourcis sous windows
    • si on lance Khiops.cmd depuis un shell, les messages d'erreur sont disponibles depuis le shell
    • depuis un raccourci Windows, on lancerait l'outil Khiops via la commande "C:\Program Files\khiops\bin\start_khiops khiops.cmd prenant le .cmd en paramètre (idem pour Khiops coclustering)
    • l'exe qui lance le khiops.cmd peut alors intercepter le code retour et la sortie stderr
    • en cas d'erreur, il peut ouvrir une fenêtre de shell (commande de type startou cmd) pour afficher de façon permanente le message d'erreur
    • il devrait être possible de ne paramétrer qu'une seule icône pour la barre de tâche: à investiguer

Code suggéré par chatgpt, à valider:

#include <windows.h>
#include <iostream>
#include <string>

int main()
{
    // Chemin vers votre script .cmd
    const char* cmdPath = "C:\\chemin\\vers\\MyShell.cmd";

    // Handles pour les pipes
    HANDLE hStdOutRead, hStdOutWrite;
    HANDLE hStdErrRead, hStdErrWrite;

    // Créer pipes pour stdout
    SECURITY_ATTRIBUTES saAttr = { sizeof(SECURITY_ATTRIBUTES), NULL, TRUE };
    CreatePipe(&hStdOutRead, &hStdOutWrite, &saAttr, 0);
    SetHandleInformation(hStdOutRead, HANDLE_FLAG_INHERIT, 0);

    // Créer pipes pour stderr
    CreatePipe(&hStdErrRead, &hStdErrWrite, &saAttr, 0);
    SetHandleInformation(hStdErrRead, HANDLE_FLAG_INHERIT, 0);

    // Configuration du STARTUPINFO
    STARTUPINFO si;
    ZeroMemory(&si, sizeof(si));
    si.cb = sizeof(si);
    si.dwFlags |= STARTF_USESTDHANDLES;
    si.hStdOutput = hStdOutWrite;
    si.hStdError = hStdErrWrite;
    si.hStdInput = NULL; // pas besoin d'entrée standard

    PROCESS_INFORMATION pi;
    ZeroMemory(&pi, sizeof(pi));

    // Construction de la commande
    std::string commandLine = "cmd.exe /C \"" + std::string(cmdPath) + "\"";

    // Lancer le processus
    BOOL success = CreateProcess(
        NULL,
        &commandLine[0],
        NULL,
        NULL,
        TRUE, // hériter des handles
        0,
        NULL,
        NULL,
        &si,
        &pi
    );

    // Fermer les handles d'écriture dans le processus parent
    CloseHandle(hStdOutWrite);
    CloseHandle(hStdErrWrite);

    if (!success)
    {
        MessageBox(NULL, "Erreur lors du lancement du processus.", "Erreur", MB_OK | MB_ICONERROR);
        return 1;
    }

    // Lire la sortie
    char buffer[4096];
    DWORD dwRead;
    std::string outputStdOut;
    std::string outputStdErr;

    // Lire stdout
    while (ReadFile(hStdOutRead, buffer, sizeof(buffer) - 1, &dwRead, NULL) && dwRead)
    {
        buffer[dwRead] = '\0';
        outputStdOut += buffer;
    }

    // Lire stderr
    while (ReadFile(hStdErrRead, buffer, sizeof(buffer) - 1, &dwRead, NULL) && dwRead)
    {
        buffer[dwRead] = '\0';
        outputStdErr += buffer;
    }

    // Attendre la fin du processus
    WaitForSingleObject(pi.hProcess, INFINITE);

    // Récupérer le code de retour
    DWORD exitCode;
    GetExitCodeProcess(pi.hProcess, &exitCode);

    // Vérifier si sortie ou erreur non vide
    if (!outputStdOut.empty() || !outputStdErr.empty())
    {
        std::string message = "Erreur ou sortie détectée.\n\n";

        if (!outputStdOut.empty())
        {
            message += "Stdout:\n" + outputStdOut + "\n";
        }
        if (!outputStdErr.empty())
        {
            message += "Stderr:\n" + outputStdErr + "\n";
        }

        MessageBox(NULL, message.c_str(), "Sortie du processus", MB_OK | MB_ICONINFORMATION);
    }

    // Fermer handles
    CloseHandle(pi.hProcess);
    CloseHandle(pi.hThread);
    CloseHandle(hStdOutRead);
    CloseHandle(hStdErrRead);

    return 0;
}

marcboulle avatar Sep 24 '25 13:09 marcboulle

Continuer le POC avec une journée, sur la piste de l’exécutable de launcher

marcboulle avatar Sep 25 '25 09:09 marcboulle

Améliorations

Améliorations apportées:

  • nettoyage des fichiers temporaires, pour ne pas encombrer le répertoire temporaire
  • message additionnel See https://khiops.org for details

On est aux limites de la longueur max d'une commandes depuis une icône de lancement du shell

  • 255 caractères utilisé , pour une limite windows "historique" de 260
  • économies de longueur réalisée de façon un peu adhoc;
    • TEMP_LOG -> K_LOG
    • khiops_%RANDOM%.log -> k_%RANDOM%.log
    • "Unable to start Khiops" -> "Khiops"
Nouvelle commande

Au lieu de la commande actuelle C:\Users\miib6422\khiops\bin\khiops.cmd, utiliser la commande suivante obtenu après de nombreux essais erreurs C:\Windows\System32\cmd.exe /c setx K_LOG %TEMP%\k_%RANDOM%.log > NUL && del %TEMP%\k_*.log && "%KHIOPS_HOME%\bin\khiops.cmd" 2> %K_LOG% & for %F in (%K_LOG%) do @if %~zF neq 0 start "Khiops" cmd /k "type %K_LOG% & echo See https://khiops.org for details"

Détails:

  • cmd /c
    • pour lancer une série de commandes
    • sinon, ça ne marche pas quand on lance en tant qu'administrateur
    • attention: windows étend cmd en C:\Windows\System32\cmd.exe, ce qui allonge la commande
  • setx K_LOG %TEMP%\k_%RANDOM% > NUL
    • setx: pour avoir une variable d'environnement qui soit valide pour les shells suivants (sinon, avec set, les shells suivants ont perdu la valeur)
    • %RANDOM%: pour générer un nom de fichier temporaire unique (sinon, le process khiops.cmd 'locke' le fichier temporaire, et on ne peut lancer deux fois Khiops simultanément)
    • > NUL: pour éviter un echo dans la console signalant la variable d'environnement positionnée par setx est bien enregistrée
  • 2> %K_LOG %: redirection de la sortie d'erreur dans un fichier de log
  • del %TEMP%\k_*.log : pour nettoyer les fichier temporaire existants
  • "%KHIOPS_HOME%\bin\khiops.cmd": pour ne pas dépendre d'un chemin, qui pourrait être trop long
  • for %F in (%K_LOG %) do @if %~zF neq 0: pour tester si ce fichier est vide ou non
  • start "Unable to start Khiops" cmd /k type %K_LOG%: en cas d'erreur, lancement d'une nouvelle console avec titre "Khiops", et affichage du contenu de l'erreur
  • & echo See khiops.org for details: invitaion à aller sur le site pour avoir des information (notamment le contournement en lançant en tant qu'administrateur)

Message obtenu en cas d'erreur

Image

Problème des doubles icônes

Version actuelle:

  • le shell de lancement de Khiops est associé à un icone de shell dos (un peu invisibilisée)
  • le binaire de Khiops est associé à la pyramide orange

Version avec la nouvelle commande:

  • on a deux icônes dans la barre de tâche, un pour le cmd, un pour Khiops Image

Solution possible: garder l'icône orange pour le cmd, et associer l’icône de la pyramide multi-couleur pour les binaire de khiops et khiops-coclustering

marcboulle avatar Oct 03 '25 15:10 marcboulle

A priori résolu avec la PR https://github.com/KhiopsML/khiops/pull/796

marcboulle avatar Oct 10 '25 15:10 marcboulle