Post

GLPI sous Docker et Traefik

GLPI sous Docker et Traefik

Infrastructure Docker

GLPI est déployé sous Docker. Un Traefik gère l’attribution du certificat et le HTTPS. Le certificat est à renouveler tous les ans avec une autorité externe. Le certificat est stocké ici : /srv/docker/glpi/certificat

La machine hôte est également sécurisée avec un fail2ban (jail SSH), un accès en SSH uniquement, et compte root désactivé.

Les mises à jour du daemon Docker sont bloquées. Attention lors des mises à jour, il faut les forcer pour Docker, et faire un snapshot avant chaque update. Un décalage de 2 versions est recommandée (sauf CVE majeure).

Rappel du docker compose de Traefik.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
services:
  traefik:
    image: traefik:v3
    container_name: traefik
    restart: unless-stopped
    
    # Sécurisation du conteneur
    security_opt:
      - no-new-privileges:true # Empêche l'élévation de privilèges des processus enfants

    environment:
      - DOCKER_API_VERSION=1.44
      - LEGO_CA_CERTIFICATES=/step-ca-certs/root_ca.crt # Injecte le certificat racine de Step-CA pour Lego (client ACME)
      - LEGO_CA_SERVER_NAME=step-ca

    networks:
      - pki-network # Isolation : Uniquement pour dialoguer avec Step-CA
      - web-network # Isolation : Uniquement pour router le trafic vers les applications (Helpdesk, GLPI...)

    ports:
      - "80:80"   # Point d'entrée HTTP
      - "443:443" # Point d'entrée HTTPS

    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro # Socket Docker en lecture seule pour la découverte de conteneurs
      - ./data/acme.json:/data/acme.json             # Stockage sécurisé des certificats ACME générés
      - /srv/docker/step-ca/data/certs/root_ca.crt:/step-ca-certs/root_ca.crt:ro # Certificat racine de l'autorité locale
      # Montage du dossier contenant Cert_bundle.pem, privateKey.pem et la conf custom-cert.yml
      - /srv/docker/glpi/certificat:/etc/traefik/certs:ro

    command:
      # --- CONFIGURATION DES POINTS D'ENTRÉE ---
      - "--entrypoints.web.address=:80"
      - "--entrypoints.web.http.redirections.entrypoint.to=websecure" # Redirection automatique globale HTTP -> HTTPS
      - "--entrypoints.web.http.redirections.entrypoint.scheme=https"
      - "--entrypoints.websecure.address=:443"
      - "--entrypoints.websecure.http.tls=true" # Active TLS par défaut sur le port 443

      # --- PROVIDER DOCKER ---
      - "--providers.docker=true"
      - "--providers.docker.exposedbydefault=false" # Sécurité : ignore les conteneurs sans le label traefik.enable=true
      - "--providers.docker.network=web-network"     # Force Traefik à utiliser ce réseau pour joindre les conteneurs
      - "--providers.docker.endpoint=unix:///var/run/docker.sock"

      # --- PROVIDER FILE (Configuration Dynamique) ---
      # Dit à Traefik de surveiller le dossier monté pour charger les fichiers de conf dynamiques (ex: custom-cert.yml)
      - "--providers.file.directory=/etc/traefik/certs"
      - "--providers.file.watch=true" # Recharge à chaud les certificats et fichiers de conf sans reboot le conteneur

      # --- RESOLVER ACME / STEP-CA ---
      - "--certificatesresolvers.myresolver.acme.caserver=https://step-ca.example.com:9000/acme/my-acme/directory" # URL de la PKI locale
      - "--certificatesresolvers.myresolver.acme.email=admin-it@example.com"
      - "--certificatesresolvers.myresolver.acme.storage=/data/acme.json"
      - "--certificatesresolvers.myresolver.acme.httpchallenge.entrypoint=web" # Utilise le challenge HTTP sur le port 80
      - "--serverstransport.insecureskipverify=true" # Permet à Traefik de joindre des backends avec certificats auto-signés

      # --- LOGS ET API ---
      - "--api.dashboard=true" # Active le tableau de bord Traefik
      - "--log.level=INFO"

    labels:
      # --- ROUTAGE DU DASHBOARD TRAEFIK ---
      - "traefik.enable=true"
      # Authentification Basic Auth pour protéger le dashboard (Utilisateur : admin)
      - "traefik.http.middlewares.auth-dash.basicauth.users=admin_user:$$2y$$05$$hashExempleSecurise"
      - "traefik.http.routers.dashboard.rule=Host(`traefik.example.com`)"
      - "traefik.http.routers.dashboard.entrypoints=websecure"
      - "traefik.http.routers.dashboard.service=api@internal" # Point vers l'API interne de Traefik
      - "traefik.http.routers.dashboard.tls.certresolver=myresolver" # Génère le certificat du dashboard via Step-CA
      - "traefik.http.routers.dashboard.middlewares=auth-dash" # Applique la protection par mot de passe

networks:
  # Réseaux définis à l'extérieur de ce fichier compose (générés manuellement via docker network create)
  pki-network:
    external: true
  web-network:
    external: true

la ligne internal: true sur le réseau glpi-internal signifie que la base de données est enfermée dans un bunker complet. Si un jour besoin que GLPI aille requêter un serveur LDAP externe, un serveur de mail ou l’API Let’s Encrypt pour vérifier quelque chose, c’est le conteneur glpi qui s’en chargera via le web-network (qui lui possède une route par défaut). La base de données reste totalement protégée.

Gestion du certificat

Dans le dossier glpi/certificat, coller les fichiers du certificat. Renommer la privateKey.pem en privateKey.pem.old et faire la commande suivante pour la déchiffrer :

sudo openssl pkey -in /srv/docker/glpi/certificat/privateKey.pem.old -out /srv/docker/glpi/certificat/privateKey.pem

Création de la conf dynamique pour faire le lien avec traefik :

sudo nano /srv/docker/glpi/certificat/custom-cert.yml

A l’intérieur, coller ceci :

1
2
3
4
5
tls:
  certificates:
    - certFile: /etc/traefik/certs/Cert_bundle.pem
      keyFile: /etc/traefik/certs/privateKey.pem

Le docker compose de traefik a été modifié en conséquence.

Pour le renouvellement, il est juste nécessaire de copier les fichiers et déchiffrer la clé privée en respectant le nommage de base. Penser à renommer la clé chiffrée en privateKey.pem.old avant de lancer la commande.


GLPI

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
services:
  # ==========================================
  # CONTENEUR DE BASE DE DONNÉES (MARIADB)
  # ==========================================
  glpi-db:
    # Version LTS stable de MariaDB pour garantir la compatibilité GLPI
    image: mariadb:10.11
    container_name: glpi-db
    # Redémarrage automatique sauf si arrêt manuel par l'administrateur
    restart: unless-stopped
    environment:
      # Nom de la base de données créée au premier démarrage
      - MARIADB_DATABASE=glpidb
      # Utilisateur applicatif dédié à GLPI
      - MARIADB_USER=glpi_app
      # Mot de passe de l'utilisateur dédié
      - MARIADB_PASSWORD=DbPasswordExample_Secret123
      # Mot de passe administrateur racine de la base de données
      - MARIADB_ROOT_PASSWORD=RootDbPasswordExample_Secret456
    volumes:
      # Persistance des données MariaDB sur l'hôte Docker
      - ./data/db:/var/lib/mysql
    networks:
      # Réseau isolé pour couper la base de données d'un accès extérieur direct
      - glpi-internal

  # ==========================================
  # CONTENEUR APPLICATIF (GLPI)
  # ==========================================
  glpi:
    # Utilisation de la dernière version officielle de GLPI
    image: glpi/glpi:latest
    container_name: glpi
    restart: unless-stopped
    depends_on:
      # Force Docker à démarrer le conteneur glpi-db avant celui-ci
      - glpi-db
    environment:
      # Configuration de la chaîne de connexion à MariaDB (via le DNS interne Docker)
      - GLPI_DB_HOST=glpi-db
      - GLPI_DB_NAME=glpidb
      - GLPI_DB_USER=glpi_app
      - GLPI_DB_PASSWORD=DbPasswordExample_Secret123
      # URL publique de l'instance pour la génération des liens internes
      - GLPI_URL=https://glpi.example.com
      # Sécurité : Désactive la validation IP/User-Agent des sessions (évite les déconnexions derrière Traefik)
      - GLPI_SESSION_CHECK_IP=0
      - GLPI_SESSION_CHECK_USER_AGENT=0
      # Force GLPI à générer tous ses jetons et cookies en HTTPS sécurisé
      - GLPI_FORCE_HTTPS=1
      # Désactive les requêtes d'update automatiques vers les serveurs externes de GLPI
      - GLPI_SKIP_UPDATES_CHECKS=1
    volumes:
      # Volumes persistants pour la configuration, les fichiers joints et les extensions
      - ./data/config:/var/glpi/config
      - ./data/files:/var/glpi/files
      - ./data/marketplace:/var/glpi/marketplace
      - ./data/plugins:/var/www/glpi/plugins
      # Injection de la configuration Apache personnalisée en lecture seule
      - ./conf/apache-glpi.conf:/etc/apache2/sites-enabled/000-default.conf:ro
      # Injection de la configuration PHP (durée/sécurité des sessions) en lecture seule
      - ./conf/99-glpi-session.ini:/usr/local/etc/php/conf.d/99-glpi-session.ini:ro
    networks:
      # Double attachement : 'web-network' pour Traefik, 'glpi-internal' pour la BDD
      - web-network
      - glpi-internal
    labels:
      # Demande explicitement à Traefik de prendre en charge ce conteneur
      - "traefik.enable=true"
      # Règle de routage basée sur le FQDN de votre GLPI
      - "traefik.http.routers.glpi.rule=Host(`glpi.example.com`)"
      # Associe le routeur au point d'entrée HTTPS (port 443 global de Traefik)
      - "traefik.http.routers.glpi.entrypoints=websecure"
      
      # --- FORÇAGE DU CERTIFICAT STATIQUE ---
      # Active le chiffrement TLS sur le routeur Traefik
      - "traefik.http.routers.glpi.tls=true"
      # IMPORTANT : On vide explicitement le certresolver pour forcer l'usage d'un certificat statique local et bloquer Step-CA
      - "traefik.http.routers.glpi.tls.certresolver="
      
      # Spécifie à Traefik que le serveur Apache interne écoute sur le port 80 du conteneur
      - "traefik.http.services.glpi.loadbalancer.server.port=80"
      
      # Association du middleware de réécriture des en-têtes
      - "traefik.http.routers.glpi.middlewares=glpi-headers"
      # Injection des en-têtes proxy indispensables pour que GLPI comprenne qu'il est derrière un SSL de proxy
      - "traefik.http.middlewares.glpi-headers.headers.customrequestheaders.X-Forwarded-Proto=https"
      - "traefik.http.middlewares.glpi-headers.headers.customrequestheaders.X-Forwarded-Port=443"
      - "traefik.http.middlewares.glpi-headers.headers.customrequestheaders.X-Forwarded-Ssl=on"
      # Protection contre le Clickjacking : empêche l'intégration de GLPI dans une iframe externe
      - "traefik.http.middlewares.glpi-headers.headers.customresponseheaders.X-Frame-Options=SAMEORIGIN"

# ==========================================
# CONFIGURATION DES RÉSEAUX DOCKER
# ==========================================
networks:
  # Réseau frontal externe géré par l'instance globale Traefik
  web-network:
    external: true
  # Réseau local isolé dédié à l'isolation stricte GLPI <-> MariaDB
  glpi-internal:
    internal: true


Mises à jour automatiques (Unattended-Upgrades)

Installation du service

Installer les paquets nécessaires :

1
2
3
sudo apt update
sudo apt install unattended-upgrades apt-listchanges

Note : Le paquet apt-listchanges permet d’afficher les informations importantes relatives aux mises à jour installées.


Configuration du service

Le fichier principal de configuration est : /etc/apt/apt.conf.d/50unattended-upgrades

Par défaut, Debian configure l’installation automatique des mises à jour de sécurité provenant des dépôts officiels. On peut le vérifier en filtrant les commentaires et les lignes vides :

1
2
cat /etc/apt/apt.conf.d/50unattended-upgrades | grep -v "//" | grep -v "^$"

Le comportement du service peut être ajusté afin de :

  • Installer uniquement les correctifs de sécurité.
  • Supprimer automatiquement les dépendances devenues inutiles (paquets orphelins).
  • Redémarrer automatiquement le système si nécessaire.
  • Envoyer des notifications par courriel à l’administrateur.

Configuration recommandée pour un serveur

Modifier le fichier /etc/apt/apt.conf.d/50unattended-upgrades pour obtenir la configuration suivante :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
Unattended-Upgrade::Origins-Pattern {
    "origin=Debian,codename=${distro_codename},label=Debian";
    "origin=Debian,codename=${distro_codename},label=Debian-Security";
    "origin=Debian,codename=${distro_codename}-security,label=Debian-Security";
};

Unattended-Upgrade::Package-Blacklist {
};

// Supprimer automatiquement les paquets orphelins
Unattended-Upgrade::Remove-Unused-Dependencies "true";

// Supprimer les noyaux obsolètes
Unattended-Upgrade::Remove-New-Unused-Dependencies "true";

// Redémarrage automatique si nécessaire (ex : mise à jour du noyau)
Unattended-Upgrade::Automatic-Reboot "false";
Unattended-Upgrade::Automatic-Reboot-WithUsers "false";
Unattended-Upgrade::Automatic-Reboot-Time "03:00";

// Envoyer un rapport par mail (nécessite mailutils + un MTA fonctionnel)
Unattended-Upgrade::Mail "root";
Unattended-Upgrade::MailReport "on-change";

// Journalisation
Unattended-Upgrade::SyslogEnable "true";
Unattended-Upgrade::SyslogFacility "daemon";

// Limite de bande passante en Ko/s (0 = illimité)
Unattended-Upgrade::Dl-Limit "0";


Activation des mises à jour automatiques

Le fichier suivant contrôle la fréquence d’exécution : /etc/apt/apt.conf.d/20auto-upgrades

Pour générer ou modifier ce fichier avec la configuration recommandée, lancer la commande interactive :

1
2
dpkg-reconfigure -plow unattended-upgrades

Vérifier que le fichier /etc/apt/apt.conf.d/20auto-upgrades contient bien :

1
2
3
APT::Periodic::Update-Package-Lists "1";
APT::Periodic::Unattended-Upgrade "1";

Comportement : Cette configuration effectue quotidiennement (1) une mise à jour de la liste des paquets et installe automatiquement les correctifs autorisés.


Vérification du fonctionnement

L’état du service système se vérifie avec :

1
2
systemctl status unattended-upgrades

Pour tester la configuration et forcer une exécution à blanc (mode debug), lancer :

1
2
unattended-upgrade --debug --dry-run

Analyse des logs

Les journaux d’exécution sont stockés dans le répertoire : /var/log/unattended-upgrades/

Pour vérifier quelles mises à jour ont été appliquées automatiquement, consulter le fichier de log principal :

1
2
cat /var/log/unattended-upgrades/unattended-upgrades.log

Liaison LDAP

  • Renseigner l’IP du serveur AD
  • Dans le filtre de connexion : (&(samaccountname=*)(objectClass=user)(objectCategory=person)(!(userAccountControl:1.2.840.113556.1.4.803:=2)))
  • Dans Base DN : DC=example,DC=com
  • Pour le compte qui sert de connecteur (mot de passe du compte dans le gestionnaire de mots de passe) : CN=svc_glpi_ldap,OU=Comptes_Service,OU=Administration,DC=example,DC=com
  • Pour la connexion des utilisateurs : samaccountname
  • Sauvegarder et tester la liaison LDAP

Pour importer des utilisateurs, se rendre dans Administration et Utilisateurs et sélectionner Liaison annuaire LDAP.

Après avoir sélectionné l’option permettant l’import, cliquer sur Rechercher, sélectionner les utilisateurs à importer, cliquer sur Actions et choisir Importer dans le menu déroulant. Lors du premier import, la page peut afficher un échec. Rafraîchir la page jusqu’au retour de la page GLPI.

Pour une synchronisation automatique des utilisateurs, se connecter en SSH sur la machine hôte et éditer la crontab :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
sudo crontab -e 

# Sélectionner nano et ajouter cette ligne à la fin du fichier 

0 2 * * * /usr/bin/docker exec -u www-data glpi php /var/www/glpi/bin/console glpi:ldap:synchronize_users

# Décryptage de la ligne de cron pour la documentation

# 0 2 * * * : "Tous les jours, à 2h00 du matin pile..."

# /usr/bin/docker exec : "...va exécuter dans le conteneur nommé..."

# glpi : "...le conteneur GLPI..."

# -u www-data : "...avec l'utilisateur web www-data..."

# php /var/www/glpi/bin/console glpi:ldap:synchronize_users : "...pour synchroniser les comptes existants et importer les nouveaux."

Il est possible de lancer le script manuellement pour vérifier le fonctionnement :

1
2
sudo docker exec -u www-data glpi php /var/www/glpi/bin/console glpi:ldap:synchronize_users


Notifications par mail

Dans le menu notifications choisir Configuration des notifications par mail :

  1. Préciser l’adresse d’expédition (assistance-it@example.com)
  2. Ajouter le nom d’affichage de l’expéditeur (Support Informatique)
  3. Ajouter la signature
  4. Mode d’envoi des e-mails en SMTP
  5. Vérifier le certificat : non, on utilise le relais SMTP
  6. Ajouter les informations liées au SMTP (smtp-relais.example.com)
  7. Ajouter le port pour de la distribution interne (25)
  8. Valider

Pour personnaliser les mails envoyés aux utilisateurs (français & anglais), se rendre dans les modèles de notifications, et sélectionner Tickets, Traductions de modèle et ajouter les différentes langues.

Pour le français, par exemple :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Titre : ##ticket.action## ##ticket.title## 

Corps : 
Lien du ticket : ##ticket.url##

Sujet : ##ticket.title##
Demandeur : ##ticket.authors##
Technicien en charge : ##IFticket.assigntousers####ticket.assigntousers####ENDIFticket.assigntousers####ELSEticket.assigntousers##Aucun##ENDELSEticket.assigntousers##
Statut actuel : ##ticket.status##

Dernier message :
##IFticket.storestatus=1####ticket.content####ENDIFticket.storestatus####IFticket.storestatus=2####FOREACH LAST 1 followups####followup.description####ENDFOREACHfollowups####ENDIFticket.storestatus####IFticket.storestatus=3####FOREACH LAST 1 followups####followup.description####ENDFOREACHfollowups####ENDIFticket.storestatus####IFticket.storestatus=4####FOREACH LAST 1 followups####followup.description####ENDFOREACHfollowups####ENDIFticket.storestatus####IFticket.storestatus=5####ticket.solution.description####ENDIFticket.storestatus####IFticket.storestatus=6####FOREACH LAST 1 followups####followup.description####ENDFOREACHfollowups####ENDIFticket.storestatus##

⚠️ Merci de ne pas répondre à ce mail. Utilisez uniquement le lien ci-dessus pour ajouter un suivi ou interagir.

Adapter selon les besoins.


Gestion des profils

Permet de modifier les droits sur les différents profils. Par défaut, le profil self-service est attribué aux utilisateurs. Il a été renommé Espace Demandeur pour les utilisateurs et est toujours attribué par défaut.

Il est possible d’attribuer des profils spécifiques directement à un groupe ou à un utilisateur. Pour cela, se rendre dans Administrations > Utilisateurs.

Cliquer sur l’utilisateur et choisir Habilitations et ajouter le(s) profil(s).


Agent GLPI

L’agent GLPI est déployé par GPO sur les ordinateurs du domaine, avec un script VBS. Le script est ici : \\srv-partages.example.com\deploiements$\GLPI\agent_glpi.vbs

L’agent permet de gérer la partie parc informatique et gestion du matériel. Pour les ordinateurs qui ne sont pas dans le domaine ou sur des OS autres que Windows, il faut installer manuellement l’agent GLPI, ou rentrer les ordinateurs manuellement.

Se baser sur la documentation officielle pour appliquer des changements.

Contenu du script :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
'
'  ------------------------------------------------------------------------
'  glpi-agent-deployment.vbs
'  Copyright (C) 2010-2017 by the FusionInventory Development Team.
'  Copyright (C) 2021-2024 by the Teclib SAS
'  ------------------------------------------------------------------------
'
'  LICENSE
'
'  This file is part of GLPI Agent project.
'
'  This file is free software; you can redistribute it and/or modify it
'  under the terms of the GNU General Public License as published by the
'  Free Software Foundation; either version 2 of the License, or (at your
'  option) any later version.
'
'
'  This file is distributed in the hope that it will be useful, but WITHOUT
'  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
'  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
'  more details.
'
'  You should have received a copy of the GNU General Public License
'  along with this program; if not, write to the Free Software Foundation,
'  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA,
'  or see https://www.gnu.org/licenses/
'
'  ------------------------------------------------------------------------
'
'  @package   GLPI Agent
'  @version   1.18
'  @file      contrib/windows/glpi-agent-deployment.vbs
'  @author(s) Benjamin Accary <meldrone@orange.fr>
'             Christophe Pujol <chpujol@gmail.com>
'             Marc Caissial <marc.caissial@zenitique.fr>
'             Tomas Abad <tabadgp@gmail.com>
'             Guillaume Bougard <gbougard@teclib.com>
'  @copyright Copyright (c) 2010-2017 FusionInventory Team
'             Copyright (c) 2021-2024 Teclib SAS
'  @license   GNU GPL version 2 or (at your option) any later version
'             https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
'  @link      https://www.glpi-project.org/
'  @since     2021
'
'  ------------------------------------------------------------------------
'

'
'
' Purpose:
'     GLPI Agent Unattended Deployment.
'
'

Option Explicit
Dim Reconfigure, Repair, Verbose
Dim Setup, SetupArchitecture, SetupLocation, SetupNightlyLocation, SetupOptions, SetupVersion, RunUninstallFusionInventoryAgent, UninstallOcsAgent

'
'
' USER SETTINGS
'
'

' SetupVersion
'    Setup version with the pattern <major>.<minor>.<release>[-<package>]
'
SetupVersion = "1.18"

' When using a nightly built version, uncomment the following SetupVersion definition line
' replacing gitABCDEFGH with the most recent git revision found on the nightly builds site
' In that case, SetupNightlyLocation will be selected as location in place of SetupLocation
'SetupVersion = "1.18-gitABCDEFGH"

' SetupLocation
'    Depending on your needs or your environment, you can use either a HTTP or
'    CIFS/SMB.
'
'    If you use HTTP, please, set to SetupLocation a URL:
'
'       SetupLocation = "http://host[:port]/[absolut_path]" or
'       SetupLocation = "https://host[:port]/[absolut_path]"
'
'    If you use CIFS, please, set to SetupLocation a UNC path name:
'
'       SetupLocation = "\\host\share\[path]"
'
'       You also must be sure that you have removed the "Open File Security Warning"
'       from programs accessed from that UNC.
'
' Location for Release Candidates
SetupLocation = "\\srv-partages.example.com\deploiements$\GLPI"

' Location for Nightly Builds
SetupNightlyLocation = "https://nightly.glpi-project.org/glpi-agent"


' SetupArchitecture
'    The setup architecture can be 'x86', 'x64' or 'Auto'
'
'    If you set SetupArchitecture = "Auto" be sure that both installers are in
'    the same SetupLocation.
'
SetupArchitecture = "x64"

' SetupOptions
'    Consult the online installer documentation to know its list of options.
'    See: https://glpi-agent.readthedocs.io/en/latest/installation/windows-command-line.html#command-line-parameters
'
'    You should use simple quotes (') to set between quotation marks those values
'    that require it; double quotes (") doesn't work with UNCs.
'
SetupOptions = "/quiet RUNNOW=1 ADD_FIREWALL_EXCEPTION=1 NO_SSL_CHECK=1 SERVER=https://glpi.example.com/front/inventory.php TASKS=inventory REINSTALLMODE=vamus"
'SetupOptions = "/quiet RUNNOW=1 SERVER='http://glpi.yourcompany.com/plugins/fusioninventory'"

' Setup
'    The installer file name. You should not have to modify this variable ever.
'
Setup = "GLPI-Agent-" & SetupVersion & "-" & SetupArchitecture & ".msi"

' Reconfigure
'    Just reconfigure the current installation if installed agent has the same version
'
Reconfigure = "Yes"

' Repair
'    Repair the installation when Setup is still installed.
'
Repair = "No"

' Verbose
'    Enable or disable the information messages.
'
'    It's advisable to use Verbose = "Yes" with 'cscript //nologo ...'.
'
Verbose = "No"

' RunUninstallFusionInventoryAgent
'    Set to "Yes" to first uninstall FusionInventory Agent
'    Also and unless SERVER or LOCAL are defined in SetupOptions, this script
'    will try to get them from FusionInventory-Agent configuration found in registry
'
RunUninstallFusionInventoryAgent = "No"

' UninstallOcsAgent
'    Enable or disable the uninstallation of OCS Agent
'
UninstallOcsAgent = "Yes"

'
'
' DO NOT EDIT BELOW
'
'

Function removeOCSAgents()
   On error resume next

   Dim Uninstall
   ' Uninstall agent ocs if is installed
   ' Verification on OS 32 Bits
   On error resume next
   Uninstall = WshShell.RegRead("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\OCS Inventory Agent\UninstallString")
   If err.number = 0 then
      WshShell.Run "CMD.EXE /C net stop ""OCS INVENTORY SERVICE""",0,True
      WshShell.Run "CMD.EXE /C """ & Uninstall & """ /S /NOSPLASH",0,True
      WshShell.Run "CMD.EXE /C rmdir ""%ProgramFiles%\OCS Inventory Agent"" /S /Q",0,True
      WshShell.Run "CMD.EXE /C rmdir ""%SystemDrive%\ocs-ng"" /S /Q",0,True
      WshShell.Run "CMD.EXE /C sc delete ""OCS INVENTORY""",0,True
   End If

   ' Verification on OS 64 Bits
   On error resume next
   Uninstall = WshShell.RegRead("HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\OCS Inventory Agent\UninstallString")
   If err.number = 0 then
      WshShell.Run "CMD.EXE /C net stop ""OCS INVENTORY SERVICE""",0,True
      WshShell.Run "CMD.EXE /C """ & Uninstall & """ /S /NOSPLASH",0,True
      WshShell.Run "CMD.EXE /C rmdir ""%ProgramFiles(x86)%\OCS Inventory Agent"" /S /Q",0,True
      WshShell.Run "CMD.EXE /C rmdir ""%SystemDrive%\ocs-ng"" /S /Q",0,True
      WshShell.Run "CMD.EXE /C sc delete ""OCS INVENTORY""",0,True
   End If

   ' Verification Agent V2 on 32Bit
   On error resume next
   Uninstall = WshShell.RegRead("HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\OCS Inventory NG Agent\UninstallString")
   If err.number = 0 then
      WshShell.Run "CMD.EXE /C net stop ""OCS INVENTORY SERVICE""",0,True
      WshShell.Run "CMD.EXE /C taskkill /F /IM ocssystray.exe",0,True
      WshShell.Run "CMD.EXE /C """ & Uninstall & """ /S /NOSPLASH",0,True
      WshShell.Run "CMD.EXE /C rmdir ""%ProgramFiles%\OCS Inventory Agent"" /S /Q",0,True
      WshShell.Run "CMD.EXE /C rmdir ""%SystemDrive%\ocs-ng"" /S /Q",0,True
      WshShell.Run "CMD.EXE /C sc delete ""OCS INVENTORY""",0,True
   End If

   ' Verification Agent V2 on 64Bit
   On error resume next
   Uninstall = WshShell.RegRead("HKLM\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\OCS Inventory NG Agent\UninstallString")
   If err.number = 0 then
      WshShell.Run "CMD.EXE /C net stop ""OCS INVENTORY SERVICE""",0,True
      WshShell.Run "CMD.EXE /C taskkill /F /IM ocssystray.exe",0,True
      WshShell.Run "CMD.EXE /C """ & Uninstall & """ /S /NOSPLASH",0,True
      WshShell.Run "CMD.EXE /C rmdir ""%ProgramFiles%\OCS Inventory Agent"" /S /Q",0,True
      WshShell.Run "CMD.EXE /C rmdir ""%SystemDrive%\ocs-ng"" /S /Q",0,True
      WshShell.Run "CMD.EXE /C sc delete ""OCS INVENTORY""",0,True
   End If
End Function

Function hasOption(opt)
   Dim regEx
   Set regEx = New RegExp
   regEx.Global = true
   regEx.IgnoreCase = False
   regEx.Pattern = "\b" & opt & "=.+\b"
   hasOption = regEx.Test(SetupOptions)
End Function

Function uninstallFusionInventoryAgent()
   Dim Uninstall, getValue

   ' Try to get SERVER and LOCAL from FIA configuration in registry if needed
   If not hasOption("SERVER") then
      On error resume next
      getValue = WshShell.RegRead("HKEY_LOCAL_MACHINE\SOFTWARE\FusionInventory-Agent\server")
      If err.number = 0 And getValue <> "" then
         SetupOptions = SetupOptions & " SERVER='" & getValue & "'"
      End If
   End If
   If not hasOption("LOCAL") then
      On error resume next
      getValue = WshShell.RegRead("HKEY_LOCAL_MACHINE\SOFTWARE\FusionInventory-Agent\local")
      If err.number = 0 And getValue <> "" then
         SetupOptions = SetupOptions & " LOCAL='" & getValue & "'"
      End If
   End If

   ' Verify normal case
   On error resume next
   Uninstall = WshShell.RegRead("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\FusionInventory-Agent\UninstallString")
   If err.number = 0 then
      WshShell.Run "CMD.EXE /C net stop FusionInventory-Agent",0,True
      WshShell.Run "CMD.EXE /C """ & Uninstall & """ /S /NOSPLASH",0,True
      WshShell.Run "CMD.EXE /C rmdir ""%ProgramFiles%\FusionInventory-Agent"" /S /Q",0,True
   End If

   ' Verify FIA x86 is installed on x64 OS
   On error resume next
   Uninstall = WshShell.RegRead("HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\FusionInventory-Agent\UninstallString")
   If err.number = 0 then
      WshShell.Run "CMD.EXE /C net stop FusionInventory-Agent",0,True
      WshShell.Run "CMD.EXE /C """ & Uninstall & """ /S /NOSPLASH",0,True
      WshShell.Run "CMD.EXE /C rmdir ""%ProgramFiles(x86)%\FusionInventory-Agent"" /S /Q",0,True
   End If
End Function

Function AdvanceTime(nMinutes)
   Dim nMinimalMinutes, dtmTimeFuture
   ' As protection
   nMinimalMinutes = 5
   If nMinutes < nMinimalMinutes Then
      nMinutes = nMinimalMinutes
   End If
   ' Add nMinutes to the current time
   dtmTimeFuture = DateAdd ("n", nMinutes, Time)
   ' Format the result value
   '    The command AT accepts 'HH:MM' values only
   AdvanceTime = Hour(dtmTimeFuture) & ":" & Minute(dtmTimeFuture)
End Function

Function baseName (strng)
   Dim regEx
   Set regEx = New RegExp
   regEx.Global = true
   regEx.IgnoreCase = True
   regEx.Pattern = ".*[/\\]([^/\\]+)$"
   baseName = regEx.Replace(strng,"$1")
End Function

Function GetSystemArchitecture()
   Dim strSystemArchitecture
   Err.Clear
   ' Get operative system architecture
   On Error Resume Next
   strSystemArchitecture = CreateObject("WScript.Shell").ExpandEnvironmentStrings("%PROCESSOR_ARCHITECTURE%")
   If Err.Number = 0 Then
      ' Check the operative system architecture
      Select Case strSystemArchitecture
         Case "x86"
            ' The system architecture is 32-bit
            GetSystemArchitecture = "x86"
         Case "AMD64"
            ' The system architecture is 64-bit
            GetSystemArchitecture = "x64"
         Case Else
            ' The system architecture is not supported
            GetSystemArchitecture = "NotSupported"
      End Select
   Else
      ' It has been not possible to get the system architecture
      GetSystemArchitecture = "Unknown"
   End If
End Function

Function isHttp(strng)
   Dim regEx, matches
   Set regEx = New RegExp
   regEx.Global = true
   regEx.IgnoreCase = True
   regEx.Pattern = "^(http(s?)).*"
   If regEx.Execute(strng).count > 0 Then
      isHttp = True
   Else
      isHttp = False
   End If
   Exit Function
End Function

Function isNightly(strng)
   Dim regEx, matches
   Set regEx = New RegExp
   regEx.Global = true
   regEx.IgnoreCase = True
   regEx.Pattern = "-(git[0-9a-f]{8})$"
   If regEx.Execute(strng).count > 0 Then
      isNightly = True
   Else
      isNightly = False
   End If
   Exit Function
End Function

' Major version 1 and Minor version greater than 7 doesn't support x86
Function doesNotSupportX86(strng)
   Dim regEx, matches, major, minor
   Set regEx = New RegExp
   regEx.Global = true
   regEx.Pattern = "^([0-9]+)\.([0-9]+)"
   Set matches = regEx.Execute(strng)
   doesNotSupportX86 = False
   If matches.count > 0 Then
      major = matches(0).SubMatches(0)
      minor = matches(0).SubMatches(1)
      If major = 1 And minor > 7 Then
         doesNotSupportX86 = True
      End If
   End If
   Exit Function
End Function

Function IsInstallationNeeded(strSetupVersion, strSetupArchitecture, strSystemArchitecture)
   Dim strCurrentSetupVersion
   ' Compare the current version, whether it exists, with strSetupVersion
   If strSystemArchitecture = "x86" Then
      ' The system architecture is 32-bit
      ' Check if the subkey 'SOFTWARE\GLPI-Agent\Installer' exists
      On error resume next
      strCurrentSetupVersion = WshShell.RegRead("HKEY_LOCAL_MACHINE\SOFTWARE\GLPI-Agent\Installer\Version")
      If Err.Number = 0 Then
      ' The subkey 'SOFTWARE\GLPI-Agent\Installer' exists
         If strCurrentSetupVersion <> strSetupVersion Then
            ShowMessage("Installation needed: " & strCurrentSetupVersion & " -> " & strSetupVersion)
            IsInstallationNeeded = True
         End If
         Exit Function
      Else
      ' The subkey 'SOFTWARE\GLPI-Agent\Installer' doesn't exist
         Err.Clear
         ShowMessage("Installation needed: " & strSetupVersion)
         IsInstallationNeeded = True
      End If
   Else
      ' The system architecture is 64-bit
      ' Check if the subkey 'SOFTWARE\Wow6432Node\GLPI-Agent\Installer' exists
      On error resume next
      strCurrentSetupVersion = WshShell.RegRead("HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\GLPI-Agent\Installer\Version")
      If Err.Number = 0 Then
      ' The subkey 'SOFTWARE\Wow6432Node\GLPI-Agent\Installer' exists
         If strCurrentSetupVersion <> strSetupVersion Then
            ShowMessage("Installation needed: " & strCurrentSetupVersion & " -> " & strSetupVersion)
            IsInstallationNeeded = True
         End If
         Exit Function
      Else
         ' The subkey 'SOFTWARE\Wow6432Node\GLPI-Agent\Installer' doesn't exist
         Err.Clear
         ' Check if the subkey 'SOFTWARE\GLPI-Agent\Installer' exists
         On error resume next
         strCurrentSetupVersion = WshShell.RegRead("HKEY_LOCAL_MACHINE\SOFTWARE\GLPI-Agent\Installer\Version")
         If Err.Number = 0 Then
         ' The subkey 'SOFTWARE\GLPI-Agent\Installer' exists
            If strCurrentSetupVersion <> strSetupVersion Then
               ShowMessage("Installation needed: " & strCurrentSetupVersion & " -> " & strSetupVersion)
               IsInstallationNeeded = True
            End If
            Exit Function
         Else
            ' The subkey 'SOFTWARE\GLPI-Agent\Installer' doesn't exist
            Err.Clear
            ShowMessage("Installation needed: " & strSetupVersion)
            IsInstallationNeeded = True
         End If
      End If
   End If
End Function

Function IsSelectedReconfigure()
   If LCase(Reconfigure) <> "no" Then
      ShowMessage("Installation reconfigure: " & SetupVersion)
      IsSelectedReconfigure = True
   Else
      IsSelectedReconfigure = False
   End If
End Function

Function IsSelectedRepair()
   If LCase(Repair) <> "no" Then
      ShowMessage("Installation repairing: " & SetupVersion)
      IsSelectedRepair = True
   Else
      IsSelectedRepair = False
   End If
End Function

Function SaveWebBinary(strSetupLocation, strSetup)
   Const adTypeBinary = 1
   Const adSaveCreateOverWrite = 2
   Const ForWriting = 2
   Dim web, varByteArray, strData, strBuffer, lngCounter, ado, strUrl
   strUrl = strSetupLocation & "/" & strSetup
   Err.Clear
   Set web = Nothing
   Set web = CreateObject("WinHttp.WinHttpRequest.5.1")
   If web Is Nothing Then Set web = CreateObject("WinHttp.WinHttpRequest")
   If web Is Nothing Then Set web = CreateObject("MSXML2.ServerXMLHTTP")
   If web Is Nothing Then Set web = CreateObject("Microsoft.XMLHTTP")
   web.Open "GET", strURL, False
   web.Send
   If Err.Number <> 0 Then
      SaveWebBinary = False
      Set web = Nothing
      Exit Function
   End If
   If web.Status <> "200" Then
      SaveWebBinary = False
      Set web = Nothing
      Exit Function
   End If
   varByteArray = web.ResponseBody
   Set web = Nothing
   On Error Resume Next
   Set ado = Nothing
   Set ado = CreateObject("ADODB.Stream")
   If ado Is Nothing Then
      Set fs = CreateObject("Scripting.FileSystemObject")
      Set ts = fs.OpenTextFile(baseName(strUrl), ForWriting, True)
      strData = ""
      strBuffer = ""
      For lngCounter = 0 to UBound(varByteArray)
         ts.Write Chr(255 And Ascb(Midb(varByteArray,lngCounter + 1, 1)))
      Next
      ts.Close
   Else
      ado.Type = adTypeBinary
      ado.Open
      ado.Write varByteArray
      ado.SaveToFile CreateObject("WScript.Shell").ExpandEnvironmentStrings("%TEMP%") & "\" & strSetup, adSaveCreateOverWrite
      ado.Close
   End If
   SaveWebBinary = True
End Function

Function ShowMessage(strMessage)
   If LCase(Verbose) <> "no" Then
      WScript.Echo strMessage
   End If
End Function

Function MsiServerAvailable()
   Dim loopCount, objWMIService, oMsiServer, oServicePath, errExecMethod
   MsiServerAvailable = false
   Const maxLoops = 120
   loopCount = 0
   Set objWMIService = GetObject("winmgmts:\\.\root\CIMV2")
   Do While loopCount < maxLoops
      If loopCount > 0 Then
         WScript.Sleep 1000
      End If
      Set oMsiServer = GetObject("winmgmts:Win32_Service='MsiServer'")
      If oMsiServer.State = "Stopped" Then
         MsiServerAvailable = true
         Exit Function
      End If
      Set oServicePath = oMsiServer.Path_
      Set errExecMethod = objWMIService.ExecMethod(oServicePath, "StopService")
      If errExecMethod.ReturnValue = 0 Then
         MsiServerAvailable = true
         Exit Function
      End If
      loopCount = loopCount + 1
   Loop
End Function

Function MsiExec(strOptions)
   Dim loopCount
   Const maxLoops = 3
   loopCount = 0
   Do While loopCount < maxLoops
      If loopCount > 0 Then
         ShowMessage("Next attempt in 30 seconds...")
         WScript.Sleep 30000
      End If
      If MsiServerAvailable() Then
         ShowMessage("Running: MsiExec.exe " & strOptions)
         MsiExec = WshShell.Run("MsiExec.exe " & strOptions, 0, True)
         If MsiExec <> 1618 Then
            Exit Do
         End If
      Else
         MsiExec = 1618
      End If
      loopCount = loopCount + 1
   Loop
   If MsiExec = 0 Then
      ShowMessage("Deployment done!")
   ElseIf MsiExec = 1618 Then
      ShowMessage("Deployment failed: MSI Installer is busy!")
   Else
      ShowMessage("Deployment failed! (Err=" & MsiExec & ")")
   End If
End Function

'
'
' MAIN
'
'

Dim nMinutesToAdvance, strCmd, strSystemArchitecture, strTempDir, WshShell, strInstallOrRepair, bInstall
Set WshShell = WScript.CreateObject("WScript.shell")

nMinutesToAdvance = 5

If UninstallOcsAgent = "Yes" Then
   removeOCSAgents()
End If

If RunUninstallFusionInventoryAgent = "Yes" Then
    uninstallFusionInventoryAgent()
End If

strSystemArchitecture = GetSystemArchitecture()
If (strSystemArchitecture <> "x86") And (strSystemArchitecture <> "x64") Then
   ShowMessage("The system architecture is unknown or not supported.")
   ShowMessage("Deployment aborted!")
   WScript.Quit 1
Else
   ShowMessage("System architecture detected: " & strSystemArchitecture)
End If

Select Case LCase(SetupArchitecture)
   Case "x86"
      SetupArchitecture = "x86"
      Setup = Replace(Setup, "x86", SetupArchitecture, 1, 1, vbTextCompare)
      ShowMessage("Setup architecture: " & SetupArchitecture)
   Case "x64"
      SetupArchitecture = "x64"
      Setup = Replace(Setup, "x64", SetupArchitecture, 1, 1, vbTextCompare)
      ShowMessage("Setup architecture: " & SetupArchitecture)
   Case "auto"
      SetupArchitecture = strSystemArchitecture
      Setup = Replace(Setup, "Auto", SetupArchitecture, 1, 1, vbTextCompare)
      ShowMessage("Setup architecture detected: " & SetupArchitecture)
   Case Else
      ShowMessage("The setup architecture '" & SetupArchitecture & "' is not supported.")
      WScript.Quit 2
End Select

If (strSystemArchitecture = "x86") And (SetupArchitecture = "x64") Then
   ShowMessage("It isn't possible to execute a 64-bit setup on a 32-bit operative system.")
   ShowMessage("Deployment aborted!")
   WScript.Quit 3
End If

If (SetupArchitecture = "x86") And doesNotSupportX86(SetupVersion) Then
   ShowMessage("GLPI-Agent v" & SetupVersion & " doesn't support installation on a 32-bit operative system.")
   ShowMessage("Deployment aborted!")
   WScript.Quit 4
End If

bInstall = False
strInstallOrRepair = "/i"

If IsInstallationNeeded(SetupVersion, SetupArchitecture, strSystemArchitecture) Then
   bInstall = True
ElseIf IsSelectedRepair() Then
   strInstallOrRepair = "/fa"
   bInstall = True
ElseIf IsSelectedReconfigure() Then
   If not hasOption("REINSTALL") Then
      SetupOptions = SetupOptions & " REINSTALL=feat_AGENT"
   End If
   bInstall = True
End If

If bInstall Then
   If isNightly(SetupVersion) Then
      SetupLocation = SetupNightlyLocation
   End If
   If isHttp(SetupLocation) Then
      ShowMessage("Downloading: " & SetupLocation & "/" & Setup)
      If SaveWebBinary(SetupLocation, Setup) Then
         strCmd = WshShell.ExpandEnvironmentStrings("%ComSpec%")
         strTempDir = WshShell.ExpandEnvironmentStrings("%TEMP%")
         MsiExec(strInstallOrRepair & " """ & strTempDir & "\" & Setup & """ " & SetupOptions)
         ShowMessage("Scheduling: DEL /Q /F """ & strTempDir & "\" & Setup & """")
         WshShell.Run "AT.EXE " & AdvanceTime(nMinutesToAdvance) & " " & strCmd & " /C ""DEL /Q /F """"" & strTempDir & "\" & Setup & """""", 0, True
      Else
         ShowMessage("Error downloading '" & SetupLocation & "\" & Setup & "'!")
      End If
   Else
      If SetupLocation <> "" And SetupLocation <> "." Then
         Setup = SetupLocation & "\" & Setup
      End If
      MsiExec(strInstallOrRepair & " """ & Setup & """ " & SetupOptions)
   End If
Else
   ShowMessage("It isn't needed the installation of '" & Setup & "'.")
End If


Création des formulaires

Les formulaires permettent de faciliter la création des tickets pour les utilisateurs.

Pour gérer les formulaires, se rendre dans Administration > Formulaires.

Lors de l’ajout, donner un titre au formulaire, et il est nécessaire de l’activer. Cliquer sur le + pour ajouter une section.

Mettre une question pour l’utilisateur, plusieurs options sont possibles selon les besoins du formulaire. Il est possible de rendre la réponse obligatoire le cas échéant.

Dans la colonne de gauche, dans Destinations c’est ce qui permet de transformer en détail le formulaire rempli par l’utilisateur en ticket. Tout est personnalisable selon les besoins dans les propriétés, les niveaux de services, etc. Penser à cocher “Configuration automatique” pour récupérer automatiquement les éléments renseignés par l’utilisateur.

Sauvegarder.


Création des SLA

Rappel sur les SLA (Service Level Agreement)

La gestion des engagements de temps repose sur la distinction entre ce qui est promis à l’utilisateur (SLA) et ce qui est convenu en interne entre les équipes techniques (OLA).

  • TTO (Time To Own - Temps de Prise en Charge) : C’est le chrono qui tourne entre l’ouverture du ticket et le moment où un technicien ou un groupe est affecté au ticket (ou le moment où le statut passe de Nouveau à En cours).
  • Objectif : Éviter qu’un ticket ne reste dans le vide sans que personne ne s’en occupe.
  • TTR (Time To Resolve - Temps de Résolution) : C’est le chrono qui tourne entre l’ouverture du ticket et le moment où le ticket passe au statut Résolu.
  • Objectif : Garantir un temps maximal pour la correction de l’incident ou le traitement de la demande.

Gestion du calendrier

Pour gérer les SLAs un calendrier est nécessaire. Se rendre dans Configuration > Intitulés > Calendriers.

Dans les plages horaires, définir les périodes d’ouverture. Les niveaux de service s’appliquent en fonction de ces dernières. Penser à définir des périodes de fermeture pendant les absences et congés (pour avoir des statistiques précises).

Pour créer des SLA, se rendre dans Configuration > Niveaux de services.

Une fois la création effectuée, des réglages sont possibles selon les niveaux de service définis en amont. Il est également possible de modifier les SLAs déjà créés de la même manière.


Base de connaissance

GLPI intègre une base de connaissance pour partager de la documentation avec les utilisateurs. Se rendre dans Outils > Base de connaissances.

Lors de l’ajout d’un nouvel article dans la base de connaissance, choisir Placer cet élément dans la FAQ : Oui, Visible depuis : maintenant et Ajouter.

Dans l’article créé, choisir Cibles et ajouter Entité.

Sélectionner Traductions au besoin et ajouter une ou plusieurs langues.

Sources et références :